Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions .github/workflows/upstream-cache.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,12 @@ jobs:
native_asset="rustpython-${short}-${triple}.tar.gz"
wasm_asset="rustpython-wasm-${short}.tar.gz"
repo=edge-toolkit/core
assets=$(gh release view rp-v1 --repo "$repo" --json assets --jq '.assets[].name' 2>/dev/null || true)
# Fail closed: on a failed asset query, abort instead of rebuilding.
# A transient API error must not look like "asset missing" and clobber the pinned asset (new hash).
if ! assets=$(gh release view rp-v1 --repo "$repo" --json assets --jq '.assets[].name'); then
echo "::error::could not query rp-v1 assets; refusing to rebuild (transient API failure?)" >&2
exit 1
fi
native_missing=true; wasm_missing=true
if echo "$assets" | grep -Fxq "$native_asset"; then native_missing=false; fi
if echo "$assets" | grep -Fxq "$wasm_asset"; then wasm_missing=false; fi
Expand Down Expand Up @@ -264,7 +269,12 @@ jobs:
asset="${AUG_VERSION}-${MATRIX_TRIPLE}.${MATRIX_EXT}"
repo=edge-toolkit/core
jq='.assets[].name'
assets=$(gh release view "$AUG_RELEASE_TAG" --repo "$repo" --json assets --jq "$jq" 2>/dev/null || true)
# Fail closed: on a failed asset query, abort instead of rebuilding.
# A transient API error must not look like "asset missing" and clobber the pinned asset (new hash).
if ! assets=$(gh release view "$AUG_RELEASE_TAG" --repo "$repo" --json assets --jq "$jq"); then
echo "::error::could not query $AUG_RELEASE_TAG assets; refusing to rebuild (transient API failure?)" >&2
exit 1
fi
if echo "$assets" | grep -Fxq "$asset"; then
echo "::notice::$asset already in $AUG_RELEASE_TAG; skipping"
echo "work=" >> "$GITHUB_OUTPUT"
Expand Down Expand Up @@ -547,7 +557,12 @@ jobs:
asset="${DTG_VERSION}-${triple}.tar.gz"
repo=edge-toolkit/core
jq='.assets[].name'
assets=$(gh release view "$DTG_RELEASE_TAG" --repo "$repo" --json assets --jq "$jq" 2>/dev/null || true)
# Fail closed: on a failed asset query, abort instead of rebuilding.
# A transient API error must not look like "asset missing" and clobber the pinned asset (new hash).
if ! assets=$(gh release view "$DTG_RELEASE_TAG" --repo "$repo" --json assets --jq "$jq"); then
echo "::error::could not query $DTG_RELEASE_TAG assets; refusing to rebuild (transient API failure?)" >&2
exit 1
fi
if echo "$assets" | grep -Fxq "$asset"; then
echo "::notice::$asset already in $DTG_RELEASE_TAG; skipping"
echo "work=" >> "$GITHUB_OUTPUT"
Expand Down Expand Up @@ -638,7 +653,12 @@ jobs:
asset="${GNUPG_VERSION}_${GNUPG_BUILD_STAMP}-x86_64-pc-windows.tar.gz"
repo=edge-toolkit/core
jq='.assets[].name'
assets=$(gh release view "$GNUPG_RELEASE_TAG" --repo "$repo" --json assets --jq "$jq" 2>/dev/null || true)
# Fail closed: on a failed asset query, abort instead of rebuilding.
# A transient API error must not look like "asset missing" and clobber the pinned asset (new hash).
if ! assets=$(gh release view "$GNUPG_RELEASE_TAG" --repo "$repo" --json assets --jq "$jq"); then
echo "::error::could not query $GNUPG_RELEASE_TAG assets; refusing to rebuild (transient API failure?)" >&2
exit 1
fi
if echo "$assets" | grep -Fxq "$asset"; then
echo "::notice::$asset already in $GNUPG_RELEASE_TAG; skipping"
echo "work=" >> "$GITHUB_OUTPUT"
Expand Down
6 changes: 6 additions & 0 deletions .mise/config.rust.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ description = "Build the comm1 workflow WASM module"
dir = "services/ws-modules/comm1"
run = "{{ vars.web_cov_wrapper }}wasm-pack build . --target web {{ vars.no_opt }}{{ vars.web_cov_feat }}"

[tasks.build-ws-except1-module]
depends = ["build-wasm-cov-wrapper"]
description = "Build the except1 exception-handling demo WASM module"
dir = "services/ws-modules/except1"
run = "{{ vars.web_cov_wrapper }}wasm-pack build . --target web {{ vars.no_opt }}{{ vars.web_cov_feat }}"

[tasks.build-ws-sensor1-module]
depends = ["build-wasm-cov-wrapper"]
description = "Build the sensor1 workflow WASM module"
Expand Down
2 changes: 1 addition & 1 deletion .mise/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ version = "1.14.1"
checksum = "sha256:3303e8022294b04fe4ed567b0d88c10c1c7d5b51e443485251a6d4a606b1433a"
url = "https://github.com/edge-toolkit/core/releases/download/augeas-v1/1.14.1-aarch64-unknown-linux-gnu.tar.xz"
[tools."http:augeas".platforms.linux-x64]
checksum = "sha256:fc6345fb8ffb84e1f57f9144aacc059aa13687f6912ffe26f90713c771892ec6"
checksum = "sha256:76eb80c33355abe9f6ea01ac90a47a70d5917d940a0a843aed9d0b61feed7714"
url = "https://github.com/edge-toolkit/core/releases/download/augeas-v1/1.14.1-x86_64-unknown-linux-gnu.tar.xz"
[tools."http:augeas".platforms.macos-arm64]
checksum = "sha256:10fc4aff94a5c6016c51b4dbbc224277a340a083c315ca0a05e9f5ef9a869403"
Expand Down
77 changes: 50 additions & 27 deletions .mise/config.zig.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
# artifact; the Zig REST-client generation step in et-int-gen detects the missing binary at runtime and is a
# no-op when it's not on PATH.
"github:christianhelle/openapi2zig" = { version = "latest", os = ["linux/x64", "macos", "windows"] }
# C tooling for the zig-data1 module's hand-written C.
# The C sources live under services/ws-modules/zig-data1/src/*.c. Two conda packages because mise hands the
# C/C++ tooling for the zig-data1 module's hand-written C and C++.
# The sources live under services/ws-modules/zig-data1/src/*.{c,cpp}. Two conda packages because mise hands the
# `clang-format` name to conda:clang-format, so conda:clang-tools omits it and only supplies clang-tidy. Both
# are conda-forge's native LLVM binaries. cpplint (Google C++ style) and flawfinder (C/C++ security scanner)
# have no prebuilt binary -- pipx is their only distribution.
Expand Down Expand Up @@ -52,80 +52,103 @@ run = "zig fmt --check services/ws-modules/ generated/zig-rest/"
run = "zig fmt services/ws-modules/ generated/zig-rest/"

[tasks.clang-format]
description = "Format C sources (clang-format)"
run = "git ls-files '*.c' '*.h' | xargs clang-format -i --style=file:config/clang-format.yaml"
description = "Format C/C++ sources (clang-format)"
run = "git ls-files '*.c' '*.cpp' '*.h' | xargs clang-format -i --style=file:config/clang-format.yaml"

[tasks.clang-format-check]
description = "Check C source formatting (clang-format)"
run = "git ls-files '*.c' '*.h' | xargs clang-format --dry-run --Werror --style=file:config/clang-format.yaml"
description = "Check C/C++ source formatting (clang-format)"
run = "git ls-files '*.c' '*.cpp' '*.h' | xargs clang-format --dry-run --Werror --style=file:config/clang-format.yaml"

[tasks.clang-tidy-check]
description = "Lint C sources (clang-tidy)"
# Flags after `--` are the compile args.
# clang_resource_arg points clang at its builtin headers (set per host -- see config.linux.toml). {{ }} renders
# to empty where unset, leaving a bare `--`. The host clang-tidy can't parse the Windows-only mingw-shim
# (windows.h, MSVC CRT), so it gets a second pass with llvm-mingw's clang-tidy cross-targeting windows;
# `mise where` locates that install on any host (config.windows.toml on Windows, config.zig.toml on Linux/macOS).
description = "Lint C/C++ sources (clang-tidy)"
# Three passes, split by the compile target each bucket of C/C++ needs before clang-tidy can parse it.
# Flags after `--` are the compile args; clang_resource_arg points clang at its builtin headers (set per host
# -- see config.linux.toml), and {{ }} renders empty where unset, leaving a bare `--`.
# 1. host pass -- portable C/C++ built for the native target. This currently matches NOTHING: every tracked
# C/C++ file lives under services/ws-web-runner/mingw-shim or services/ws-modules/zig-* (both excluded
# just below), so the pass is a reserved slot for future portable C/C++ that is neither the Windows shim
# nor a wasm module. (On main it matched zig-data1/src/util.c; PR #93 moved the zig sources to pass 3.)
# 2. mingw-shim -- Windows-only (windows.h, MSVC CRT), so it goes through llvm-mingw's clang-tidy
# cross-targeting x86_64-w64-mingw32 (`mise where` locates that install on any host).
# 3. zig modules -- compiled to wasm, so the host clang-tidy targets wasm32 with the same exception-handling
# flags their build.zig files use, so wasm-only builtins (__builtin_wasm_throw) parse.
# `xargs -r` (--no-run-if-empty) guards every pass -- required because pass 1 matches nothing (above) and
# uutils findutils 0.8.0 xargs panics on empty input in -I mode:
# thread 'main' panicked at src/xargs/mod.rs:411:46: index out of bounds: the len is 0 but the index is 0
# (observed on PR #93's docker-linux build + check lanes). -r makes empty input a clean no-op.
run = """
git ls-files '*.c' '*.h' ':!services/ws-web-runner/mingw-shim' |
xargs -I{} clang-tidy --config-file=config/clang-tidy.yaml {} -- {{ vars.clang_resource_arg }}
git ls-files '*.c' '*.cpp' '*.h' ':!services/ws-web-runner/mingw-shim' ':!services/ws-modules/zig-*' |
xargs -r -I{} clang-tidy --config-file=config/clang-tidy.yaml {} -- {{ vars.clang_resource_arg }}
llvm_ct="$(mise where 'github:mstorsjo/llvm-mingw')/bin/clang-tidy"
git ls-files 'services/ws-web-runner/mingw-shim/*.c' |
xargs -I{} "$llvm_ct" --config-file=config/clang-tidy.yaml {} -- --target=x86_64-w64-mingw32 -std=c11
xargs -r -I{} "$llvm_ct" --config-file=config/clang-tidy.yaml {} -- --target=x86_64-w64-mingw32 -std=c11
wasm_flags=({{ vars.clang_resource_arg }} --target=wasm32-unknown-unknown -fwasm-exceptions -mexception-handling)
git ls-files 'services/ws-modules/zig-*/src/*.c' 'services/ws-modules/zig-*/src/*.cpp' |
xargs -r -I{} clang-tidy --config-file=config/clang-tidy.yaml {} -- "${wasm_flags[@]}" -fno-rtti
"""
Comment on lines 79 to 88

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== .mise/config.zig.toml (relevant lines) ==\n'
cat -n .mise/config.zig.toml | goawk 'NR>=70 && NR<=110 { print }'

printf '\n== config/clang-tidy.yaml ==\n'
cat -n config/clang-tidy.yaml | goawk 'NR<=120 { print }'

Repository: edge-toolkit/core

Length of output: 244


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

for path, start, end in [
    (Path('.mise/config.zig.toml'), 70, 110),
    (Path('config/clang-tidy.yaml'), 1, 160),
]:
    print(f"\n== {path} ({start}-{end}) ==")
    with path.open() as f:
        for i, line in enumerate(f, 1):
            if start <= i <= end:
                print(f"{i:4d}: {line}", end="")
            elif i > end:
                break

print("\n== matching zig module sources ==")
for p in sorted(Path('services/ws-modules').glob('zig-*/src/*')):
    if p.suffix in {'.c', '.cpp'}:
        print(p)
PY

Repository: edge-toolkit/core

Length of output: 4244


🌐 Web query:

Clang -fno-rtti C input unused argument warning warnings as errors driver

💡 Result:

In Clang, the "argument unused during compilation" message is a driver-level diagnostic controlled by the -Wunused-command-line-argument flag [1]. When you use -Werror, this warning is promoted to an error [2][1]. To manage or suppress this error, you can use the following methods: 1. Use -Qunused-arguments: This flag instructs the Clang driver to suppress warnings about unused command-line arguments entirely [3][4]. This is often the simplest approach if you want to silence these messages globally [2]. 2. Use -Wno-unused-command-line-argument: This explicitly disables the unused command-line argument diagnostic [2]. 3. Downgrade to a warning: If you are using -Werror globally but want to treat this specific diagnostic as a warning, you can pass -Wno-error=unused-command-line-argument [2]. This ensures the driver still reports the issue but does not halt the compilation [2]. 4. Selective suppression: For more granular control, the driver provides --start-no-unused-arguments and --end-no-unused-arguments, which can be wrapped around specific flags that are known to be unused in certain contexts (e.g., flags that only apply to linking but appear during compilation) [3][2]. Note that this diagnostic is intentionally designed to catch misspellings or incompatible flags, as Clang does not support all the command-line options found in other compilers like GCC [5]. Some flags may be annotated as TargetSpecific in newer Clang versions, which can elevate these warnings to errors automatically for certain targets [1].

Citations:


Move -fno-rtti off the C inputs The wasm clang-tidy pass matches both *.c and *.cpp, but -fno-rtti is C++-only. With WarningsAsErrors: "*", the C invocation can fail on services/ws-modules/zig-data1/src/util.c. Split the glob or pass that flag only to *.cpp.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.mise/config.zig.toml around lines 79 - 88, Update the wasm clang-tidy
invocation in the run script so `-fno-rtti` is applied only to C++ sources, not
the `*.c` inputs. Split the `git ls-files`/`xargs` processing for
`services/ws-modules/zig-*/src/*.c` and `*.cpp`, preserving the shared wasm
flags while adding `-fno-rtti` only to the C++ invocation.

shell = "bash -euo pipefail -c"

[tasks.clang-tidy-fix]
description = "Apply clang-tidy's machine-applicable fix-its to C sources in place"
# Mirrors clang-tidy-check's two passes: host clang-tidy for portable C, llvm-mingw's for the windows mingw-shim.
description = "Apply clang-tidy's machine-applicable fix-its to C/C++ sources in place"
# Mirrors clang-tidy-check's three passes.
# Host clang-tidy for portable C/C++, llvm-mingw's for the windows mingw-shim, and a wasm32 cross-target pass
# for the zig modules' C/C++.
run = """
git ls-files '*.c' '*.h' ':!services/ws-web-runner/mingw-shim' |
xargs -I{} clang-tidy --fix --config-file=config/clang-tidy.yaml {} -- {{ vars.clang_resource_arg }}
git ls-files '*.c' '*.cpp' '*.h' ':!services/ws-web-runner/mingw-shim' ':!services/ws-modules/zig-*' |
xargs -r -I{} clang-tidy --fix --config-file=config/clang-tidy.yaml {} -- {{ vars.clang_resource_arg }}
llvm_ct="$(mise where 'github:mstorsjo/llvm-mingw')/bin/clang-tidy"
git ls-files 'services/ws-web-runner/mingw-shim/*.c' |
xargs -I{} "$llvm_ct" --fix --config-file=config/clang-tidy.yaml {} -- --target=x86_64-w64-mingw32 -std=c11
xargs -r -I{} "$llvm_ct" --fix --config-file=config/clang-tidy.yaml {} -- --target=x86_64-w64-mingw32 -std=c11
wasm_flags=({{ vars.clang_resource_arg }} --target=wasm32-unknown-unknown -fwasm-exceptions -mexception-handling)
git ls-files 'services/ws-modules/zig-*/src/*.c' 'services/ws-modules/zig-*/src/*.cpp' |
xargs -r -I{} clang-tidy --fix --config-file=config/clang-tidy.yaml {} -- "${wasm_flags[@]}" -fno-rtti
"""
shell = "bash -euo pipefail -c"

[tasks.cpplint-check]
description = "Lint C sources for Google C++ style (cpplint)"
description = "Lint C/C++ sources for Google C++ style (cpplint)"
# cpplint and clang-tidy share the `// NOLINT` syntax, so cpplint sees the shim's clang-tidy-named NOLINTs.
# -readability/nolint stops it erroring on those (bugprone-*, clang-diagnostic-*) as unknown cpplint categories.
run = """
git ls-files '*.c' '*.h' |
git ls-files '*.c' '*.cpp' '*.h' |
xargs cpplint --quiet --linelength=120 --filter=-legal/copyright,-build/include_subdir,-readability/nolint
"""
shell = "bash -euo pipefail -c"

[tasks.flawfinder-check]
description = "Scan C sources for risky C APIs (flawfinder security lint)"
description = "Scan C/C++ sources for risky C APIs (flawfinder security lint)"
# flawfinder is a lexical scanner (no compile), so unlike clang-tidy it also covers the mingw-shim sources.
# Gate on risk level >= 2; the blanket level-1 notes (e.g. every strlen) are too noisy to fail CI on. A
# reviewed-safe hit at or above the gate is silenced with an inline `flawfinder: ignore` comment stating why.
run = """
git ls-files '*.c' '*.h' |
git ls-files '*.c' '*.cpp' '*.h' |
xargs flawfinder --error-level=2 --minlevel=2 --quiet --dataonly
"""
shell = "bash -euo pipefail -c"

# Namespaced aggregators picked up by the default config's globbed `check`/`fmt`.
[tasks."check:zig"]
depends = ["clang-format-check", "clang-tidy-check", "cpplint-check", "flawfinder-check", "zig-check"]
description = "Run Zig + C checks (zig fmt-check, clang-format, clang-tidy, cpplint, flawfinder)"
description = "Run Zig + C/C++ checks (zig fmt-check, clang-format, clang-tidy, cpplint, flawfinder)"

[tasks."fmt:zig"]
depends = ["clang-format", "zig-fmt"]
description = "Format Zig + C sources"
description = "Format Zig + C/C++ sources"

[tasks."fix:zig"]
depends = ["clang-tidy-fix"]
description = "Apply C lint-fix passes"
description = "Apply C/C++ lint-fix passes"

[tasks.build-ws-zig-data1-module]
description = "Build the zig-data1 workflow WASM module"
dir = "services/ws-modules/zig-data1"
run = "zig build -Doptimize=ReleaseSmall"

[tasks.build-ws-zig-except1-module]
description = "Build the zig-except1 exception-handling demo WASM module"
dir = "services/ws-modules/zig-except1"
run = "zig build -Doptimize=ReleaseSmall"

[tasks."prefetch:zig"]
description = "Prefetch Zig build dependencies"
run = "zig build --fetch --build-file services/ws-modules/zig-data1/build.zig"
Expand Down
50 changes: 25 additions & 25 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,28 +220,28 @@ settings, different file globs). taplo specifically: the only right way to forma
The `mise run <task>` formatters and checks per file type. The aggregates (`fmt`/`check`/`fmt-all`/`check-all`)
run every loaded language's row; guest rows need their `MISE_ENV` loaded.

| File type | Formatter task(s) |
| --------- | ------------------------------- |
| `*.rs` | `cargo-fmt`, `cargo-clippy-fix` |
| `*.toml` | `taplo-fmt` |
| `*.py` | `ruff-fmt` |
| `*.dart` | `fmt:dart` |
| `*.zig` | `fmt:zig` |
| `*.c` | `clang-format` |
| `*.cs` | `fmt:dotnet` |

| File type | Check task(s) |
| --------- | ---------------------------------------------------------------------------------------------- |
| `*.rs` | `cargo-check`, `cargo-clippy`, `cargo-fmt-check`, `cargo-doc-check`, `ast-grep-check` |
| `*.toml` | `taplo-check`, `conftest-check-toml`, `semgrep-check` |
| `*.yaml` | `ast-grep-check`, `conftest-check-yaml`, `ryl-check`, `action-validator-check`, `zizmor-check` |
| `*.json` | `semgrep-check` |
| `*.py` | `check:python` |
| `*.dart` | `check:dart` |
| `*.zig` | `check:zig` |
| `*.c` | `clang-format-check`, `clang-tidy-check`, `cpplint-check` |
| `*.cs` | `check:dotnet` |
| `*.java` | `check:java` |
| File type | Formatter task(s) |
| -------------- | ------------------------------- |
| `*.rs` | `cargo-fmt`, `cargo-clippy-fix` |
| `*.toml` | `taplo-fmt` |
| `*.py` | `ruff-fmt` |
| `*.dart` | `fmt:dart` |
| `*.zig` | `fmt:zig` |
| `*.c`, `*.cpp` | `clang-format` |
| `*.cs` | `fmt:dotnet` |

| File type | Check task(s) |
| -------------- | ---------------------------------------------------------------------------------------------- |
| `*.rs` | `cargo-check`, `cargo-clippy`, `cargo-fmt-check`, `cargo-doc-check`, `ast-grep-check` |
| `*.toml` | `taplo-check`, `conftest-check-toml`, `semgrep-check` |
| `*.yaml` | `ast-grep-check`, `conftest-check-yaml`, `ryl-check`, `action-validator-check`, `zizmor-check` |
| `*.json` | `semgrep-check` |
| `*.py` | `check:python` |
| `*.dart` | `check:dart` |
| `*.zig` | `check:zig` |
| `*.c`, `*.cpp` | `clang-format-check`, `clang-tidy-check`, `cpplint-check` |
| `*.cs` | `check:dotnet` |
| `*.java` | `check:java` |

`dprint-fmt` / `dprint-check` cover `*.md`, `*.yaml`, `*.json`/`*.jsonc`, `*.ts`/`*.js`, `*.css`, `*.html`,
`*.java`, and `Dockerfile*`; `hadolint-check` also lints Dockerfiles, and `link-check` scans `*.md` + `*.rs`. Every
Expand Down Expand Up @@ -304,15 +304,15 @@ The server only serves them from disk.

Languages:

- **Rust -> WASM** (wasm-pack): audio1, bluetooth, comm1, data1, face-detection, geolocation, graphics-info, har1, nfc,
sensor1, speech-recognition, video1
- **Rust -> WASM** (wasm-pack): audio1, bluetooth, comm1, data1, except1, face-detection, geolocation, graphics-info,
har1, nfc, sensor1, speech-recognition, video1
- **Dart -> JS**: dart-comm1
- **Python (Pyodide)**: pydata1, pyeye1, pyface1
- **C# (.NET WASM)**: dotnet-data1
- **Java (TeaVM -> JS)**: java-data1
- **R (webR -> WASM)**: rdata1, rcomm1 -- browser-only (webR spawns a classic Worker, unsupported by Deno's
ws-web-runner). Their JS shims are linted by the `js` env; `MISE_ENV=r` supplies webR + the vendoring build tasks.
- **Zig -> WASM**: zig-data1
- **Zig -> WASM**: zig-data1, zig-except1 (C++ wasm-exception-handling demo)
- **Python (componentize-py -> WASI Preview 2 component)**: wasi-graphics-info -- runs in
`et-ws-wasi-runner` rather than the browser. The WIT world the component implements is at
`services/ws-wasi-runner/wit/world.wit` and is mirrored under the module's own `wit/`.
Expand Down
15 changes: 15 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ members = [
"services/ws-modules/bluetooth",
"services/ws-modules/comm1",
"services/ws-modules/data1",
"services/ws-modules/except1",
"services/ws-modules/face-detection",
"services/ws-modules/geolocation",
"services/ws-modules/graphics-info",
Expand Down
Loading
Loading