Skip to content

Add local channel install script for custom builds#19

Open
rubenvereecken wants to merge 115 commits into
CloverLabsAI:mainfrom
rubenvereecken:ruben/local-channel-install
Open

Add local channel install script for custom builds#19
rubenvereecken wants to merge 115 commits into
CloverLabsAI:mainfrom
rubenvereecken:ruben/local-channel-install

Conversation

@rubenvereecken

@rubenvereecken rubenvereecken commented Mar 20, 2026

Copy link
Copy Markdown

Related Issue

N/A — feature request / discussion

Description

How do you lot manage local/custom builds?

I've been building Camoufox from source (patching things, testing fixes) and kept running into the same annoyance: after installing my custom build, a camoufox fetch would reset active_version and I'd be back on the upstream binary without realising. Cue 20 minutes of confused debugging before I notice the version string is wrong.

The multiversion system already supports multiple repos under browsers/ — official, coryking, etc. So I started putting my local builds under browsers/local/ and it works brilliantly:

~/.cache/camoufox/browsers/
├── official/
│   └── 135.0.1-beta.24/
├── local/                          ← custom builds go here
│   └── 146.0.1-my-custom-build.1/
│       ├── version.json
│       └── Camoufox.app/
└── ...

Each build gets a version.json so the multiversion system picks it up:

{
  "version": "146.0.1",
  "build": "my-custom-build.1",
  "prerelease": false,
  "local_build": true
}

Then active_version in config.json points to browsers/local/146.0.1-my-custom-build.1 and it survives camoufox fetch because fetch only touches the official channel.

This PR adds a small shell script (scripts/install-local-build.sh) that automates this:

  • Takes a build artifact zip (or defaults to latest in dist/)
  • Extracts to browsers/local/<version-build>/
  • Writes version.json
  • Sets active_version
  • Fixes permissions (the classic cp -R strips executable bits problem)

Usage

# Install latest build from dist/
./scripts/install-local-build.sh

# Install a specific artifact
./scripts/install-local-build.sh dist/camoufox-146.0.1-my-fix.1-mac.arm64.zip

# Verify
cat ~/.cache/camoufox/config.json
# → active_version: "browsers/local/146.0.1-my-fix.1"

Discussion points

  • Is there a better way to do this already? I couldn't find one — executable_path works but bypasses the Python package's version management entirely
  • Would it make sense to build local channel support into the CLI? Something like camoufox install --local /path/to/artifact.zip would be lovely. The multiversion system already handles the directory structure, it'd just need a new install path
  • The local_build: true flag in version.json — could be useful if the CLI wants to distinguish local builds from fetched ones (e.g. skip them during camoufox fetch --replace)

Happy to rework this if there's a preferred approach. Just wanted to share what's been working for me.

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Other

Testing

# Install a build
./scripts/install-local-build.sh dist/camoufox-146.0.1-test.1-mac.arm64.zip

# Verify it's active
python -c "from camoufox.pkgman import launch_path; print(launch_path())"
# → .../browsers/local/146.0.1-test.1/Camoufox.app/Contents/MacOS/camoufox

# Run camoufox fetch — should NOT change active_version
camoufox fetch
cat ~/.cache/camoufox/config.json
# → active_version still points to browsers/local/...

Fingerprint Report

N/A — no changes to browser patches or fingerprint generation. This is purely a build management script.

Checklist

  • I have linked a related issue above
  • My changes are focused on a single logical change
  • I have added testing instructions which include the desired result
  • I have included a fingerprint report from https://camoufox-tester.vercel.app/
  • Service tests pass (bash service_tests/run_tests.sh)

Summary by CodeRabbit

  • New Features
    • Added a new CLI installation tool for deploying custom Camoufox builds to a local environment with support for specifying build artifacts and version information through command-line parameters.

PopcornDev1 and others added 30 commits February 3, 2026 17:45
- timezone-spoofing.patch: per-context timezone via per-realm DateTimeInfo
- geolocation-spoofing.patch: CAMOU_CONFIG backwards compatibility for geolocation
- locale-spoofing.patch: add camoucfg LOCAL_INCLUDES
- anti-font-fingerprinting.patch: add RoverfoxStorageManager exports to moz.build
- audio-fingerprint-manager.patch: per-context audio fingerprinting (all 6 API methods)
- screen-spoofing.patch: per-context screen dimensions with global MaskConfig fallback
- Disable webrtc-ip-spoofing.patch (will re-enable after fixing)
- Remove screen-hijacker.patch (superseded by screen-spoofing.patch)
…urrency, and timezone (daijro#443)

Fixes issue where global CAMOU_CONFIG settings for navigator.platform,
navigator.hardwareConcurrency, and timezone were not applied in the main
window Navigator (only WorkerNavigator was patched via fingerprint-injection.patch).
- navigator-spoofing.patch: Global config fixes for platform/hardwareConcurrency/timezone
- timezone-spoofing.patch: Persistence across page navigation via SetNewDocument hook
- audio-fingerprint-manager.patch: Full 6-method coverage with self-destruct pattern
- screen-spoofing.patch: Per-context dimensions with self-destruct pattern
- webrtc-ip-spoofing.patch: Re-enabled with getStats() sanitization + comprehensive IPv6 regex
…ion-spoofing

CloverLabsAI#1 feat: timezone, geolocation, and locale spoofing patches
…fing

CloverLabsAI#2 feat: per-context audio fingerprinting and screen spoofing patches
…-#443

CloverLabsAI#3 Fixed Issue daijro#443 + Detection Prevention + WebRTC Re-enablement
…oncurrency) with global fallback + docs update.
@coderabbitai

coderabbitai Bot commented Mar 20, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

A new Bash script is added to install custom Camoufox builds into a local browser cache. The script resolves a target artifact ZIP, derives a version string, extracts the archive into a structured directory, applies permissions, generates version metadata, and updates the active browser configuration.

Changes

Cohort / File(s) Summary
Installation Script
scripts/install-local-build.sh
New executable Bash script for installing custom Camoufox builds. Handles artifact resolution (from CLI argument or latest macOS arm64 build in dist/), version/build derivation, ZIP extraction with macOS-specific handling for .app bundles, directory setup under ${CACHE_DIR}/browsers/local/, permission configuration, version.json metadata generation, and config.json active version updates. Includes build verification via Info.plist inspection.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 A script hops into the warren,
Installing builds with flair and care,
Unpacking zips through bushes and trees,
Permissions set, metadata shared,
The local cache now stands prepared! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a shell script for installing custom Camoufox builds to a local channel, which is the primary purpose of this PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can use Trivy to scan for security misconfigurations and secrets in Infrastructure as Code files.

Add a .trivyignore file to your project to customize which findings Trivy reports.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
scripts/install-local-build.sh (3)

99-107: JSON generation via heredoc is fragile.

If BUILD contains characters like " or \ (from unusual filenames), the resulting JSON would be malformed. Consider using jq or python3 for safe JSON generation.

♻️ Safer JSON generation
 # Write version.json
-cat > "$INSTALL_DIR/version.json" <<VEOF
-{
-  "version": "$VERSION",
-  "build": "$BUILD",
-  "prerelease": false,
-  "local_build": true
-}
-VEOF
+python3 -c "
+import json
+data = {
+    'version': '''$VERSION''',
+    'build': '''$BUILD''',
+    'prerelease': False,
+    'local_build': True
+}
+with open('$INSTALL_DIR/version.json', 'w') as f:
+    json.dump(data, f, indent=2)
+"

Or use jq -n if available.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/install-local-build.sh` around lines 99 - 107, The heredoc writing
version.json can produce invalid JSON if BUILD or VERSION contain quotes or
backslashes; update the script (scripts/install-local-build.sh) to generate JSON
using a JSON-safe tool instead of interpolation: replace the cat heredoc that
writes "$INSTALL_DIR/version.json" with a jq -n invocation that sets
"version","build","prerelease" and "local_build" via --arg, or run a short
python3 -c snippet that constructs a dict with VERSION and BUILD and json.dump()
to the target file; ensure you still write to the same path
($INSTALL_DIR/version.json) and preserve the boolean fields, and make the change
around the existing variables VERSION, BUILD, and the version.json creation
block.

31-31: Default artifact selection is hardcoded to macOS ARM64.

The default glob pattern only matches *-mac.arm64.zip, which limits usability for Linux users and Intel Mac users. Consider detecting the platform and adjusting the pattern:

♻️ Suggested improvement for cross-platform default
 ARTIFACT="${1:-}"
 if [[ -z "$ARTIFACT" ]]; then
-    ARTIFACT="$(ls -t "$REPO_ROOT"/dist/camoufox-*-mac.arm64.zip 2>/dev/null | head -1)"
+    # Detect platform for default artifact selection
+    if [[ "$(uname)" == "Darwin" ]]; then
+        if [[ "$(uname -m)" == "arm64" ]]; then
+            PATTERN="*-mac.arm64.zip"
+        else
+            PATTERN="*-mac.x86_64.zip"
+        fi
+    else
+        PATTERN="*-linux.*.zip"
+    fi
+    ARTIFACT="$(ls -t "$REPO_ROOT"/dist/camoufox-${PATTERN} 2>/dev/null | head -1)"
     if [[ -z "$ARTIFACT" ]]; then
         echo "No artifact found in dist/. Pass the zip path as an argument."
         exit 1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/install-local-build.sh` at line 31, The ARTIFACT selection is
hardcoded to macOS ARM64 by the ARTIFACT assignment; update the script
(install-local-build.sh) to detect the current platform (e.g., via uname or
OSTYPE) and set a platform-specific glob before the ls call (handle linux ->
*-linux*.zip, mac arm64 -> *-mac.arm64.zip, mac intel -> *-mac.amd64.zip, etc.),
then use that glob in the ARTIFACT assignment so the default artifact selection
works across platforms and falls back gracefully if no match is found.

96-97: Overly broad permission setting.

chmod -R 755 makes all files executable, including resources that shouldn't be (.json, images, etc.). Consider a more targeted approach that preserves proper file permissions.

♻️ More precise permission handling
 # Fix permissions (cp/unzip can strip executable bits)
-chmod -R 755 "$INSTALL_DIR"
+# Set directories to 755, files to 644
+find "$INSTALL_DIR" -type d -exec chmod 755 {} \;
+find "$INSTALL_DIR" -type f -exec chmod 644 {} \;
+# Restore executable bit on binaries
+if [[ -d "$INSTALL_DIR/Camoufox.app" ]]; then
+    # macOS: framework binaries
+    find "$INSTALL_DIR/Camoufox.app/Contents/MacOS" -type f -exec chmod 755 {} \;
+else
+    # Linux: main executable and libs
+    find "$INSTALL_DIR" -type f \( -name "camoufox*" -o -name "*.so" \) -exec chmod 755 {} \;
+fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/install-local-build.sh` around lines 96 - 97, The current blanket
chmod -R 755 "$INSTALL_DIR" makes every file executable; replace it with
targeted permission fixes: set directories under INSTALL_DIR to 755, set regular
files to 644, then re-enable execute on files that should be executable (e.g.,
those already marked executable or scripts detected via shebang) by setting them
to 755; locate the existing chmod -R 755 "$INSTALL_DIR" line in the script and
replace it with these targeted operations referencing INSTALL_DIR so
non-executable resources (JSON, images, etc.) are not made executable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/install-local-build.sh`:
- Around line 91-94: The mv command using "$TMP_DIR"/* will skip hidden
dotfiles; update the else branch that moves artifacts so hidden files are
included by either enabling dotglob temporarily (shopt -s dotglob; mv
"$TMP_DIR"/* "$INSTALL_DIR/"; shopt -u dotglob to restore) or use the safe
directory-move pattern mv "$TMP_DIR"/. "$INSTALL_DIR/"; ensure you reference the
same TMP_DIR and INSTALL_DIR variables from this script when applying the
change.
- Around line 64-65: The script currently extracts VERSION from VERSION_BUILD
into the variable VERSION and computes BUILD from it, but it doesn't validate
that VERSION was successfully extracted; add a validation step after
VERSION="$(...)" to check if VERSION is non-empty and, if empty, print a clear
error (including the offending VERSION_BUILD value) and exit non‑zero so you
don't produce an invalid version.json. Only compute
BUILD="${VERSION_BUILD#${VERSION}-}" and continue when VERSION is valid;
otherwise abort early with the error message.
- Around line 116-123: The current inline Python here interpolates shell
variables into the code string (CONFIG_FILE and RELATIVE_PATH), risking syntax
breaks or injection; change the invocation so Python reads values from the
environment or from command-line arguments instead of embedding them.
Specifically, export or pass CONFIG_FILE and RELATIVE_PATH (or VERSION_BUILD) as
environment variables or use python -c with sys.argv, then in the Python code
(the block that opens and writes cfg and sets cfg['active_version']) reference
os.environ['CONFIG_FILE'] and os.environ['RELATIVE_PATH'] (or sys.argv[1]/[2])
rather than relying on shell interpolation; update the call site that currently
constructs the multiline string to pass these values safely.

---

Nitpick comments:
In `@scripts/install-local-build.sh`:
- Around line 99-107: The heredoc writing version.json can produce invalid JSON
if BUILD or VERSION contain quotes or backslashes; update the script
(scripts/install-local-build.sh) to generate JSON using a JSON-safe tool instead
of interpolation: replace the cat heredoc that writes
"$INSTALL_DIR/version.json" with a jq -n invocation that sets
"version","build","prerelease" and "local_build" via --arg, or run a short
python3 -c snippet that constructs a dict with VERSION and BUILD and json.dump()
to the target file; ensure you still write to the same path
($INSTALL_DIR/version.json) and preserve the boolean fields, and make the change
around the existing variables VERSION, BUILD, and the version.json creation
block.
- Line 31: The ARTIFACT selection is hardcoded to macOS ARM64 by the ARTIFACT
assignment; update the script (install-local-build.sh) to detect the current
platform (e.g., via uname or OSTYPE) and set a platform-specific glob before the
ls call (handle linux -> *-linux*.zip, mac arm64 -> *-mac.arm64.zip, mac intel
-> *-mac.amd64.zip, etc.), then use that glob in the ARTIFACT assignment so the
default artifact selection works across platforms and falls back gracefully if
no match is found.
- Around line 96-97: The current blanket chmod -R 755 "$INSTALL_DIR" makes every
file executable; replace it with targeted permission fixes: set directories
under INSTALL_DIR to 755, set regular files to 644, then re-enable execute on
files that should be executable (e.g., those already marked executable or
scripts detected via shebang) by setting them to 755; locate the existing chmod
-R 755 "$INSTALL_DIR" line in the script and replace it with these targeted
operations referencing INSTALL_DIR so non-executable resources (JSON, images,
etc.) are not made executable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0628eaea-c0d8-4af1-aecd-bc3570e3c4a7

📥 Commits

Reviewing files that changed from the base of the PR and between b67d323 and de7575d.

📒 Files selected for processing (1)
  • scripts/install-local-build.sh

Comment on lines +64 to +65
VERSION="$(echo "$VERSION_BUILD" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+')"
BUILD="${VERSION_BUILD#${VERSION}-}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing validation when version extraction fails.

If VERSION_BUILD doesn't match the expected semver pattern (e.g., a malformed filename), grep returns an empty string. The script then proceeds with an empty VERSION and incorrect BUILD, resulting in an invalid version.json that could break the multiversion system.

🛡️ Proposed fix to validate VERSION extraction
 VERSION="$(echo "$VERSION_BUILD" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+')"
+if [[ -z "$VERSION" ]]; then
+    echo "Error: Could not extract semver from version-build string: $VERSION_BUILD"
+    echo "Expected format: <major>.<minor>.<patch>-<build> (e.g., 146.0.1-my-fix.1)"
+    exit 1
+fi
 BUILD="${VERSION_BUILD#${VERSION}-}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
VERSION="$(echo "$VERSION_BUILD" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+')"
BUILD="${VERSION_BUILD#${VERSION}-}"
VERSION="$(echo "$VERSION_BUILD" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+')"
if [[ -z "$VERSION" ]]; then
echo "Error: Could not extract semver from version-build string: $VERSION_BUILD"
echo "Expected format: <major>.<minor>.<patch>-<build> (e.g., 146.0.1-my-fix.1)"
exit 1
fi
BUILD="${VERSION_BUILD#${VERSION}-}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/install-local-build.sh` around lines 64 - 65, The script currently
extracts VERSION from VERSION_BUILD into the variable VERSION and computes BUILD
from it, but it doesn't validate that VERSION was successfully extracted; add a
validation step after VERSION="$(...)" to check if VERSION is non-empty and, if
empty, print a clear error (including the offending VERSION_BUILD value) and
exit non‑zero so you don't produce an invalid version.json. Only compute
BUILD="${VERSION_BUILD#${VERSION}-}" and continue when VERSION is valid;
otherwise abort early with the error message.

Comment on lines +91 to +94
else
# Linux/Windows: move everything
mv "$TMP_DIR"/* "$INSTALL_DIR/"
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Hidden files (dotfiles) may not be moved.

The glob * doesn't match hidden files by default in bash. If the artifact contains dotfiles, they won't be copied to INSTALL_DIR. Consider using shopt -s dotglob temporarily or mv "$TMP_DIR"/. "$INSTALL_DIR/" pattern.

🔧 Suggested fix
 else
     # Linux/Windows: move everything
-    mv "$TMP_DIR"/* "$INSTALL_DIR/"
+    # Use dotglob to include hidden files
+    shopt -s dotglob
+    mv "$TMP_DIR"/* "$INSTALL_DIR/"
+    shopt -u dotglob
 fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
else
# Linux/Windows: move everything
mv "$TMP_DIR"/* "$INSTALL_DIR/"
fi
else
# Linux/Windows: move everything
# Use dotglob to include hidden files
shopt -s dotglob
mv "$TMP_DIR"/* "$INSTALL_DIR/"
shopt -u dotglob
fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/install-local-build.sh` around lines 91 - 94, The mv command using
"$TMP_DIR"/* will skip hidden dotfiles; update the else branch that moves
artifacts so hidden files are included by either enabling dotglob temporarily
(shopt -s dotglob; mv "$TMP_DIR"/* "$INSTALL_DIR/"; shopt -u dotglob to restore)
or use the safe directory-move pattern mv "$TMP_DIR"/. "$INSTALL_DIR/"; ensure
you reference the same TMP_DIR and INSTALL_DIR variables from this script when
applying the change.

Comment on lines +116 to +123
python3 -c "
import json, sys
with open('$CONFIG_FILE') as f:
cfg = json.load(f)
cfg['active_version'] = '$RELATIVE_PATH'
with open('$CONFIG_FILE', 'w') as f:
json.dump(cfg, f, indent=2)
"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential code injection via shell variable interpolation in Python.

The shell variables $CONFIG_FILE and $RELATIVE_PATH are interpolated directly into the Python code string. If VERSION_BUILD (and thus RELATIVE_PATH) contains single quotes or other special characters, it could break the Python syntax or enable code injection. While this is a local script, it's safer to pass values via environment variables.

🛡️ Safer approach using environment variables
 if [[ -f "$CONFIG_FILE" ]]; then
     # Use python for safe JSON manipulation
-    python3 -c "
-import json, sys
-with open('$CONFIG_FILE') as f:
-    cfg = json.load(f)
-cfg['active_version'] = '$RELATIVE_PATH'
-with open('$CONFIG_FILE', 'w') as f:
-    json.dump(cfg, f, indent=2)
-"
+    CONFIG_FILE="$CONFIG_FILE" RELATIVE_PATH="$RELATIVE_PATH" python3 -c "
+import json, os
+config_file = os.environ['CONFIG_FILE']
+relative_path = os.environ['RELATIVE_PATH']
+with open(config_file) as f:
+    cfg = json.load(f)
+cfg['active_version'] = relative_path
+with open(config_file, 'w') as f:
+    json.dump(cfg, f, indent=2)
+"
 else
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
python3 -c "
import json, sys
with open('$CONFIG_FILE') as f:
cfg = json.load(f)
cfg['active_version'] = '$RELATIVE_PATH'
with open('$CONFIG_FILE', 'w') as f:
json.dump(cfg, f, indent=2)
"
CONFIG_FILE="$CONFIG_FILE" RELATIVE_PATH="$RELATIVE_PATH" python3 -c "
import json, os
config_file = os.environ['CONFIG_FILE']
relative_path = os.environ['RELATIVE_PATH']
with open(config_file) as f:
cfg = json.load(f)
cfg['active_version'] = relative_path
with open(config_file, 'w') as f:
json.dump(cfg, f, indent=2)
"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/install-local-build.sh` around lines 116 - 123, The current inline
Python here interpolates shell variables into the code string (CONFIG_FILE and
RELATIVE_PATH), risking syntax breaks or injection; change the invocation so
Python reads values from the environment or from command-line arguments instead
of embedding them. Specifically, export or pass CONFIG_FILE and RELATIVE_PATH
(or VERSION_BUILD) as environment variables or use python -c with sys.argv, then
in the Python code (the block that opens and writes cfg and sets
cfg['active_version']) reference os.environ['CONFIG_FILE'] and
os.environ['RELATIVE_PATH'] (or sys.argv[1]/[2]) rather than relying on shell
interpolation; update the call site that currently constructs the multiline
string to pass these values safely.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants