diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 7b0420f..3d78ad2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,6 +1,6 @@ version: 2 updates: - - package-ecosystem: pip + - package-ecosystem: uv directory: "/" schedule: interval: cron @@ -25,4 +25,13 @@ updates: github-actions: patterns: - "*" + ignore: + # The action ref is the Rust version to install, not an action release. + # Dependabot otherwise proposes unreleased toolchains such as 1.100.0. + - dependency-name: dtolnay/rust-toolchain + # The v4 ref already follows current v4 security and patch releases. + - dependency-name: github/codeql-action + update-types: + - version-update:semver-minor + - version-update:semver-patch open-pull-requests-limit: 2 diff --git a/.github/release-intro.md b/.github/release-intro.md new file mode 100644 index 0000000..e509065 --- /dev/null +++ b/.github/release-intro.md @@ -0,0 +1,30 @@ +## Download VidXP + +{release_notice}VidXP turns video into searchable dialogue, scenes, people, and +inspectable evidence. Choose the desktop app for the guided local setup, or use +the Python package and containers for command-line and server deployments. + +| Platform | Download | +| --- | --- | +| Windows x86-64 | [Installer]({windows_url}) | +| macOS Apple Silicon | [DMG]({macos_url}) | +| Linux x86-64 | [AppImage]({linux_url}) | + +Verify downloaded files against [SHA256SUMS]({checksums_url}). + +### Command line + +```bash +python -m pip install "vidxp[local-worker,mcp]=={version}" +``` + +### Containers + +```bash +docker pull {container_image}:{version} +``` + +Server deployments use the matching `-control` and `-worker` image tags. + +[Installation guide]({installation_url}) · [Server deployment]({deployment_url}) · +[Report an issue]({issues_url}) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 483331f..4d3a7b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,6 +35,11 @@ on: required: false default: false type: boolean + package_artifact_name: + description: Preserve the already-smoke-tested distribution under this name. + required: false + default: "" + type: string workflow_dispatch: inputs: checkout_ref: @@ -61,9 +66,14 @@ on: required: false default: true type: boolean + package_artifact_name: + description: Preserve the already-smoke-tested distribution under this name. + required: false + default: "" + type: string concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || inputs.checkout_ref || github.ref }} cancel-in-progress: true permissions: @@ -72,14 +82,11 @@ permissions: jobs: scope: - if: >- - github.event_name != 'pull_request' || - github.base_ref != 'release' || - github.head_ref != 'main' runs-on: ubuntu-latest outputs: needs_python: ${{ steps.scope.outputs.needs_python }} run_container: ${{ steps.scope.outputs.run_container }} + run_desktop: ${{ steps.scope.outputs.run_desktop }} run_suite: ${{ steps.scope.outputs.run_suite }} steps: - uses: actions/checkout@v7 @@ -87,39 +94,26 @@ jobs: fetch-depth: 0 ref: ${{ inputs.checkout_ref || github.sha }} + - name: Validate GitHub Actions workflows + run: bash utils/check_workflows.sh + - name: Determine validation scope id: scope shell: bash env: BASE_SHA: ${{ github.event.pull_request.base.sha }} + BASE_REF: ${{ github.base_ref }} FORCE_VALIDATION: ${{ inputs.force_validation || false }} + HEAD_REF: ${{ github.head_ref }} RUN_CONTAINERS: ${{ inputs.run_containers || false }} run: | - if [[ "$FORCE_VALIDATION" == "true" ]]; then - { - echo "run_suite=true" - echo "run_container=$RUN_CONTAINERS" - echo "needs_python=true" - } >> "$GITHUB_OUTPUT" - exit 0 - fi - - changed_files="$(git diff --name-only "$BASE_SHA" HEAD)" - if grep -Eq '^(\.github/workflows/ci\.yml$|src/|tests/|utils/|LICENSE$|MANIFEST\.in$|pyproject\.toml$|uv\.lock$)' <<< "$changed_files"; then - run_suite=true - else - run_suite=false - fi - if grep -Eq '^(\.dockerignore$|\.github/workflows/ci\.yml$|Dockerfile$|compose\.yaml$|pyproject\.toml$|uv\.lock$|src/vidxp/(requirements/.*\.txt|capabilities/[^/]+/requirements\.txt)$)' <<< "$changed_files"; then - run_container=true - else - run_container=false - fi - - needs_python="$run_suite" - echo "run_suite=$run_suite" >> "$GITHUB_OUTPUT" - echo "run_container=$run_container" >> "$GITHUB_OUTPUT" - echo "needs_python=$needs_python" >> "$GITHUB_OUTPUT" + python utils/ci_scope.py \ + --base "$BASE_SHA" \ + --base-ref "$BASE_REF" \ + --force-validation "$FORCE_VALIDATION" \ + --github-output "$GITHUB_OUTPUT" \ + --head-ref "$HEAD_REF" \ + --run-containers "$RUN_CONTAINERS" validate: if: needs.scope.outputs.needs_python == 'true' @@ -139,15 +133,25 @@ jobs: python-version: ${{ matrix.python-version }} cache: pip + - uses: actions/setup-node@v7 + if: needs.scope.outputs.run_suite == 'true' && matrix.python-version == '3.14' + with: + node-version: "22" + cache: npm + cache-dependency-path: web/upload-page/package-lock.json + - name: Install repository tooling run: | python -m pip install --upgrade pip + python -m pip install "uv==0.12.0" python -m pip install -r utils/build-requirements.txt + - name: Verify Python lockfile + run: uv lock --check + - name: Install test surface if: needs.scope.outputs.run_suite == 'true' run: | - python -m pip install "uv==0.12.0" uv sync \ --frozen \ --extra all \ @@ -162,6 +166,21 @@ jobs: if: needs.scope.outputs.run_suite == 'true' && matrix.python-version == '3.14' run: ruff check src tests + - name: Install locked upload-page tooling + if: needs.scope.outputs.run_suite == 'true' && matrix.python-version == '3.14' + run: npm ci + working-directory: web/upload-page + + - name: Test upload page + if: needs.scope.outputs.run_suite == 'true' && matrix.python-version == '3.14' + run: npm test + working-directory: web/upload-page + + - name: Build upload page and verify committed bundle + if: needs.scope.outputs.run_suite == 'true' && matrix.python-version == '3.14' + run: npm run check:bundle + working-directory: web/upload-page + - name: Test if: needs.scope.outputs.run_suite == 'true' run: uv run --no-sync python -m unittest discover -s tests -q @@ -180,41 +199,24 @@ jobs: .wheel-smoke/bin/python -m pip install --upgrade pip .wheel-smoke/bin/python -m pip install dist/*.whl .wheel-smoke/bin/python -m pip check - .wheel-smoke/bin/python - <<'PY' - from importlib.util import find_spec - from subprocess import check_output - - import vidxp - from vidxp.capabilities.registry import create_capability_registry - - assert create_capability_registry().names() == ( - "dialogue", "scene", "actor" - ) - help_text = check_output( - [".wheel-smoke/bin/vidxp", "--help"], - text=True, - ) - assert "benchmark" in help_text - benchmark_help = check_output( - [".wheel-smoke/bin/vidxp", "benchmark", "--help"], - text=True, - ) - assert "official benchmark adapters" in benchmark_help - for module in ( - "chromadb", - "cv2", - "faster_whisper", - "sentence_transformers", - "streamlit", - "torch", - "transformers", - ): - assert find_spec(module) is None, module - PY + .wheel-smoke/bin/python utils/verify_runtime.py minimal \ + --vidxp-executable .wheel-smoke/bin/vidxp + + - name: Preserve the validated distribution + if: >- + needs.scope.outputs.run_suite == 'true' && + matrix.python-version == '3.14' && + inputs.package_artifact_name != '' + uses: actions/upload-artifact@v7 + with: + name: ${{ inputs.package_artifact_name }} + path: dist/ + if-no-files-found: error + retention-days: 30 - name: Validate Compose configuration if: needs.scope.outputs.run_container == 'true' && matrix.python-version == '3.14' - run: docker compose config --quiet + run: bash utils/validate_compose.sh - name: Build container if: needs.scope.outputs.run_container == 'true' && matrix.python-version == '3.14' @@ -222,33 +224,7 @@ jobs: - name: Smoke container if: needs.scope.outputs.run_container == 'true' && matrix.python-version == '3.14' - shell: bash - run: | - docker run --detach --name vidxp-ci \ - --publish 127.0.0.1:8501:8501 vidxp:ci - trap 'docker rm --force vidxp-ci >/dev/null 2>&1 || true' EXIT - - docker exec vidxp-ci vidxp --version - docker exec vidxp-ci vidxp init --json - docker exec vidxp-ci python -c \ - 'import chromadb, cv2, faster_whisper, huggingface_hub, pooch, psutil, sentence_transformers, torch, transformers; assert psutil.virtual_memory().available > 0' - docker exec vidxp-ci python -c \ - 'import importlib.metadata as m; assert not any(d.metadata["Name"].lower().startswith("nvidia-") for d in m.distributions())' - docker exec vidxp-ci sh -c \ - 'test ! -d "$HOME/.cache/huggingface" && test ! -d "$HOME/.cache/clip"' - - for attempt in {1..30}; do - if curl --fail --silent http://127.0.0.1:8501/_stcore/health; then - exit 0 - fi - if [[ "$(docker inspect --format='{{.State.Running}}' vidxp-ci)" != "true" ]]; then - break - fi - sleep 2 - done - - docker logs vidxp-ci - exit 1 + run: bash utils/smoke_container.sh vidxp:ci provider-platform-smoke: if: needs.scope.outputs.run_suite == 'true' @@ -286,58 +262,40 @@ jobs: VIDXP_ALLOW_MODEL_DOWNLOADS: "false" - name: Verify platform and CPU runtime + run: uv run --no-sync python utils/verify_runtime.py cpu + + desktop: + if: >- + github.event_name == 'pull_request' && + needs.scope.outputs.run_desktop == 'true' + needs: scope + uses: ./.github/workflows/desktop.yml + with: + checkout_ref: ${{ github.sha }} + + required: + if: always() && github.event_name == 'pull_request' + needs: + - scope + - validate + - provider-platform-smoke + - desktop + name: validation/required + runs-on: ubuntu-latest + steps: + - name: Require every applicable validation job + env: + DESKTOP_RESULT: ${{ needs.desktop.result }} + PROVIDER_RESULT: ${{ needs.provider-platform-smoke.result }} + SCOPE_RESULT: ${{ needs.scope.result }} + VALIDATE_RESULT: ${{ needs.validate.result }} shell: bash run: | - uv run --no-sync python - <<'PY' - from importlib import metadata - import platform - import chromadb - import cv2 - import faster_whisper - import huggingface_hub - import pooch - import psutil - import sentence_transformers - import torch - import transformers - - from vidxp.runtime import resolve_backends - - assert hasattr(cv2, "FaceDetectorYN") - assert hasattr(cv2, "FaceRecognizerSF") - assert hasattr(faster_whisper, "WhisperModel") - assert hasattr(faster_whisper, "BatchedInferencePipeline") - assert hasattr( - sentence_transformers.SentenceTransformer, - "encode_query", - ) - assert hasattr( - sentence_transformers.SentenceTransformer, - "encode_document", - ) - assert hasattr(transformers, "AutoModel") - assert hasattr(transformers, "AutoProcessor") - assert hasattr(chromadb, "PersistentClient") - assert hasattr(huggingface_hub, "snapshot_download") - assert hasattr(pooch, "retrieve") - assert psutil.virtual_memory().available > 0 - assert torch.version.cuda is None, torch.version.cuda - installed = { - distribution.metadata["Name"].lower().replace("_", "-") - for distribution in metadata.distributions() - if distribution.metadata.get("Name") - } - leaks = sorted( - name - for name in installed - if name in {"cuda-toolkit", "cuda-bindings", "triton"} - or name.startswith("nvidia-") - or name.startswith("pytorch-triton") - ) - assert not leaks, leaks - - profile = resolve_backends("cpu") - assert profile.torch_device == "cpu" - if platform.system() == "Darwin": - assert platform.machine() == "arm64" - PY + [[ "$SCOPE_RESULT" == "success" ]] + for result in \ + "$DESKTOP_RESULT" \ + "$PROVIDER_RESULT" \ + "$VALIDATE_RESULT" + do + [[ "$result" == "success" || "$result" == "skipped" ]] + done diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8eb1ef8..6bdee2f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -6,15 +6,13 @@ on: - main paths: - ".github/workflows/codeql.yml" - - "src/**/*.py" - - "utils/**/*.py" + - "**/*.py" push: branches: - main paths: - ".github/workflows/codeql.yml" - - "src/**/*.py" - - "utils/**/*.py" + - "**/*.py" schedule: - cron: "17 4 * * 6" diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml index 409d2ea..d857091 100644 --- a/.github/workflows/containers.yml +++ b/.github/workflows/containers.yml @@ -1,50 +1,89 @@ -name: Publish core containers +name: Release containers on: workflow_call: inputs: - channel: - description: Container channel to publish. + operation: + description: Build a candidate or promote its immutable digests. required: true type: string - tag: - description: Existing core tag to build. + checkout_ref: + description: Exact source revision used for a candidate build. + required: false + default: "" + type: string + candidate_id: + description: Stable candidate identifier used for temporary tags. required: true type: string + channel: + description: beta or stable when promoting. + required: false + default: "" + type: string version: - description: Core version without the v prefix. + description: Combined release version without the v prefix. required: true type: string + product_digest: + required: false + default: "" + type: string + control_digest: + required: false + default: "" + type: string + worker_digest: + required: false + default: "" + type: string + outputs: + product_digest: + value: ${{ jobs.stage.outputs.product_digest }} + control_digest: + value: ${{ jobs.stage.outputs.control_digest }} + worker_digest: + value: ${{ jobs.stage.outputs.worker_digest }} permissions: contents: read packages: write jobs: - publish: + stage: + if: inputs.operation == 'stage' runs-on: ubuntu-latest + outputs: + product_digest: ${{ steps.digests.outputs.product }} + control_digest: ${{ steps.digests.outputs.control }} + worker_digest: ${{ steps.digests.outputs.worker }} steps: - uses: actions/checkout@v7 with: - ref: ${{ inputs.tag }} + ref: ${{ inputs.checkout_ref }} + + - name: Verify staging inputs + shell: bash + run: | + [[ "${{ inputs.checkout_ref }}" =~ ^[0-9a-f]{40}$ ]] + [[ "${{ inputs.candidate_id }}" =~ ^[0-9a-f]{40}$ ]] - name: Resolve source revision id: source shell: bash run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + - name: Validate Compose deployment configuration + run: bash utils/validate_compose.sh + - uses: docker/setup-buildx-action@v4 - - name: Generate product image metadata + - name: Generate image metadata id: metadata uses: docker/metadata-action@v6 with: images: ghcr.io/${{ github.repository }} - tags: | - type=raw,value=${{ inputs.version }} - type=semver,pattern={{major}}.{{minor}},value=${{ inputs.tag }},enable=${{ inputs.channel == 'stable' }} - type=raw,value=latest,enable=${{ inputs.channel == 'stable' }} - type=raw,value=beta,enable=${{ inputs.channel == 'beta' }} + tags: type=raw,value=candidate-${{ inputs.candidate_id }} labels: | org.opencontainers.image.title=VidXP org.opencontainers.image.description=Local-first video indexing and search @@ -60,7 +99,7 @@ jobs: load: true platforms: linux/amd64 push: false - tags: ${{ steps.metadata.outputs.tags }} + tags: ghcr.io/${{ github.repository }}:candidate-${{ inputs.candidate_id }} labels: ${{ steps.metadata.outputs.labels }} cache-from: type=gha,scope=release-product cache-to: type=gha,mode=max,scope=release-product @@ -73,9 +112,7 @@ jobs: platforms: linux/amd64 push: false target: control - tags: | - ghcr.io/${{ github.repository }}:${{ inputs.version }}-control - ghcr.io/${{ github.repository }}:${{ inputs.channel == 'stable' && 'latest' || 'beta' }}-control + tags: ghcr.io/${{ github.repository }}:candidate-${{ inputs.candidate_id }}-control labels: ${{ steps.metadata.outputs.labels }} cache-from: type=gha,scope=release-control cache-to: type=gha,mode=max,scope=release-control @@ -88,53 +125,58 @@ jobs: platforms: linux/amd64 push: false target: worker - tags: | - ghcr.io/${{ github.repository }}:${{ inputs.version }}-worker - ghcr.io/${{ github.repository }}:${{ inputs.channel == 'stable' && 'latest' || 'beta' }}-worker + tags: ghcr.io/${{ github.repository }}:candidate-${{ inputs.candidate_id }}-worker labels: ${{ steps.metadata.outputs.labels }} cache-from: type=gha,scope=release-worker cache-to: type=gha,mode=max,scope=release-worker - - name: Smoke product image + - name: Smoke candidate images shell: bash run: | - image="ghcr.io/${{ github.repository }}:${{ inputs.version }}" - docker run --detach --name vidxp-release \ - --publish 127.0.0.1:8501:8501 "$image" - trap 'docker rm --force vidxp-release >/dev/null 2>&1 || true' EXIT - - docker exec vidxp-release vidxp --version - docker exec vidxp-release vidxp init --json - docker exec vidxp-release python -c \ - 'import chromadb, cv2, faster_whisper, huggingface_hub, pooch, psutil, sentence_transformers, torch, transformers; assert psutil.virtual_memory().available > 0' - docker exec vidxp-release python -c \ - 'import importlib.metadata as m; assert not any(d.metadata["Name"].lower().startswith("nvidia-") for d in m.distributions())' - docker exec vidxp-release sh -c \ - 'test ! -d "$HOME/.cache/huggingface" && test ! -d "$HOME/.cache/clip"' - - for attempt in {1..30}; do - if curl --fail --silent http://127.0.0.1:8501/_stcore/health; then - exit 0 - fi - if [[ "$(docker inspect --format='{{.State.Running}}' vidxp-release)" != "true" ]]; then - break - fi - sleep 2 - done + product="ghcr.io/${{ github.repository }}:candidate-${{ inputs.candidate_id }}" + control="${product}-control" + worker="${product}-worker" + bash utils/smoke_container.sh "$product" "$control" "$worker" - docker logs vidxp-release - exit 1 + - name: Log in to GitHub Container Registry + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: Smoke server images + - name: Push candidate images and record immutable digests + id: digests shell: bash run: | - control="ghcr.io/${{ github.repository }}:${{ inputs.version }}-control" - worker="ghcr.io/${{ github.repository }}:${{ inputs.version }}-worker" - docker run --rm "$control" vidxp-api --help - docker run --rm "$control" vidxp-mcp --help - docker run --rm "$worker" vidxp init --json - docker run --rm "$worker" python -c \ - 'import chromadb, cv2, faster_whisper, huggingface_hub, pooch, psutil, sentence_transformers, torch, transformers; assert psutil.virtual_memory().available > 0' + digest() { + docker buildx imagetools inspect "$1" --format '{{json .Manifest}}' | + jq -er '.digest' + } + base="ghcr.io/${{ github.repository }}:candidate-${{ inputs.candidate_id }}" + docker push "$base" + docker push "${base}-control" + docker push "${base}-worker" + { + echo "product=$(digest "$base")" + echo "control=$(digest "${base}-control")" + echo "worker=$(digest "${base}-worker")" + } >> "$GITHUB_OUTPUT" + + promote: + if: inputs.operation == 'promote' + runs-on: ubuntu-latest + steps: + - name: Verify promotion inputs + shell: bash + run: | + [[ "${{ inputs.channel }}" == "beta" || "${{ inputs.channel }}" == "stable" ]] + [[ "${{ inputs.candidate_id }}" =~ ^[0-9a-f]{40}$ ]] + [[ "${{ inputs.product_digest }}" =~ ^sha256:[0-9a-f]{64}$ ]] + [[ "${{ inputs.control_digest }}" =~ ^sha256:[0-9a-f]{64}$ ]] + [[ "${{ inputs.worker_digest }}" =~ ^sha256:[0-9a-f]{64}$ ]] + + - uses: docker/setup-buildx-action@v4 - name: Log in to GitHub Container Registry uses: docker/login-action@v4 @@ -143,89 +185,65 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Protect immutable version tags - id: existing - env: - SOURCE_SHA: ${{ steps.source.outputs.sha }} + - name: Promote the candidate manifests without rebuilding shell: bash run: | - check_version_tag() { - local name="$1" - local image="$2" - local local_image="vidxp-release-local:$name" - - docker tag "$image" "$local_image" - if ! docker pull "$image" >/dev/null 2>&1; then - docker tag "$local_image" "$image" - echo "${name}=false" >> "$GITHUB_OUTPUT" - return - fi - - revision="$( - docker inspect \ - --format '{{ index .Config.Labels "org.opencontainers.image.revision" }}' \ - "$image" + repository="ghcr.io/${{ github.repository }}" + candidate="${repository}:candidate-${{ inputs.candidate_id }}" + + promote() { + local source="$1" + local expected="$2" + shift 2 + actual="$( + docker buildx imagetools inspect "$source" \ + --format '{{json .Manifest}}' | jq -er '.digest' )" - if [[ "$revision" != "$SOURCE_SHA" ]]; then - echo "::error::$image already belongs to source revision $revision, not $SOURCE_SHA." + if [[ "$actual" != "$expected" ]]; then + echo "::error::$source resolved to $actual instead of $expected." exit 1 fi - echo "${name}=true" >> "$GITHUB_OUTPUT" + for target in "$@"; do + existing="$( + docker buildx imagetools inspect "$target" \ + --format '{{json .Manifest}}' 2>/dev/null | jq -r '.digest // empty' || true + )" + if [[ "$target" == "${repository}:${{ inputs.version }}"* && + -n "$existing" && "$existing" != "$expected" ]]; then + echo "::error::Immutable tag $target already points to $existing." + exit 1 + fi + [[ "$existing" == "$expected" ]] || \ + docker buildx imagetools create \ + --prefer-index=false \ + --tag "$target" \ + "${repository}@${expected}" + done } - check_version_tag \ - product \ - "ghcr.io/${{ github.repository }}:${{ inputs.version }}" - check_version_tag \ - control \ - "ghcr.io/${{ github.repository }}:${{ inputs.version }}-control" - check_version_tag \ - worker \ - "ghcr.io/${{ github.repository }}:${{ inputs.version }}-worker" - - - name: Publish containers - shell: bash - run: | - product="ghcr.io/${{ github.repository }}:${{ inputs.version }}" - control="${product}-control" - worker="${product}-worker" - control_channel="ghcr.io/${{ github.repository }}:${{ inputs.channel == 'stable' && 'latest' || 'beta' }}-control" - worker_channel="ghcr.io/${{ github.repository }}:${{ inputs.channel == 'stable' && 'latest' || 'beta' }}-worker" - - if [[ "${{ steps.existing.outputs.product }}" == "true" ]]; then - while read -r image; do - [[ "$image" == "$product" ]] || docker tag "$product" "$image" - done <<< "${{ steps.metadata.outputs.tags }}" - fi - while read -r image; do - if [[ "$image" != "$product" || - "${{ steps.existing.outputs.product }}" != "true" ]]; then - docker push "$image" - fi - done <<< "${{ steps.metadata.outputs.tags }}" - - if [[ "${{ steps.existing.outputs.control }}" == "true" ]]; then - docker tag "$control" "$control_channel" + product_tags=("${repository}:${{ inputs.version }}") + control_tags=("${repository}:${{ inputs.version }}-control") + worker_tags=("${repository}:${{ inputs.version }}-worker") + if [[ "${{ inputs.channel }}" == "stable" ]]; then + major_minor="$(cut -d. -f1,2 <<< "${{ inputs.version }}")" + product_tags+=("${repository}:${major_minor}" "${repository}:latest") + control_tags+=("${repository}:latest-control") + worker_tags+=("${repository}:latest-worker") else - docker push "$control" + product_tags+=("${repository}:beta") + control_tags+=("${repository}:beta-control") + worker_tags+=("${repository}:beta-worker") fi - docker push "$control_channel" - if [[ "${{ steps.existing.outputs.worker }}" == "true" ]]; then - docker tag "$worker" "$worker_channel" - else - docker push "$worker" - fi - docker push "$worker_channel" + promote "$candidate" "${{ inputs.product_digest }}" "${product_tags[@]}" + promote "${candidate}-control" "${{ inputs.control_digest }}" "${control_tags[@]}" + promote "${candidate}-worker" "${{ inputs.worker_digest }}" "${worker_tags[@]}" - - name: Verify public container access + - name: Verify public release tags shell: bash run: | docker logout ghcr.io for suffix in "" "-control" "-worker"; do - image="ghcr.io/${{ github.repository }}:${{ inputs.version }}${suffix}" - if ! docker buildx imagetools inspect "$image"; then - echo "::error::Make the GHCR package public, then rerun this workflow for the same tag." - exit 1 - fi + docker buildx imagetools inspect \ + "ghcr.io/${{ github.repository }}:${{ inputs.version }}${suffix}" done diff --git a/.github/workflows/desktop.yml b/.github/workflows/desktop.yml index e2c27d0..8b48c9b 100644 --- a/.github/workflows/desktop.yml +++ b/.github/workflows/desktop.yml @@ -7,6 +7,11 @@ on: description: Commit to build required: true type: string + artifact_retention_days: + description: Number of days to retain built installers. + required: false + default: 14 + type: number workflow_dispatch: inputs: checkout_ref: @@ -14,18 +19,11 @@ on: required: false default: "" type: string - pull_request: - branches: - - main - - release - paths: - - "desktop/**" - - "src/vidxp/requirements/**" - - "src/vidxp/capabilities/*/requirements.txt" - - "pyproject.toml" - - "uv.lock" - - ".github/workflows/desktop.yml" - + artifact_retention_days: + description: Number of days to retain built installers. + required: false + default: 14 + type: number permissions: contents: read @@ -35,16 +33,12 @@ concurrency: jobs: build: - if: >- - github.event_name != 'pull_request' || - github.base_ref != 'release' || - github.head_ref != 'main' name: ${{ matrix.target == 'windows' && 'Windows x86-64 NSIS' || matrix.target == 'macos' && 'macOS Apple Silicon DMG' || 'Linux x86-64 AppImage' }} runs-on: ${{ matrix.target == 'windows' && 'windows-2025' || matrix.target == 'macos' && 'macos-15' || 'ubuntu-24.04' }} strategy: fail-fast: false matrix: - target: ${{ fromJSON(github.event_name == 'pull_request' && !startsWith(github.head_ref, 'release-please--branches--') && '["windows"]' || '["windows","macos","linux"]') }} + target: [windows, macos, linux] steps: - uses: actions/checkout@v7 @@ -75,42 +69,41 @@ jobs: version: "0.12.0" enable-cache: false - - uses: dtolnay/rust-toolchain@1.97.1 + - id: rust-toolchain + uses: dtolnay/rust-toolchain@1.97.1 + + - name: Install locked license tooling + run: cargo install cargo-about --version 0.9.1 --locked --features cli - name: Restore Rust build cache - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: | ~/.cargo/registry ~/.cargo/git desktop/src-tauri/target - key: desktop-rust-${{ runner.os }}-${{ runner.arch }}-1.97.1-${{ hashFiles('desktop/src-tauri/Cargo.lock') }} + key: desktop-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.rust-toolchain.outputs.cachekey }}-${{ hashFiles('desktop/src-tauri/Cargo.lock') }} restore-keys: | - desktop-rust-${{ runner.os }}-${{ runner.arch }}-1.97.1- + desktop-rust-${{ runner.os }}-${{ runner.arch }}-${{ steps.rust-toolchain.outputs.cachekey }}- - name: Install locked desktop tooling run: npm ci working-directory: desktop - - name: Verify the desktop runtime constraints - shell: bash + - name: Check the desktop frontend + run: npm run check + working-directory: desktop + + - name: Verify generated desktop contracts and notices run: | - generated="$RUNNER_TEMP/runtime-constraints.txt" - uv export \ - --frozen \ - --extra local-worker \ - --extra frontend \ - --no-dev \ - --no-emit-project \ - --no-hashes \ - --format requirements-txt \ - --output-file "$generated" - git diff --no-index --ignore-matching-lines='^#' -- \ - desktop/runtime-constraints.txt "$generated" + cargo fetch --manifest-path src-tauri/Cargo.toml --locked + npm run model-catalog:check + npm run notices:check + working-directory: desktop - name: Restore the pinned uv sidecar id: uv-sidecar-cache - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: desktop/src-tauri/binaries key: desktop-uv-sidecar-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('desktop/sidecars.json') }} @@ -129,22 +122,7 @@ jobs: - name: Verify the Windows app uses the GUI subsystem if: runner.os == 'Windows' - shell: pwsh - run: | - $path = "desktop/src-tauri/target/release/vidxp-desktop.exe" - $stream = [System.IO.File]::OpenRead($path) - try { - $reader = [System.IO.BinaryReader]::new($stream) - $stream.Position = 0x3c - $peOffset = $reader.ReadInt32() - $stream.Position = $peOffset + 4 + 20 + 68 - $subsystem = $reader.ReadUInt16() - if ($subsystem -ne 2) { - throw "Expected Windows GUI subsystem 2, found $subsystem." - } - } finally { - $stream.Dispose() - } + run: powershell -ExecutionPolicy Bypass -File desktop/scripts/verify-windows-gui.ps1 - name: Preserve the desktop installer uses: actions/upload-artifact@v7 @@ -153,4 +131,4 @@ jobs: path: ${{ matrix.target == 'windows' && 'desktop/src-tauri/target/release/bundle/nsis/*-setup.exe' || matrix.target == 'macos' && 'desktop/src-tauri/target/release/bundle/dmg/*.dmg' || 'desktop/src-tauri/target/release/bundle/appimage/*.AppImage' }} if-no-files-found: error compression-level: 0 - retention-days: 14 + retention-days: ${{ inputs.artifact_retention_days || 14 }} diff --git a/.github/workflows/publish-desktop.yml b/.github/workflows/publish-desktop.yml deleted file mode 100644 index 2fd0baa..0000000 --- a/.github/workflows/publish-desktop.yml +++ /dev/null @@ -1,138 +0,0 @@ -name: Publish desktop release - -on: - workflow_dispatch: - inputs: - tag: - description: Existing desktop tag to build and publish. - required: true - type: string - -permissions: - contents: read - -concurrency: - group: desktop-release-${{ inputs.tag }} - cancel-in-progress: false - -jobs: - verify: - runs-on: ubuntu-latest - outputs: - source_sha: ${{ steps.source.outputs.sha }} - steps: - - uses: actions/checkout@v7 - with: - ref: ${{ inputs.tag }} - - - name: Resolve source revision - id: source - shell: bash - run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" - - - name: Verify desktop tag and version sources - shell: bash - run: | - tag="${{ inputs.tag }}" - if [[ "$tag" != desktop-v* ]]; then - echo "::error::$tag is not a desktop release tag." - exit 1 - fi - if ! git show-ref --verify --quiet "refs/tags/$tag"; then - echo "::error::$tag is not an existing Git tag." - exit 1 - fi - python - "${tag#desktop-v}" <<'PY' - import json - from pathlib import Path - import sys - import tomllib - - expected = sys.argv[1] - desktop = Path("desktop") - runtime_manifest = json.loads( - (desktop / "runtime-manifest.json").read_text() - ) - versions = { - "VERSION": (desktop / "VERSION").read_text().strip(), - "Cargo.toml": tomllib.loads( - (desktop / "src-tauri" / "Cargo.toml").read_text() - )["package"]["version"], - "package.json": json.loads( - (desktop / "package.json").read_text() - )["version"], - "package-lock.json": json.loads( - (desktop / "package-lock.json").read_text() - )["version"], - "package-lock root": json.loads( - (desktop / "package-lock.json").read_text() - )["packages"][""]["version"], - "runtime manifest desktop": runtime_manifest["desktop_version"], - "runtime manifest package": runtime_manifest["package_version"], - "Tauri config": json.loads( - (desktop / "src-tauri" / "tauri.conf.json").read_text() - )["version"], - } - mismatches = { - source: actual - for source, actual in versions.items() - if actual != expected - } - if mismatches: - raise SystemExit( - f"desktop tag expects {expected}; mismatches: {mismatches}" - ) - PY - - build: - needs: verify - uses: ./.github/workflows/desktop.yml - with: - checkout_ref: ${{ inputs.tag }} - - publish: - needs: - - build - - verify - runs-on: ubuntu-latest - permissions: - actions: write - contents: write - steps: - - uses: actions/download-artifact@v8 - with: - pattern: vidxp-desktop-* - path: desktop-dist/ - merge-multiple: true - - - name: Publish complete desktop release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - shell: bash - run: | - tag="${{ inputs.tag }}" - version="${tag#desktop-v}" - gh release upload "$tag" desktop-dist/* \ - --repo "$GITHUB_REPOSITORY" \ - --clobber - if [[ "$version" == *-* ]]; then - gh release edit "$tag" \ - --repo "$GITHUB_REPOSITORY" \ - --draft=false \ - --prerelease - else - gh release edit "$tag" \ - --repo "$GITHUB_REPOSITORY" \ - --draft=false \ - --latest - fi - - - name: Synchronize stable source back to main - if: ${{ !contains(inputs.tag, '-b.') }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh workflow run sync-channels.yml \ - --repo "$GITHUB_REPOSITORY" \ - --ref main \ - -f release_sha="${{ needs.verify.outputs.source_sha }}" diff --git a/.github/workflows/release-candidate.yml b/.github/workflows/release-candidate.yml new file mode 100644 index 0000000..835ea17 --- /dev/null +++ b/.github/workflows/release-candidate.yml @@ -0,0 +1,205 @@ +name: Release candidate + +on: + workflow_dispatch: + inputs: + pull_request: + description: Release Please pull request number. + required: true + type: string + target_branch: + description: main for beta or release for stable. + required: true + type: string + base_sha: + description: Target branch revision included in the candidate. + required: true + type: string + head_sha: + description: Exact Release Please revision to build. + required: true + type: string + +permissions: + contents: read + packages: write + pull-requests: read + statuses: write + +concurrency: + group: release-candidate-${{ inputs.head_sha }} + cancel-in-progress: false + +jobs: + pending: + runs-on: ubuntu-latest + steps: + - name: Mark the exact candidate revision pending + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HEAD_SHA: ${{ inputs.head_sha }} + TARGET_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + shell: bash + run: | + [[ "$HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] + gh api --method POST "repos/$GITHUB_REPOSITORY/statuses/$HEAD_SHA" \ + -f state=pending \ + -f context=release/candidate \ + -f description='Building the combined release candidate' \ + -f target_url="$TARGET_URL" + + contract: + needs: pending + runs-on: ubuntu-latest + outputs: + channel: ${{ steps.contract.outputs.channel }} + source_tree: ${{ steps.source.outputs.tree }} + tag: ${{ steps.contract.outputs.tag }} + version: ${{ steps.contract.outputs.version }} + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + ref: ${{ inputs.head_sha }} + + - name: Verify the candidate source and current pull request + id: source + env: + BASE_SHA: ${{ inputs.base_sha }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HEAD_SHA: ${{ inputs.head_sha }} + PULL_REQUEST: ${{ inputs.pull_request }} + TARGET_BRANCH: ${{ inputs.target_branch }} + shell: bash + run: | + [[ "$BASE_SHA" =~ ^[0-9a-f]{40}$ ]] + [[ "$HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] + [[ "$TARGET_BRANCH" == "main" || "$TARGET_BRANCH" == "release" ]] + [[ "$(git rev-parse HEAD)" == "$HEAD_SHA" ]] + git merge-base --is-ancestor "$BASE_SHA" "$HEAD_SHA" + + pr="$(gh api "repos/$GITHUB_REPOSITORY/pulls/$PULL_REQUEST")" + [[ "$(jq -r .state <<< "$pr")" == "open" ]] + [[ "$(jq -r .base.ref <<< "$pr")" == "$TARGET_BRANCH" ]] + [[ "$(jq -r .base.sha <<< "$pr")" == "$BASE_SHA" ]] + [[ "$(jq -r .head.sha <<< "$pr")" == "$HEAD_SHA" ]] + [[ "$(jq -r .head.ref <<< "$pr")" == release-please--branches--* ]] + echo "tree=$(git rev-parse 'HEAD^{tree}')" >> "$GITHUB_OUTPUT" + + - name: Validate the combined version contract + id: contract + shell: bash + run: | + channel="${{ inputs.target_branch == 'release' && 'stable' || 'beta' }}" + python utils/release_contract.py --channel "$channel" --github-output \ + >> "$GITHUB_OUTPUT" + + core: + needs: contract + uses: ./.github/workflows/ci.yml + with: + checkout_ref: ${{ inputs.head_sha }} + force_validation: true + package_artifact_name: vidxp-python-dist + provider_platforms: '["ubuntu-24.04","windows-2025","macos-15"]' + python_versions: '["3.11","3.12","3.13","3.14"]' + run_containers: false + + desktop: + needs: contract + uses: ./.github/workflows/desktop.yml + with: + artifact_retention_days: 30 + checkout_ref: ${{ inputs.head_sha }} + + containers: + needs: contract + permissions: + contents: read + packages: write + uses: ./.github/workflows/containers.yml + with: + candidate_id: ${{ inputs.head_sha }} + checkout_ref: ${{ inputs.head_sha }} + operation: stage + version: ${{ needs.contract.outputs.version }} + + finalize: + if: always() + needs: + - pending + - contract + - core + - desktop + - containers + runs-on: ubuntu-latest + steps: + - name: Record the successful candidate + if: >- + needs.pending.result == 'success' && + needs.contract.result == 'success' && + needs.core.result == 'success' && + needs.desktop.result == 'success' && + needs.containers.result == 'success' + env: + CHANNEL: ${{ needs.contract.outputs.channel }} + CONTROL_DIGEST: ${{ needs.containers.outputs.control_digest }} + HEAD_SHA: ${{ inputs.head_sha }} + PRODUCT_DIGEST: ${{ needs.containers.outputs.product_digest }} + SOURCE_TREE: ${{ needs.contract.outputs.source_tree }} + TAG: ${{ needs.contract.outputs.tag }} + VERSION: ${{ needs.contract.outputs.version }} + WORKER_DIGEST: ${{ needs.containers.outputs.worker_digest }} + shell: bash + run: | + jq -n \ + --arg candidate_run_id "$GITHUB_RUN_ID" \ + --arg channel "$CHANNEL" \ + --arg control_digest "$CONTROL_DIGEST" \ + --arg product_digest "$PRODUCT_DIGEST" \ + --arg source_sha "$HEAD_SHA" \ + --arg source_tree "$SOURCE_TREE" \ + --arg tag "$TAG" \ + --arg version "$VERSION" \ + --arg worker_digest "$WORKER_DIGEST" \ + '{candidate_run_id: $candidate_run_id, channel: $channel, + source_sha: $source_sha, source_tree: $source_tree, tag: $tag, + version: $version, containers: {product: $product_digest, + control: $control_digest, worker: $worker_digest}}' \ + > release-candidate.json + + - name: Preserve the candidate manifest + if: >- + needs.pending.result == 'success' && + needs.contract.result == 'success' && + needs.core.result == 'success' && + needs.desktop.result == 'success' && + needs.containers.result == 'success' + uses: actions/upload-artifact@v7 + with: + name: vidxp-release-candidate + path: release-candidate.json + if-no-files-found: error + retention-days: 30 + + - name: Publish the candidate status + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HEAD_SHA: ${{ inputs.head_sha }} + SUCCESS: ${{ needs.pending.result == 'success' && needs.contract.result == 'success' && needs.core.result == 'success' && needs.desktop.result == 'success' && needs.containers.result == 'success' }} + TARGET_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + shell: bash + run: | + if [[ "$SUCCESS" == "true" ]]; then + state=success + description='Combined release candidate is ready' + else + state=failure + description='Combined release candidate failed' + fi + gh api --method POST "repos/$GITHUB_REPOSITORY/statuses/$HEAD_SHA" \ + -f state="$state" \ + -f context=release/candidate \ + -f description="$description" \ + -f target_url="$TARGET_URL" + [[ "$state" == "success" ]] diff --git a/.github/workflows/release-gate.yml b/.github/workflows/release-gate.yml new file mode 100644 index 0000000..7d9c8c3 --- /dev/null +++ b/.github/workflows/release-gate.yml @@ -0,0 +1,40 @@ +name: Release gate + +on: + pull_request_target: + branches: + - main + - release + types: + - opened + - synchronize + - reopened + +permissions: + contents: none + statuses: write + +jobs: + classify: + runs-on: ubuntu-latest + steps: + - name: Classify the pull request without checking out its code + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HEAD_REF: ${{ github.event.pull_request.head.ref }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + TARGET_URL: ${{ github.event.pull_request.html_url }} + shell: bash + run: | + if [[ "$HEAD_REF" == release-please--branches--* ]]; then + state=pending + description='Waiting for the combined release candidate' + else + state=success + description='Not a Release Please pull request' + fi + gh api --method POST "repos/$GITHUB_REPOSITORY/statuses/$HEAD_SHA" \ + -f state="$state" \ + -f context=release/candidate \ + -f description="$description" \ + -f target_url="$TARGET_URL" diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 04e3051..a3dff19 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -12,6 +12,7 @@ permissions: contents: write issues: write pull-requests: write + statuses: write concurrency: group: release-please-${{ github.ref_name }} @@ -21,15 +22,7 @@ jobs: release: runs-on: ubuntu-latest steps: - - name: Enable the beta publication workflow - if: github.ref_name == 'main' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: >- - gh api --method PUT - "repos/$GITHUB_REPOSITORY/actions/workflows/release-to-test-pypi.yml/enable" - - - name: Prepare or create component releases + - name: Prepare or create the combined release id: release uses: googleapis/release-please-action@v5 with: @@ -38,30 +31,95 @@ jobs: target-branch: ${{ github.ref_name }} token: ${{ secrets.GITHUB_TOKEN }} - - name: Publish the core release - if: steps.release.outputs.release_created == 'true' + - name: Refresh and validate the open release candidate + if: steps.release.outputs.release_created != 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAG: ${{ steps.release.outputs.tag_name }} + TARGET_BRANCH: ${{ github.ref_name }} shell: bash run: | - if [[ "${{ github.ref_name }}" == "release" ]]; then - workflow="release-to-pypi.yml" - else - workflow="release-to-test-pypi.yml" + pr="$( + gh api "repos/$GITHUB_REPOSITORY/pulls?state=open&base=$TARGET_BRANCH&per_page=100" \ + --jq '[.[] | select(.head.ref | startswith("release-please--branches--"))][0]' + )" + [[ "$pr" != "null" ]] || exit 0 + + number="$(jq -r .number <<< "$pr")" + head="$(jq -r .head.sha <<< "$pr")" + base="$(jq -r .base.sha <<< "$pr")" + update_log="$RUNNER_TEMP/update-branch.log" + if ! gh api --method PUT \ + "repos/$GITHUB_REPOSITORY/pulls/$number/update-branch" \ + -f expected_head_sha="$head" >"$update_log" 2>&1; then + if ! grep -qiE 'already up.to.date|422|head branch was modified' "$update_log"; then + cat "$update_log" + exit 1 + fi fi - gh workflow run "$workflow" \ + + for _ in {1..45}; do + pr="$(gh api "repos/$GITHUB_REPOSITORY/pulls/$number")" + head="$(jq -r .head.sha <<< "$pr")" + base="$(jq -r .base.sha <<< "$pr")" + comparison="$(gh api "repos/$GITHUB_REPOSITORY/compare/${base}...${head}")" + if [[ "$(jq -r .merge_base_commit.sha <<< "$comparison")" == "$base" ]]; then + break + fi + sleep 2 + done + [[ "$(jq -r .merge_base_commit.sha <<< "$comparison")" == "$base" ]] + + current_status="$( + gh api "repos/$GITHUB_REPOSITORY/commits/$head/status" \ + --jq '[.statuses[] | select(.context == "release/candidate")] | sort_by(.updated_at) | last | .state // ""' + )" + if [[ "$current_status" == "success" ]]; then + echo "Candidate $head is already validated." + exit 0 + fi + + run_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/workflows/release-candidate.yml" + gh api --method POST "repos/$GITHUB_REPOSITORY/statuses/$head" \ + -f state=pending \ + -f context=release/candidate \ + -f description='Combined release candidate is queued' \ + -f target_url="$run_url" + gh workflow run release-candidate.yml \ --repo "$GITHUB_REPOSITORY" \ - --ref "$TAG" \ - -f tag="$TAG" + --ref "$TARGET_BRANCH" \ + -f pull_request="$number" \ + -f target_branch="$TARGET_BRANCH" \ + -f base_sha="$base" \ + -f head_sha="$head" - - name: Publish the desktop release - if: steps.release.outputs['desktop--release_created'] == 'true' + - name: Dispatch publication of the validated candidate + if: steps.release.outputs.release_created == 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAG: ${{ steps.release.outputs['desktop--tag_name'] }} + RELEASE_SHA: ${{ steps.release.outputs.sha }} + TAG: ${{ steps.release.outputs.tag_name }} + TARGET_BRANCH: ${{ github.ref_name }} + shell: bash run: | - gh workflow run publish-desktop.yml \ + pr="$( + gh api -H 'Accept: application/vnd.github+json' \ + "repos/$GITHUB_REPOSITORY/commits/$RELEASE_SHA/pulls" \ + --jq '[.[] | select(.base.ref == env.TARGET_BRANCH and (.head.ref | startswith("release-please--branches--")))][0]' + )" + [[ "$pr" != "null" ]] + head="$(jq -r .head.sha <<< "$pr")" + status="$( + gh api "repos/$GITHUB_REPOSITORY/commits/$head/status" \ + --jq '[.statuses[] | select(.context == "release/candidate")] | sort_by(.updated_at) | last' + )" + [[ "$(jq -r .state <<< "$status")" == "success" ]] + target_url="$(jq -r .target_url <<< "$status")" + [[ "$target_url" =~ /actions/runs/([0-9]+)$ ]] + candidate_run_id="${BASH_REMATCH[1]}" + + gh workflow run release-to-pypi.yml \ --repo "$GITHUB_REPOSITORY" \ --ref "$TAG" \ - -f tag="$TAG" + -f tag="$TAG" \ + -f candidate_run_id="$candidate_run_id" \ + -f candidate_head_sha="$head" diff --git a/.github/workflows/release-to-pypi.yml b/.github/workflows/release-to-pypi.yml index cf54687..5ea62e7 100644 --- a/.github/workflows/release-to-pypi.yml +++ b/.github/workflows/release-to-pypi.yml @@ -1,99 +1,140 @@ -name: Release (tag → PyPI and GHCR) +name: Publish combined release on: workflow_dispatch: inputs: tag: - description: Existing stable core tag to publish. + description: Existing combined release tag created by Release Please. + required: true + type: string + candidate_run_id: + description: Successful Release candidate workflow run. + required: true + type: string + candidate_head_sha: + description: Exact Release Please head revision that was validated. required: true type: string permissions: + actions: read contents: read - pull-requests: read concurrency: - group: pypi-${{ inputs.tag }} + group: publish-${{ inputs.tag }} cancel-in-progress: false jobs: - validate: - uses: ./.github/workflows/ci.yml - with: - checkout_ref: ${{ inputs.tag }} - force_validation: true - python_versions: '["3.11","3.12","3.13","3.14"]' - provider_platforms: '["ubuntu-24.04","windows-2025","macos-15"]' - run_containers: false - - build: - needs: validate + resolve: runs-on: ubuntu-latest outputs: + channel: ${{ steps.contract.outputs.channel }} + control_digest: ${{ steps.candidate.outputs.control_digest }} + product_digest: ${{ steps.candidate.outputs.product_digest }} source_sha: ${{ steps.source.outputs.sha }} - version: ${{ steps.version.outputs.version }} + version: ${{ steps.contract.outputs.version }} + worker_digest: ${{ steps.candidate.outputs.worker_digest }} steps: - uses: actions/checkout@v7 with: + fetch-depth: 0 ref: ${{ inputs.tag }} - - name: Resolve source revision - id: source + - name: Verify tag and combined version contract + id: contract shell: bash - run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + run: | + tag="${{ inputs.tag }}" + git show-ref --verify --quiet "refs/tags/$tag" + if [[ "$tag" == *-* ]]; then channel=beta; else channel=stable; fi + python utils/release_contract.py \ + --channel "$channel" \ + --expected-tag "$tag" \ + --github-output >> "$GITHUB_OUTPUT" - - uses: actions/setup-python@v7 - with: - python-version: "3.14" - cache: pip + - name: Download the exact candidate artifacts + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RUN_ID: ${{ inputs.candidate_run_id }} + shell: bash + run: | + [[ "$RUN_ID" =~ ^[0-9]+$ ]] + run="$(gh run view "$RUN_ID" --repo "$GITHUB_REPOSITORY" --json conclusion,event,name)" + [[ "$(jq -r .conclusion <<< "$run")" == "success" ]] + [[ "$(jq -r .event <<< "$run")" == "workflow_dispatch" ]] + [[ "$(jq -r .name <<< "$run")" == "Release candidate" ]] + for artifact in \ + vidxp-release-candidate \ + vidxp-python-dist \ + vidxp-desktop-windows-x86_64 \ + vidxp-desktop-macos-aarch64 \ + vidxp-desktop-linux-x86_64; do + gh run download "$RUN_ID" \ + --repo "$GITHUB_REPOSITORY" \ + --name "$artifact" \ + --dir "candidate-artifacts/$artifact" + done - - name: Verify stable tag - id: version + - name: Match the candidate to the merged release tree + id: candidate + env: + CANDIDATE_HEAD_SHA: ${{ inputs.candidate_head_sha }} + CANDIDATE_RUN_ID: ${{ inputs.candidate_run_id }} + CHANNEL: ${{ steps.contract.outputs.channel }} + TAG: ${{ steps.contract.outputs.tag }} + VERSION: ${{ steps.contract.outputs.version }} shell: bash run: | - tag="${{ inputs.tag }}" - if [[ "$tag" != v* || "$tag" == *-* ]]; then - echo "::error::$tag is not a stable core release tag." - exit 1 - fi - if ! git show-ref --verify --quiet "refs/tags/$tag"; then - echo "::error::$tag is not an existing Git tag." - exit 1 - fi - version="${tag#v}" - package_version="$( - python -c \ - 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])' - )" - if [[ "$package_version" != "$version" ]]; then - echo "::error::Tag $tag does not match package version $package_version." - exit 1 - fi - echo "version=$version" >> "$GITHUB_OUTPUT" + [[ "$CANDIDATE_HEAD_SHA" =~ ^[0-9a-f]{40}$ ]] + candidate="candidate-artifacts/vidxp-release-candidate/release-candidate.json" + jq -e \ + --arg run "$CANDIDATE_RUN_ID" \ + --arg channel "$CHANNEL" \ + --arg sha "$CANDIDATE_HEAD_SHA" \ + --arg tag "$TAG" \ + --arg version "$VERSION" \ + '.candidate_run_id == $run and .channel == $channel and + .source_sha == $sha and .tag == $tag and .version == $version' \ + "$candidate" - - name: Install build tooling - run: python -m pip install -r utils/build-requirements.txt + git fetch origin "$CANDIDATE_HEAD_SHA" + candidate_tree="$(git rev-parse "${CANDIDATE_HEAD_SHA}^{tree}")" + release_tree="$(git rev-parse 'HEAD^{tree}')" + recorded_tree="$(jq -r .source_tree "$candidate")" + [[ "$candidate_tree" == "$release_tree" ]] + [[ "$recorded_tree" == "$release_tree" ]] - - name: Build distribution - run: bash utils/build_package.sh + { + echo "product_digest=$(jq -r .containers.product "$candidate")" + echo "control_digest=$(jq -r .containers.control "$candidate")" + echo "worker_digest=$(jq -r .containers.worker "$candidate")" + } >> "$GITHUB_OUTPUT" - - name: Smoke distribution + - name: Prepare release assets and checksums + id: source shell: bash run: | - python -m venv .release-smoke - .release-smoke/bin/python -m pip install dist/*.whl - .release-smoke/bin/python -m pip check - .release-smoke/bin/vidxp --version + mkdir release-assets + find candidate-artifacts/vidxp-python-dist \ + candidate-artifacts/vidxp-desktop-* \ + -type f -exec cp '{}' release-assets/ ';' + [[ "$(find release-assets -maxdepth 1 -name '*.whl' | wc -l)" == 1 ]] + [[ "$(find release-assets -maxdepth 1 -name '*.tar.gz' | wc -l)" == 1 ]] + [[ "$(find release-assets -maxdepth 1 -name '*.exe' | wc -l)" == 1 ]] + [[ "$(find release-assets -maxdepth 1 -name '*.dmg' | wc -l)" == 1 ]] + [[ "$(find release-assets -maxdepth 1 -name '*.AppImage' | wc -l)" == 1 ]] + (cd release-assets && sha256sum -- ./* > SHA256SUMS) + echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" - uses: actions/upload-artifact@v7 with: - name: pypi-${{ inputs.tag }} - path: dist/ + name: vidxp-release-assets + path: release-assets/ if-no-files-found: error - retention-days: 14 + retention-days: 30 publish-pypi: - needs: build + needs: resolve runs-on: ubuntu-latest environment: pypi permissions: @@ -106,23 +147,25 @@ jobs: - uses: actions/download-artifact@v8 with: - name: pypi-${{ inputs.tag }} - path: dist/ + name: vidxp-release-assets + path: release-assets/ - name: Check PyPI release state id: registry shell: bash run: | + mkdir dist + cp release-assets/*.whl release-assets/*.tar.gz dist/ state="$( python utils/verify_published_distribution.py \ --repository https://pypi.org \ --package vidxp \ - --version "${{ needs.build.outputs.version }}" \ + --version "${{ needs.resolve.outputs.version }}" \ --dist dist )" echo "state=$state" >> "$GITHUB_OUTPUT" - - name: Publish to PyPI + - name: Publish the beta or stable package to PyPI if: steps.registry.outputs.state == 'absent' uses: pypa/gh-action-pypi-publish@release/v1 with: @@ -130,20 +173,24 @@ jobs: publish-containers: needs: - - build + - resolve - publish-pypi permissions: contents: read packages: write uses: ./.github/workflows/containers.yml with: - channel: stable - tag: ${{ inputs.tag }} - version: ${{ needs.build.outputs.version }} + candidate_id: ${{ inputs.candidate_head_sha }} + channel: ${{ needs.resolve.outputs.channel }} + control_digest: ${{ needs.resolve.outputs.control_digest }} + operation: promote + product_digest: ${{ needs.resolve.outputs.product_digest }} + version: ${{ needs.resolve.outputs.version }} + worker_digest: ${{ needs.resolve.outputs.worker_digest }} publish-github: needs: - - build + - resolve - publish-pypi - publish-containers runs-on: ubuntu-latest @@ -151,28 +198,59 @@ jobs: actions: write contents: write steps: + - uses: actions/checkout@v7 + with: + ref: ${{ inputs.tag }} + - uses: actions/download-artifact@v8 with: - name: pypi-${{ inputs.tag }} - path: dist/ + name: vidxp-release-assets + path: release-assets/ - - name: Publish complete stable release + - name: Publish the complete combined release env: + CHANNEL: ${{ needs.resolve.outputs.channel }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ inputs.tag }} + VERSION: ${{ needs.resolve.outputs.version }} shell: bash run: | - gh release upload "${{ inputs.tag }}" dist/* \ + gh release view "$TAG" \ --repo "$GITHUB_REPOSITORY" \ - --clobber - gh release edit "${{ inputs.tag }}" \ + --json body \ + --jq .body > release-please-notes.md + python utils/render_release_notes.py \ + --assets release-assets \ + --channel "$CHANNEL" \ + --existing release-please-notes.md \ + --output release-notes.md \ + --repository "$GITHUB_REPOSITORY" \ + --tag "$TAG" \ + --template .github/release-intro.md \ + --version "$VERSION" + gh release upload "$TAG" release-assets/* \ --repo "$GITHUB_REPOSITORY" \ - --draft=false + --clobber + if [[ "$CHANNEL" == "beta" ]]; then + gh release edit "$TAG" \ + --repo "$GITHUB_REPOSITORY" \ + --notes-file release-notes.md \ + --draft=false \ + --prerelease + else + gh release edit "$TAG" \ + --repo "$GITHUB_REPOSITORY" \ + --notes-file release-notes.md \ + --draft=false \ + --latest + fi - - name: Synchronize stable source back to main + - name: Synchronize a completed stable release back to main + if: needs.resolve.outputs.channel == 'stable' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh workflow run sync-channels.yml \ --repo "$GITHUB_REPOSITORY" \ --ref main \ - -f release_sha="${{ needs.build.outputs.source_sha }}" + -f release_sha="${{ needs.resolve.outputs.source_sha }}" diff --git a/.github/workflows/release-to-test-pypi.yml b/.github/workflows/release-to-test-pypi.yml index c9d0529..2cc019e 100644 --- a/.github/workflows/release-to-test-pypi.yml +++ b/.github/workflows/release-to-test-pypi.yml @@ -1,18 +1,25 @@ -name: Prerelease (tag → TestPyPI) +name: Publish nightly package on: + push: + branches: + - main + paths-ignore: + - "**/*.md" + - "docs/**" workflow_dispatch: inputs: - tag: - description: Existing core prerelease tag to publish. - required: true + checkout_ref: + description: Main revision to publish as an ephemeral nightly. + required: false + default: "" type: string permissions: contents: read concurrency: - group: testpypi-${{ inputs.tag }} + group: nightly-testpypi cancel-in-progress: false jobs: @@ -23,54 +30,35 @@ jobs: steps: - uses: actions/checkout@v7 with: - ref: ${{ inputs.tag }} + ref: ${{ inputs.checkout_ref || github.sha }} - uses: actions/setup-python@v7 with: python-version: "3.14" cache: pip - - name: Verify prerelease tag + - name: Assign an ephemeral nightly version id: version shell: bash run: | - tag="${{ inputs.tag }}" - if [[ "$tag" != v*-* ]]; then - echo "::error::$tag is not a core prerelease tag." - exit 1 - fi - if ! git show-ref --verify --quiet "refs/tags/$tag"; then - echo "::error::$tag is not an existing Git tag." - exit 1 - fi - version="${tag#v}" - package_version="$( - python -c \ - 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])' - )" - if [[ "$package_version" != "$version" ]]; then - echo "::error::Tag $tag does not match package version $package_version." - exit 1 - fi + version="$(python utils/prepare_nightly.py --run-number "$GITHUB_RUN_NUMBER")" echo "version=$version" >> "$GITHUB_OUTPUT" - name: Install build tooling run: python -m pip install -r utils/build-requirements.txt - - name: Build distribution - run: bash utils/build_package.sh - - - name: Smoke distribution + - name: Build and smoke the nightly distribution shell: bash run: | - python -m venv .release-smoke - .release-smoke/bin/python -m pip install dist/*.whl - .release-smoke/bin/python -m pip check - .release-smoke/bin/vidxp --version + bash utils/build_package.sh + python -m venv .nightly-smoke + .nightly-smoke/bin/python -m pip install dist/*.whl + .nightly-smoke/bin/python -m pip check + [[ "$(.nightly-smoke/bin/vidxp --version)" == "VidXP ${{ steps.version.outputs.version }}" ]] - uses: actions/upload-artifact@v7 with: - name: testpypi-${{ inputs.tag }} + name: vidxp-nightly-dist path: dist/ if-no-files-found: error retention-days: 14 @@ -85,11 +73,11 @@ jobs: steps: - uses: actions/checkout@v7 with: - ref: ${{ inputs.tag }} + ref: ${{ inputs.checkout_ref || github.sha }} - uses: actions/download-artifact@v8 with: - name: testpypi-${{ inputs.tag }} + name: vidxp-nightly-dist path: dist/ - name: Check TestPyPI release state @@ -105,49 +93,39 @@ jobs: )" echo "state=$state" >> "$GITHUB_OUTPUT" - - name: Publish to TestPyPI + - name: Publish the unique nightly to TestPyPI if: steps.registry.outputs.state == 'absent' uses: pypa/gh-action-pypi-publish@release/v1 with: repository-url: https://test.pypi.org/legacy/ packages-dir: dist/ - publish-containers: - needs: - - build - - publish - permissions: - contents: read - packages: write - uses: ./.github/workflows/containers.yml - with: - channel: beta - tag: ${{ inputs.tag }} - version: ${{ needs.build.outputs.version }} - - publish-github: - needs: - - build - - publish - - publish-containers - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/download-artifact@v8 - with: - name: testpypi-${{ inputs.tag }} - path: dist/ - - - name: Publish complete prerelease - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Download and install the exact TestPyPI artifact shell: bash run: | - gh release upload "${{ inputs.tag }}" dist/* \ - --repo "$GITHUB_REPOSITORY" \ - --clobber - gh release edit "${{ inputs.tag }}" \ - --repo "$GITHUB_REPOSITORY" \ - --draft=false \ - --prerelease + for _ in {1..30}; do + state="$( + python utils/verify_published_distribution.py \ + --repository https://test.pypi.org \ + --package vidxp \ + --version "${{ needs.build.outputs.version }}" \ + --dist dist + )" + [[ "$state" == "identical" ]] && break + sleep 10 + done + [[ "$state" == "identical" ]] + + python -m pip download \ + --index-url https://test.pypi.org/simple \ + --no-deps \ + --no-cache-dir \ + --dest downloaded \ + "vidxp==${{ needs.build.outputs.version }}" + [[ "$(sha256sum dist/*.whl | cut -d' ' -f1)" == \ + "$(sha256sum downloaded/*.whl | cut -d' ' -f1)" ]] + python -m venv .testpypi-smoke + .testpypi-smoke/bin/python -m pip install downloaded/*.whl + .testpypi-smoke/bin/python -m pip check + [[ "$(.testpypi-smoke/bin/vidxp --version)" == \ + "VidXP ${{ needs.build.outputs.version }}" ]] diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index b3a2765..bf519e0 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -5,19 +5,6 @@ on: branches: - main - release - paths: - - ".github/dependabot.yml" - - ".github/workflows/**" - - "pyproject.toml" - - "uv.lock" - - "src/**/*.txt" - - "utils/build-requirements.txt" - - "desktop/package.json" - - "desktop/package-lock.json" - - "desktop/runtime-constraints.txt" - - "desktop/sidecars.json" - - "desktop/src-tauri/Cargo.toml" - - "desktop/src-tauri/Cargo.lock" concurrency: group: security-${{ github.event.pull_request.number || github.ref }} diff --git a/.gitignore b/.gitignore index 49668d6..1e94432 100644 --- a/.gitignore +++ b/.gitignore @@ -38,10 +38,11 @@ pnpm-debug.log* # compiled output /target /desktop/node_modules/ +/desktop/dist/ /desktop/src-tauri/target/ /desktop/src-tauri/gen/ /desktop/src-tauri/binaries/uv-* -/desktop/web/icon.png +/desktop/public/icon.png /desktop/src-tauri/icons/android/ /desktop/src-tauri/icons/ios/ /desktop/src-tauri/icons/64x64.png diff --git a/.release-please-manifest.json b/.release-please-manifest.json index da42fbd..96ce562 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,4 +1,3 @@ { - ".": "0.3.0", - "desktop": "0.3.0" + ".": "0.4.0-b.1" } diff --git a/.release-please-manifest.stable.json b/.release-please-manifest.stable.json index da42fbd..0ee8c01 100644 --- a/.release-please-manifest.stable.json +++ b/.release-please-manifest.stable.json @@ -1,4 +1,3 @@ { - ".": "0.3.0", - "desktop": "0.3.0" + ".": "0.3.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 273dfd2..4accd74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,34 @@ # CHANGELOG +## [0.4.0-b.1](https://github.com/grayhatdevelopers/vidxp/compare/v0.4.0-b...v0.4.0-b.1) (2026-08-03) + + +### Features + +* **skills:** add installable VidXP agent workflows for guided video ingestion, readiness checks, and evidence search ([62af88e](https://github.com/grayhatdevelopers/vidxp/commit/62af88e70e6dd1c2ac629fdaa7584d8679740ef0), [e321e29](https://github.com/grayhatdevelopers/vidxp/commit/e321e298f64d51dfbcc7276ee3e071d20d698f9b)) +* **desktop:** connect to an existing VidXP installation or manage an isolated local runtime ([9a96b3a](https://github.com/grayhatdevelopers/vidxp/commit/9a96b3ac4dd299fafa6c682a6794b627c16b2bf1)) +* **mcp:** upload or import videos, index them automatically, and track ingestion until they are searchable ([9a5a911](https://github.com/grayhatdevelopers/vidxp/commit/9a5a911bef79474e55152c62e9289023fcf10c5a)) +* **mcp:** return visual evidence boards with search results ([549e727](https://github.com/grayhatdevelopers/vidxp/commit/549e727a7132dbc46ade7d521f11947afeaac745)) + + +### Bug Fixes + +* **desktop:** prevent console windows during background operations ([42da9a5](https://github.com/grayhatdevelopers/vidxp/commit/42da9a563fcf79ae5b9b852e67a170bfb51a77e2)) +* **mcp:** make follow-up clip creation reliable and support up to 10 evidence items ([58a6db8](https://github.com/grayhatdevelopers/vidxp/commit/58a6db807480ed562bb2b44f62414ca78de568e5)) + +## [0.4.0-b](https://github.com/grayhatdevelopers/vidxp/compare/v0.3.0...v0.4.0-b) (2026-07-31) + + +### Features + +* **api:** add explicit local network sharing ([#39](https://github.com/grayhatdevelopers/vidxp/issues/39)) ([37f3a84](https://github.com/grayhatdevelopers/vidxp/commit/37f3a84f03dcfc9022d723bac91d970352c3c1e3)) + + +### Bug Fixes + +* **models:** harden preparation downloads ([62cb7b1](https://github.com/grayhatdevelopers/vidxp/commit/62cb7b1b2dbdfbc968435bb76101b3199a88c1f8)) +* **models:** harden preparation downloads ([69c5e51](https://github.com/grayhatdevelopers/vidxp/commit/69c5e51588c496699fe3a49b8c61a374f1058a98)) + ## [0.3.0](https://github.com/grayhatdevelopers/vidxp/compare/v0.2.0...v0.3.0) (2026-07-31) diff --git a/Dockerfile b/Dockerfile index 75c0d46..b27524f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -52,7 +52,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ENV PATH="/opt/vidxp/bin:${PATH}" \ PYTHONDONTWRITEBYTECODE=1 \ - PYTHONUNBUFFERED=1 + PYTHONUNBUFFERED=1 \ + VIDXP_HTTP_PORT=8000 USER vidxp WORKDIR /var/lib/vidxp diff --git a/INSTALLATION_GUIDE.md b/INSTALLATION_GUIDE.md index d8ddca4..9ffa4e9 100644 --- a/INSTALLATION_GUIDE.md +++ b/INSTALLATION_GUIDE.md @@ -11,7 +11,7 @@ shape needs. | Local agent integration | `vidxp[local-worker,mcp]` | Local worker and stdio MCP | | Native browser UI | `vidxp[local-worker,frontend]` | CLI, local worker, Streamlit | | Local application server | `vidxp[local-worker,server]` | Loopback HTTP API, remote MCP, local worker | -| Desktop app | Install the native package | Guided app-owned Python and worker runtime with an optional browser interface | +| Desktop app | Install the native package | Adopt a compatible local installation or create a private Desktop-managed runtime | | Browser UI in Docker | Published `vidxp` image | One CPU worker/UI container | | Public/self-hosted service | `compose.coolify.yaml` | API/MCP control plane, CPU worker, PostgreSQL, Chroma, tusd | | Embed one capability | `dialogue`, `scene`, or `actor` extra | Python indexing/retrieval code | @@ -25,14 +25,17 @@ Local model work requires a capability or worker extra. | Installation | Install first | Managed by VidXP | |---|---|---| | CLI or MCP | [uv 0.12+](https://docs.astral.sh/uv/getting-started/installation/) | Python and the isolated VidXP environment | -| Desktop | A supported OS and internet access for first setup | uv, Python, VidXP, and selected model files | +| Desktop-managed target | A supported OS, internet access for first setup, FFmpeg, ffprobe, `libx264`, and `aac` | uv, Python, VidXP, and selected model files | +| Desktop with existing target | A compatible local `vidxp` executable and that installation's own media-runtime setup | Target discovery and launch coordination only | | Docker | Docker Engine or Docker Desktop | Python, VidXP, and FFmpeg inside the image | Native CLI and desktop processing require FFmpeg, ffprobe, `libx264`, and `aac`. `vidxp init` checks them and offers the supported operating-system -package-manager command when something is missing. The desktop app performs -the same check through native confirmation dialogs. Docker already includes -FFmpeg. +package-manager command when something is missing. On Windows, Desktop can +show and run the WinGet command after consent when WinGet is available. On +macOS it can do the same with Homebrew; without Homebrew it provides Homebrew +or manual FFmpeg remediation. Linux displays the applicable APT, DNF, or +manual command without automating elevation. Docker already includes FFmpeg. Supported native systems are Windows x86-64, Linux x86-64, and Apple Silicon macOS 14 or newer. CPU is the supported runtime; GPU installation remains @@ -179,10 +182,19 @@ vidxp doctor --modalities dialogue,actor ### 5. Start the selected surface - CLI: `vidxp --help` -- Browser UI: `vidxp ui` -- Local HTTP API and remote MCP: `vidxp-api` +- Loopback browser UI: `vidxp ui` +- LAN-shared unauthenticated browser UI: `vidxp ui --share` +- Local HTTP API and MCP: `vidxp-api` +- LAN-shared authenticated HTTP API and MCP: `vidxp-api --share` - Local stdio MCP: `vidxp-mcp` +The browser UI binds to loopback unless `--share` is present. In share mode, +VidXP gives Streamlit an explicit wildcard bind and Streamlit prints both the +Local and Network URLs. The UI has no authentication, so share it only on a +trusted network. +VidXP suppresses Streamlit's first-run email prompt and disables Streamlit +usage-statistics collection for this managed launch. + ## First CLI index ```bash @@ -237,8 +249,20 @@ After installing `local-worker,mcp`: vidxp mcp-config ``` -The command prints a complete, import-ready `mcpServers` JSON object with the -resolved absolute `vidxp-mcp` executable and default repository argument. +The command prints `mcpServers` JSON for Claude Desktop and other clients that +use that local-stdio format, with the resolved absolute `vidxp-mcp` executable +and default repository argument. It is not a universal MCP configuration. + +Codex uses its own configuration. Either run: + +```bash +codex mcp add vidxp -- vidxp-mcp --repository default +``` + +or add an `[mcp_servers.vidxp]` entry to `~/.codex/config.toml`. The ChatGPT +desktop app and Codex share that local MCP configuration. ChatGPT web does not +read this file or the generated JSON; connect it to a deployed HTTPS `/mcp` +endpoint through a custom app/connector instead. ```bash vidxp-mcp --check --repository default @@ -263,37 +287,102 @@ Install `local-worker,server`, prepare models, then run: vidxp-api ``` +The default is reachable only from the same machine. To deliberately share it +on the machine's detected LAN address, run `vidxp-api --share`. Share mode: + +- generates and then reuses an app-owned bearer token; +- binds Uvicorn to the detected LAN address; +- configures the HTTP and MCP Host-header policies for that address; and +- prints the exact health URL, Streamable HTTP MCP URL, and bearer token. + +The managed token is stored as `api-share-token` in VidXP's platform-native +configuration directory. Share mode uses plain HTTP and is intended for a +trusted local network; use the supported reverse-proxy deployment when TLS is +required. + The unauthenticated local default is deliberately loopback-only: | Endpoint | Purpose | |---|---| -| `http://127.0.0.1:8000/docs` | Interactive OpenAPI | -| `http://127.0.0.1:8000/openapi.json` | Machine-readable contract | -| `http://127.0.0.1:8000/health` | Process liveness | -| `http://127.0.0.1:8000/ready` | Aggregate runtime readiness | -| `http://127.0.0.1:8000/mcp` | Streamable HTTP MCP | +| `http://127.0.0.1:32191/docs` | Interactive OpenAPI | +| `http://127.0.0.1:32191/openapi.json` | Machine-readable contract | +| `http://127.0.0.1:32191/health` | Process liveness | +| `http://127.0.0.1:32191/ready` | Aggregate runtime readiness | +| `http://127.0.0.1:32191/mcp` | Streamable HTTP MCP | + +Native installs default to port `32191` to avoid the heavily reused development +port `8000`. Use `vidxp-api --port ` when a specific port is required. + +The Streamable HTTP MCP endpoint includes `create_media_upload`. Its returned +capability link uses the actual listener host and port; opening `/` manually is +not an upload flow. Native mode serves the packaged Uppy page and receives bounded, +non-resumable multipart uploads directly in the API process. It requires no Docker, +PostgreSQL, Chroma server, tusd, or separately started helper. The session result +reports the effective per-file and aggregate limits, and `get_media_upload` follows +the durable import and automatic-indexing lifecycle through `indexed` and +`searchable=true`. + +`vidxp-api --share` is different: it binds a bearer-protected, plain-HTTP LAN +listener but cannot safely synthesize an advertised browser handoff origin. +Consequently its MCP surface omits `create_media_upload` and +`get_media_upload` unless an explicit HTTPS +`VIDXP_UPLOAD_HANDOFF_PUBLIC_URL` is configured. The command reports that +omission instead of exposing a tool that would fail when called. + +Local stdio exposes `ingest_local_media` instead. Pass one to ten paths that are +inside the configured import boundaries and poll `get_media_ingestion`; file bytes +do not cross MCP. Both ingestion tools default to the repository's advertised +capability set. Supply `modalities` to narrow it or +`index_after_import=false` for the advanced registration-only workflow. Do not bind an unauthenticated API to a non-loopback address. Public deployments require static bearer or OIDC authentication and should use the -supported server Compose topology. +supported server Compose topology. Hosted ChatGPT and Claude integrations +should use OIDC because those clients cannot be configured with VidXP's private +single-tenant static token. Set `VIDXP_HTTP_AUTH_MODE=oidc`, the issuer, +audience, JWKS URL, required scopes, and canonical HTTPS +`VIDXP_MCP_PUBLIC_URL`; VidXP publishes the MCP protected-resource metadata and +validates those access tokens. ## Desktop application Download the Windows, Apple Silicon macOS, or Linux package from [GitHub Releases](https://github.com/grayhatdevelopers/vidxp/releases). -On first launch, the application checks FFmpeg, provisions its own Python and -VidXP runtime, lets you choose capabilities and model storage, and optionally -downloads the selected models. Python and uv do not need to be installed -separately. - -Capability code is selected independently from the optional browser interface. -After configuration, the Tauri supervisor stays in the system tray. Closing -the window hides it; **Quit VidXP** from the tray shuts down the interface and -worker. - -The NSIS, DMG, and AppImage packages do not bundle FFmpeg. The application uses -a native confirmation dialog before running a supported package manager. +Desktop opens its control panel first and asks which local target to use. It +does not install anything before that choice: + +- **Use an existing installation** discovers compatible `vidxp` executables or + lets you browse to one. Desktop validates the versioned probe and launch + contracts, but the installation stays externally owned. Desktop never + installs, repairs, updates, removes, or broadly stops it. If its browser + surface is missing, enable the `frontend` extra with that installation's own + package-management workflow before Desktop can open it. +- **Set up VidXP for me** creates a private Python and VidXP runtime owned by + Desktop. Python and uv do not need to be installed separately. Capability + code, the optional browser interface, model storage, and initial model + preparation are selected before applying the draft. + +A managed setup or update remains a draft until its candidate runtime passes +the Desktop probe and launch contracts. Activation then replaces the previous +managed target atomically; failed or cancelled work leaves the previous target +authoritative. For an unchanged ready runtime, **Prepare / verify models** +checks cached files and downloads only missing selected model material without +requiring a configuration change. + +Starting Desktop, or starting it a second time, shows and focuses the control +panel without opening a browser. **Open VidXP** explicitly starts or reuses the +loopback browser service and opens one tab. Closing a configured window hides +it to the tray. Tray actions are **Manage VidXP**, **Open VidXP**, and **Quit +VidXP**. Quit stops the exact browser service Desktop launched; broad worker +shutdown is limited to a Desktop-owned runtime. + +The NSIS, DMG, and AppImage packages do not bundle FFmpeg. Managed setup can +run WinGet on Windows or Homebrew on macOS only after native confirmation and +only when that package manager is available. Without Homebrew, macOS shows +installation remediation instead. Linux displays an APT, DNF, or manual +command and does not automate elevation. An adopted installation keeps +responsibility for its own FFmpeg setup. Windows SmartScreen and macOS Gatekeeper may require explicit confirmation until signing is added. See [Desktop application](docs/desktop.md) for runtime, storage, and build details. diff --git a/MANIFEST.in b/MANIFEST.in index 383bfce..cdda21d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,16 @@ include README.md include LICENSE include docs/images/logo.png +recursive-include src/vidxp/assets/upload_page * +recursive-include src/vidxp/assets/artifact_download * +include web/upload-page/package.json +include web/upload-page/package-lock.json +include web/upload-page/scripts/build.mjs +include web/upload-page/src/app.js +include web/upload-page/src/app.css +include web/upload-page/src/index.html +include web/upload-page/src/recovery.js +prune web/upload-page/node_modules global-exclude *.whl global-exclude *.pyc global-exclude __pycache__ diff --git a/README.md b/README.md index fff63e4..e8399e6 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@

- + Download VidXP desktop app

@@ -78,6 +78,14 @@ vidxp doctor vidxp mcp-config ``` +`vidxp mcp-config` emits the `mcpServers` JSON used by Claude Desktop and +compatible local stdio clients. Codex has separate configuration: use +`codex mcp add vidxp -- vidxp-mcp --repository default` or configure +`[mcp_servers.vidxp]` in `~/.codex/config.toml`. ChatGPT Desktop and ChatGPT web +use ChatGPT's own connector configuration and do not read Codex's config; hosted +ChatGPT connections use a remote MCP endpoint, with VidXP deployed behind HTTPS +and OIDC. + The CLI works without MCP. Add the browser app with: ```bash @@ -86,6 +94,16 @@ uv tool install --python 3.14 --torch-backend cpu \ vidxp ui ``` +`vidxp ui` binds to loopback by default. Use `vidxp ui --share` only when you +intend to expose the unauthenticated browser interface on the local network. +Streamlit prints its Local and Network URLs when it starts. VidXP disables +Streamlit's first-run email prompt and usage-statistics collection. + +`vidxp-api --share` exposes a bearer-protected HTTP API/MCP endpoint on a +trusted LAN. Browser upload tools are omitted unless an explicit HTTPS upload +handoff origin is configured, because a LAN listener alone cannot advertise a +safe browser capability page. + If the `vidxp` command is not found, run `uv tool update-shell` once and reopen the terminal. @@ -94,13 +112,16 @@ the terminal. Download the installer for Windows, Apple Silicon macOS, or Linux from [GitHub Releases](https://github.com/grayhatdevelopers/vidxp/releases). -The desktop installer manages Python, VidXP, and the local worker for you. On -first launch, choose the search capabilities you want, where model files should -live, and whether to download them immediately. Python and uv do not need to be +On first launch, choose whether to adopt an existing compatible VidXP +installation without downloading another runtime, or create a private runtime +managed by VidXP Desktop. For a managed runtime, choose the search capabilities, +model location, and optional browser interface; Python and uv do not need to be installed separately. -After setup, VidXP can stay available from the system tray. The browser -interface is optional and can be left out of the installed VidXP runtime. +Desktop opens its control panel when started. Browser launch is a separate, +explicit **Open VidXP** action. After configuration, closing the control panel +keeps VidXP available through **Manage VidXP**, **Open VidXP**, and **Quit +VidXP** in the system tray. ### 3. Docker for a server @@ -126,6 +147,10 @@ See the [Coolify guide](docs/deployment/coolify.md) for the complete setup. - Group recurring faces in a video and render a highlighted actor overlay. - Search one selected video or every video in the active library. - Open matching timestamps and export downloadable clips and overlays. +- Receive search and query results as annotated evidence boards, then open the + exact frames or clips worth inspecting. +- Retrieve completed clips through native MCP resources, local stdio paths, or + short-lived resumable HTTPS downloads without embedding video bytes in tool JSON. - Keep personal, client, or project libraries separate. - Follow long indexing jobs, cancel them, and keep the last working index if a later run fails. @@ -166,6 +191,38 @@ scenes, ask questions about a library, and create clips or actor overlays. Local agents can connect over stdio; remote agents can connect to a self-hosted VidXP server. +Search and question results can include directly inspectable frames and clips, so +agents can show the evidence behind an answer without making users translate raw +timestamps. Evidence rendering is best-effort: a result can still be useful when +an individual frame or clip cannot be produced. Agents can request additional +ranked evidence in small batches without rerunning the search. +For broader result sets, an agent can first show bounded evidence-board pages +with a tile-to-evidence map, then fetch exact frames or clips only for the +selected tiles. + +Remote agents can hand users a short-lived page for selecting and uploading +multiple videos. Local agents can ingest approved filesystem paths without moving +video bytes through MCP. VidXP normally indexes successful imports automatically; +registration-only ingestion stops at `registered`, and indexing failures can be +retried without uploading the video again. + +Agents can call `get_workspace` before acting to inspect registered media, +active-index coverage, model readiness, and the searchable, queryable, +inspectable, or renderable roles available for each video. Invalid capability +or media selections are rejected before a durable job is queued and include an +actionable next step. + +### ChatGPT and Codex skills + +VidXP includes reusable skill source folders for the two common agent workflows: + +- [Ingest and index videos](skills/vidxp-ingest-video/SKILL.md) +- [Find moments and return inspectable evidence](skills/vidxp-find-video-evidence/SKILL.md) + +Download a skill folder and add it through a supported ChatGPT desktop or Codex +Skills surface. The skills require a connected VidXP MCP server; installable +plugin packaging for additional ChatGPT surfaces will follow separately. + - [Python, HTTP, and MCP installation](INSTALLATION_GUIDE.md) - [Optional capability packages](INSTALLATION_GUIDE.md#optional-dependency-extras) - [Coolify server setup](docs/deployment/coolify.md) @@ -228,6 +285,13 @@ Contributions are welcome. Read the ## Credits Built by Grayhat Developers PVT Ltd. and maintained by the community. +Originally researched by students: +- [Abdullah Mansoor](https://github.com/abdullahmansoor321) +- [Muhammad Haroon](https://github.com/haroon10725) +- [Sarah Jawaid](https://github.com/sarr266) +- [Talha Ahmed](https://github.com/talhaahmed1234) + +Working with [Dr Shahab Tahzeeb](https://scholar.google.com/citations?user=cryeRB0AAAAJ&hl=en) ([NED University of Engineering and Technology](https://www.neduet.edu.pk/)) and [Saad Bazaz](https://scholar.google.com/citations?user=mrJo09oAAAAJ&hl=en) ([Grayhat](https://grayhat.studio)). Email: info@grayhat.studio diff --git a/compose.coolify.yaml b/compose.coolify.yaml index cd6d601..5066573 100644 --- a/compose.coolify.yaml +++ b/compose.coolify.yaml @@ -5,16 +5,31 @@ x-vidxp-environment: &vidxp-environment VIDXP_MODEL_CACHE: /var/lib/vidxp/models PGPASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD} VIDXP_HTTP_BIND_HOST: 0.0.0.0 - VIDXP_HTTP_AUTH_MODE: static - VIDXP_HTTP_STATIC_BEARER_TOKEN: ${VIDXP_HTTP_STATIC_BEARER_TOKEN:?Set a bearer token of at least 32 characters} + VIDXP_HTTP_AUTH_MODE: ${VIDXP_HTTP_AUTH_MODE:-static} + VIDXP_HTTP_STATIC_BEARER_TOKEN: ${VIDXP_HTTP_STATIC_BEARER_TOKEN:-} + VIDXP_HTTP_OIDC_ISSUER: ${VIDXP_HTTP_OIDC_ISSUER:-} + VIDXP_HTTP_OIDC_AUDIENCE: ${VIDXP_HTTP_OIDC_AUDIENCE:-} + VIDXP_HTTP_OIDC_JWKS_URL: ${VIDXP_HTTP_OIDC_JWKS_URL:-} + VIDXP_HTTP_REQUIRED_SCOPES: ${VIDXP_HTTP_REQUIRED_SCOPES:-[]} + VIDXP_MCP_PUBLIC_URL: ${VIDXP_MCP_PUBLIC_URL:-} + VIDXP_MCP_MAX_RESOURCE_BYTES: ${VIDXP_MCP_MAX_RESOURCE_BYTES:-16777216} VIDXP_HTTP_TRUSTED_HOSTS: '["127.0.0.1","localhost","${VIDXP_PUBLIC_API_HOST:?Set the public API host}"]' VIDXP_MCP_ALLOWED_HOSTS: '["127.0.0.1:*","localhost:*","${VIDXP_PUBLIC_API_HOST:?Set the public API host}"]' + VIDXP_ARTIFACT_DOWNLOAD_PUBLIC_URL: https://${VIDXP_PUBLIC_API_HOST:?Set the public API host}/artifact-download + VIDXP_ARTIFACT_DOWNLOAD_SECRET: ${VIDXP_ARTIFACT_DOWNLOAD_SECRET:?Set a dedicated artifact-download secret of at least 32 characters} + VIDXP_ARTIFACT_DOWNLOAD_TTL_SECONDS: ${VIDXP_ARTIFACT_DOWNLOAD_TTL_SECONDS:-900} VIDXP_UPLOAD_PUBLIC_ENDPOINT: ${VIDXP_UPLOAD_PUBLIC_ENDPOINT:?Set the public tusd endpoint ending in /uploads/} VIDXP_UPLOAD_INTERNAL_ENDPOINT: http://tusd:8080/uploads/ VIDXP_UPLOAD_CLEANUP_TOKEN: ${VIDXP_UPLOAD_CLEANUP_TOKEN:?Set a cleanup token of at least 32 characters} + VIDXP_UPLOAD_HANDOFF_PUBLIC_URL: ${VIDXP_UPLOAD_HANDOFF_PUBLIC_URL:?Set the HTTPS VidXP URL ending in /upload-handoff} + VIDXP_UPLOAD_HANDOFF_SECRET: ${VIDXP_UPLOAD_HANDOFF_SECRET:?Set a dedicated handoff secret of at least 32 characters} + VIDXP_UPLOAD_CORS_ORIGIN_REGEX: ${VIDXP_UPLOAD_CORS_ORIGIN_REGEX:?Set a grouped exact-origin policy that permits the handoff origin} VIDXP_UPLOAD_QUARANTINE_ROOT: /var/lib/vidxp/uploads VIDXP_UPLOAD_MAX_BYTES: ${VIDXP_UPLOAD_MAX_BYTES:-53687091200} VIDXP_UPLOAD_QUOTA_BYTES: ${VIDXP_UPLOAD_QUOTA_BYTES:-107374182400} + VIDXP_UPLOAD_SESSION_MAX_FILES: ${VIDXP_UPLOAD_SESSION_MAX_FILES:-10} + VIDXP_UPLOAD_SESSION_MAX_BYTES: ${VIDXP_UPLOAD_SESSION_MAX_BYTES:-107374182400} + VIDXP_UPLOAD_SESSION_TTL_SECONDS: ${VIDXP_UPLOAD_SESSION_TTL_SECONDS:-86400} services: postgres: @@ -178,8 +193,9 @@ services: - -hooks-http-size-limit=5120 - -hooks-http-retry=3 - -hooks-http-backoff=1s - - -cors-allow-origin=${VIDXP_UPLOAD_CORS_ORIGIN_REGEX:?Set an anchored browser-origin regex} + - -cors-allow-origin=${VIDXP_UPLOAD_CORS_ORIGIN_REGEX:?Set a grouped exact-origin browser policy} - -cors-allow-headers=Authorization + - -cors-expose-headers=X-VidXP-Error - -cors-max-age=600 - -network-timeout=60s - -shutdown-timeout=30s diff --git a/desktop/THIRD_PARTY_NOTICES.txt b/desktop/THIRD_PARTY_NOTICES.txt new file mode 100644 index 0000000..de97bba --- /dev/null +++ b/desktop/THIRD_PARTY_NOTICES.txt @@ -0,0 +1,11542 @@ +VidXP Desktop Legal Notices +=========================== + +This artifact is generated from locked production dependency graphs and bundled sidecar metadata. + +VIDXP PROJECT LICENSE +===================== +VidXP Desktop and VidXP | MIT | https://github.com/grayhatdevelopers/vidxp + +MIT License + +Copyright (c) 2026 Grayhat Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +BUNDLED EXECUTABLES +=================== +uv 0.12.0 | MIT OR Apache-2.0 | https://github.com/astral-sh/uv/tree/0.12.0 +The complete MIT terms from the pinned uv release follow. The complete Apache-2.0 terms are included in the Rust dependency section below. + +MIT License + +Copyright (c) 2025 Astral Software Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +RUST DEPENDENCIES +================= +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- num_threads 0.1.7 | https://github.com/jhpratt/num_threads | registry+https://github.com/rust-lang/crates.io-index + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Jacob Pratt + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- powerfmt 0.2.0 | https://github.com/jhpratt/powerfmt | registry+https://github.com/rust-lang/crates.io-index + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 Jacob Pratt et al. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- deranged 0.5.8 | https://github.com/jhpratt/deranged | registry+https://github.com/rust-lang/crates.io-index + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2024 Jacob Pratt et al. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- embed_plist 1.2.2 | https://github.com/nvzqz/embed-plist-rs | registry+https://github.com/rust-lang/crates.io-index +- encoding_rs 0.8.35 | https://github.com/hsivonen/encoding_rs | registry+https://github.com/rust-lang/crates.io-index +- utf8_iter 1.0.4 | https://github.com/hsivonen/utf8_iter | registry+https://github.com/rust-lang/crates.io-index + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- windows-collections 0.2.0 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-collections 0.3.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-core 0.61.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-core 0.62.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-future 0.2.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-future 0.3.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-implement 0.60.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-interface 0.59.3 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-link 0.1.3 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-link 0.2.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-numerics 0.2.0 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-numerics 0.3.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-result 0.3.4 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-result 0.4.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-strings 0.4.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-strings 0.5.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-sys 0.45.0 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-sys 0.59.0 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-sys 0.60.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-sys 0.61.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-targets 0.42.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-targets 0.52.6 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-targets 0.53.5 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-threading 0.1.0 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-threading 0.2.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows-version 0.1.7 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows 0.61.3 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows 0.62.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_aarch64_gnullvm 0.42.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_aarch64_gnullvm 0.52.6 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_aarch64_gnullvm 0.53.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_aarch64_msvc 0.42.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_aarch64_msvc 0.52.6 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_aarch64_msvc 0.53.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_i686_gnu 0.42.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_i686_gnu 0.52.6 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_i686_gnu 0.53.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_i686_gnullvm 0.52.6 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_i686_gnullvm 0.53.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_i686_msvc 0.42.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_i686_msvc 0.52.6 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_i686_msvc 0.53.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_x86_64_gnu 0.42.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_x86_64_gnu 0.52.6 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_x86_64_gnu 0.53.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_x86_64_gnullvm 0.42.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_x86_64_gnullvm 0.52.6 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_x86_64_gnullvm 0.53.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_x86_64_msvc 0.42.2 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_x86_64_msvc 0.52.6 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index +- windows_x86_64_msvc 0.53.1 | https://github.com/microsoft/windows-rs | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) Microsoft Corporation. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- zerocopy 0.8.55 | https://github.com/google/zerocopy | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 The Fuchsia Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- serialize-to-javascript-impl 0.1.2 | https://github.com/chippers/serialize-to-javascript | registry+https://github.com/rust-lang/crates.io-index +- serialize-to-javascript 0.1.2 | https://github.com/chippers/serialize-to-javascript | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- ipnet 2.12.0 | https://github.com/krisprice/ipnet | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Juniper Networks, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- swift-rs 1.0.7 | https://github.com/Brendonovich/swift-rs | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 The swift-rs developers + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- json-patch 3.0.1 | https://github.com/idubrov/json-patch | registry+https://github.com/rust-lang/crates.io-index +- winapi 0.3.9 | https://github.com/retep998/winapi-rs | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- crc32fast 1.5.0 | https://github.com/srijs/rust-crc32fast | registry+https://github.com/rust-lang/crates.io-index +- env_filter 0.1.4 | https://github.com/rust-cli/env_logger | registry+https://github.com/rust-lang/crates.io-index +- foreign-types-macros 0.2.4 | https://github.com/sfackler/foreign-types | registry+https://github.com/rust-lang/crates.io-index +- foreign-types-shared 0.3.1 | https://github.com/sfackler/foreign-types | registry+https://github.com/rust-lang/crates.io-index +- foreign-types 0.5.0 | https://github.com/sfackler/foreign-types | registry+https://github.com/rust-lang/crates.io-index +- hex 0.4.3 | https://github.com/KokaKiwi/rust-hex | registry+https://github.com/rust-lang/crates.io-index +- jni-sys 0.3.1 | https://github.com/jni-rs/jni-sys | registry+https://github.com/rust-lang/crates.io-index +- jni-sys 0.4.1 | https://github.com/jni-rs/jni-sys | registry+https://github.com/rust-lang/crates.io-index +- serde_spanned 1.1.1 | https://github.com/toml-rs/toml | registry+https://github.com/rust-lang/crates.io-index +- toml 1.1.4+spec-1.1.0 | https://github.com/toml-rs/toml | registry+https://github.com/rust-lang/crates.io-index +- toml_datetime 1.1.1+spec-1.1.0 | https://github.com/toml-rs/toml | registry+https://github.com/rust-lang/crates.io-index +- toml_edit 0.19.15 | https://github.com/toml-rs/toml | registry+https://github.com/rust-lang/crates.io-index +- toml_edit 0.20.2 | https://github.com/toml-rs/toml | registry+https://github.com/rust-lang/crates.io-index +- toml_edit 0.25.13+spec-1.1.0 | https://github.com/toml-rs/toml | registry+https://github.com/rust-lang/crates.io-index +- toml_parser 1.1.3+spec-1.1.0 | https://github.com/toml-rs/toml | registry+https://github.com/rust-lang/crates.io-index +- toml_writer 1.1.2+spec-1.1.0 | https://github.com/toml-rs/toml | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- async-broadcast 0.7.2 | https://github.com/smol-rs/async-broadcast | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2020 Yoshua Wuyts + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- jsonptr 0.6.3 | https://github.com/chanced/jsonptr | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2024 Chance Dinkins + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- futures-channel 0.3.33 | https://github.com/rust-lang/futures-rs | registry+https://github.com/rust-lang/crates.io-index +- futures-core 0.3.33 | https://github.com/rust-lang/futures-rs | registry+https://github.com/rust-lang/crates.io-index +- futures-executor 0.3.33 | https://github.com/rust-lang/futures-rs | registry+https://github.com/rust-lang/crates.io-index +- futures-io 0.3.33 | https://github.com/rust-lang/futures-rs | registry+https://github.com/rust-lang/crates.io-index +- futures-macro 0.3.33 | https://github.com/rust-lang/futures-rs | registry+https://github.com/rust-lang/crates.io-index +- futures-sink 0.3.33 | https://github.com/rust-lang/futures-rs | registry+https://github.com/rust-lang/crates.io-index +- futures-task 0.3.33 | https://github.com/rust-lang/futures-rs | registry+https://github.com/rust-lang/crates.io-index +- futures-util 0.3.33 | https://github.com/rust-lang/futures-rs | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright (c) 2016 Alex Crichton +Copyright (c) 2017 The Tokio Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- typenum 1.20.1 | https://github.com/paholg/typenum | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2014 Paho Lurie-Gregg + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- reqwest 0.13.4 | https://github.com/seanmonstar/reqwest | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2016 Sean McArthur + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- cookie 0.18.1 | https://github.com/SergioBenitez/cookie-rs | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2017 Sergio Benitez +Copyright 2014 Alex Chricton + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- http 1.4.2 | https://github.com/hyperium/http | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2017 http-rs authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- ppv-lite86 0.2.21 | https://github.com/cryptocorrosion/cryptocorrosion | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2019 The CryptoCorrosion Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- proc-macro-error-attr 1.0.4 | https://gitlab.com/CreepySkeleton/proc-macro-error | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2019-2020 CreepySkeleton + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- async-recursion 1.1.1 | https://github.com/dcchut/async-recursion | registry+https://github.com/rust-lang/crates.io-index +- keyboard-types 0.7.0 | https://github.com/pyfisch/keyboard-types | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- async-channel 2.5.0 | https://github.com/smol-rs/async-channel | registry+https://github.com/rust-lang/crates.io-index +- async-executor 1.14.0 | https://github.com/smol-rs/async-executor | registry+https://github.com/rust-lang/crates.io-index +- async-io 2.6.0 | https://github.com/smol-rs/async-io | registry+https://github.com/rust-lang/crates.io-index +- async-lock 3.4.2 | https://github.com/smol-rs/async-lock | registry+https://github.com/rust-lang/crates.io-index +- async-process 2.5.0 | https://github.com/smol-rs/async-process | registry+https://github.com/rust-lang/crates.io-index +- async-signal 0.2.14 | https://github.com/smol-rs/async-signal | registry+https://github.com/rust-lang/crates.io-index +- async-task 4.7.1 | https://github.com/smol-rs/async-task | registry+https://github.com/rust-lang/crates.io-index +- atomic-waker 1.1.2 | https://github.com/smol-rs/atomic-waker | registry+https://github.com/rust-lang/crates.io-index +- base64 0.21.7 | https://github.com/marshallpierce/rust-base64 | registry+https://github.com/rust-lang/crates.io-index +- base64 0.22.1 | https://github.com/marshallpierce/rust-base64 | registry+https://github.com/rust-lang/crates.io-index +- bitflags 1.3.2 | https://github.com/bitflags/bitflags | registry+https://github.com/rust-lang/crates.io-index +- bitflags 2.13.1 | https://github.com/bitflags/bitflags | registry+https://github.com/rust-lang/crates.io-index +- blocking 1.6.2 | https://github.com/smol-rs/blocking | registry+https://github.com/rust-lang/crates.io-index +- bumpalo 3.20.3 | https://github.com/fitzgen/bumpalo | registry+https://github.com/rust-lang/crates.io-index +- camino 1.2.5 | https://github.com/camino-rs/camino | registry+https://github.com/rust-lang/crates.io-index +- cfg-if 1.0.4 | https://github.com/rust-lang/cfg-if | registry+https://github.com/rust-lang/crates.io-index +- concurrent-queue 2.5.0 | https://github.com/smol-rs/concurrent-queue | registry+https://github.com/rust-lang/crates.io-index +- core-foundation-sys 0.8.7 | https://github.com/servo/core-foundation-rs | registry+https://github.com/rust-lang/crates.io-index +- core-foundation 0.10.1 | https://github.com/servo/core-foundation-rs | registry+https://github.com/rust-lang/crates.io-index +- core-graphics-types 0.2.0 | https://github.com/servo/core-foundation-rs | registry+https://github.com/rust-lang/crates.io-index +- core-graphics 0.25.0 | https://github.com/servo/core-foundation-rs | registry+https://github.com/rust-lang/crates.io-index +- crossbeam-channel 0.5.16 | https://github.com/crossbeam-rs/crossbeam | registry+https://github.com/rust-lang/crates.io-index +- crossbeam-utils 0.8.22 | https://github.com/crossbeam-rs/crossbeam | registry+https://github.com/rust-lang/crates.io-index +- displaydoc 0.2.7 | https://github.com/yaahc/displaydoc | registry+https://github.com/rust-lang/crates.io-index +- equivalent 1.0.2 | https://github.com/indexmap-rs/equivalent | registry+https://github.com/rust-lang/crates.io-index +- errno 0.3.14 | https://github.com/lambda-fairy/rust-errno | registry+https://github.com/rust-lang/crates.io-index +- event-listener-strategy 0.5.4 | https://github.com/smol-rs/event-listener-strategy | registry+https://github.com/rust-lang/crates.io-index +- event-listener 5.4.2 | https://github.com/smol-rs/event-listener | registry+https://github.com/rust-lang/crates.io-index +- fastrand 2.5.0 | https://github.com/smol-rs/fastrand | registry+https://github.com/rust-lang/crates.io-index +- flate2 1.1.9 | https://github.com/rust-lang/flate2-rs | registry+https://github.com/rust-lang/crates.io-index +- fnv 1.0.7 | https://github.com/servo/rust-fnv | registry+https://github.com/rust-lang/crates.io-index +- form_urlencoded 1.2.2 | https://github.com/servo/rust-url | registry+https://github.com/rust-lang/crates.io-index +- futures-lite 2.6.1 | https://github.com/smol-rs/futures-lite | registry+https://github.com/rust-lang/crates.io-index +- glob 0.3.4 | https://github.com/rust-lang/glob | registry+https://github.com/rust-lang/crates.io-index +- hashbrown 0.17.1 | https://github.com/rust-lang/hashbrown | registry+https://github.com/rust-lang/crates.io-index +- heck 0.4.1 | https://github.com/withoutboats/heck | registry+https://github.com/rust-lang/crates.io-index +- heck 0.5.0 | https://github.com/withoutboats/heck | registry+https://github.com/rust-lang/crates.io-index +- hermit-abi 0.5.2 | https://github.com/hermit-os/hermit-rs | registry+https://github.com/rust-lang/crates.io-index +- html5ever 0.38.0 | https://github.com/servo/html5ever | registry+https://github.com/rust-lang/crates.io-index +- httparse 1.10.1 | https://github.com/seanmonstar/httparse | registry+https://github.com/rust-lang/crates.io-index +- idna 1.1.0 | https://github.com/servo/rust-url/ | registry+https://github.com/rust-lang/crates.io-index +- idna_adapter 1.2.1 | https://github.com/hsivonen/idna_adapter | registry+https://github.com/rust-lang/crates.io-index +- indexmap 2.14.0 | https://github.com/indexmap-rs/indexmap | registry+https://github.com/rust-lang/crates.io-index +- jni 0.21.1 | https://github.com/jni-rs/jni-rs | registry+https://github.com/rust-lang/crates.io-index +- js-sys 0.3.103 | https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/js-sys | registry+https://github.com/rust-lang/crates.io-index +- libappindicator 0.9.0 | | registry+https://github.com/rust-lang/crates.io-index +- linux-raw-sys 0.12.1 | https://github.com/sunfishcode/linux-raw-sys | registry+https://github.com/rust-lang/crates.io-index +- lock_api 0.4.14 | https://github.com/Amanieu/parking_lot | registry+https://github.com/rust-lang/crates.io-index +- log 0.4.33 | https://github.com/rust-lang/log | registry+https://github.com/rust-lang/crates.io-index +- markup5ever 0.38.0 | https://github.com/servo/html5ever | registry+https://github.com/rust-lang/crates.io-index +- mime 0.3.17 | https://github.com/hyperium/mime | registry+https://github.com/rust-lang/crates.io-index +- muda 0.19.3 | https://github.com/tauri-apps/muda | registry+https://github.com/rust-lang/crates.io-index +- once_cell 1.21.4 | https://github.com/matklad/once_cell | registry+https://github.com/rust-lang/crates.io-index +- ordered-stream 0.2.0 | https://github.com/danieldg/ordered-stream | registry+https://github.com/rust-lang/crates.io-index +- parking 2.2.1 | https://github.com/smol-rs/parking | registry+https://github.com/rust-lang/crates.io-index +- parking_lot 0.12.5 | https://github.com/Amanieu/parking_lot | registry+https://github.com/rust-lang/crates.io-index +- parking_lot_core 0.9.12 | https://github.com/Amanieu/parking_lot | registry+https://github.com/rust-lang/crates.io-index +- percent-encoding 2.3.2 | https://github.com/servo/rust-url/ | registry+https://github.com/rust-lang/crates.io-index +- piper 0.2.5 | https://github.com/smol-rs/piper | registry+https://github.com/rust-lang/crates.io-index +- png 0.17.16 | https://github.com/image-rs/image-png | registry+https://github.com/rust-lang/crates.io-index +- png 0.18.1 | https://github.com/image-rs/image-png | registry+https://github.com/rust-lang/crates.io-index +- polling 3.11.0 | https://github.com/smol-rs/polling | registry+https://github.com/rust-lang/crates.io-index +- regex-automata 0.4.16 | https://github.com/rust-lang/regex | registry+https://github.com/rust-lang/crates.io-index +- regex-syntax 0.8.11 | https://github.com/rust-lang/regex | registry+https://github.com/rust-lang/crates.io-index +- regex 1.13.1 | https://github.com/rust-lang/regex | registry+https://github.com/rust-lang/crates.io-index +- rustix 1.1.4 | https://github.com/bytecodealliance/rustix | registry+https://github.com/rust-lang/crates.io-index +- scopeguard 1.2.0 | https://github.com/bluss/scopeguard | registry+https://github.com/rust-lang/crates.io-index +- serde_with 3.21.0 | https://github.com/jonasbb/serde_with/ | registry+https://github.com/rust-lang/crates.io-index +- serde_with_macros 3.21.0 | https://github.com/jonasbb/serde_with/ | registry+https://github.com/rust-lang/crates.io-index +- servo_arc 0.4.3 | https://github.com/servo/stylo | registry+https://github.com/rust-lang/crates.io-index +- signal-hook-registry 1.4.8 | https://github.com/vorner/signal-hook | registry+https://github.com/rust-lang/crates.io-index +- signal-hook 0.3.18 | https://github.com/vorner/signal-hook | registry+https://github.com/rust-lang/crates.io-index +- smallvec 1.15.2 | https://github.com/servo/rust-smallvec | registry+https://github.com/rust-lang/crates.io-index +- socket2 0.6.5 | https://github.com/rust-lang/socket2 | registry+https://github.com/rust-lang/crates.io-index +- stable_deref_trait 1.2.1 | https://github.com/storyyeller/stable_deref_trait | registry+https://github.com/rust-lang/crates.io-index +- string_cache 0.9.0 | https://github.com/servo/string-cache | registry+https://github.com/rust-lang/crates.io-index +- syn 1.0.109 | https://github.com/dtolnay/syn | registry+https://github.com/rust-lang/crates.io-index +- tao-macros 0.1.4 | https://github.com/tauri-apps/tao | registry+https://github.com/rust-lang/crates.io-index +- tempfile 3.27.0 | https://github.com/Stebalien/tempfile | registry+https://github.com/rust-lang/crates.io-index +- tendril 0.5.1 | https://github.com/servo/html5ever | registry+https://github.com/rust-lang/crates.io-index +- toml_datetime 0.6.3 | https://github.com/toml-rs/toml | registry+https://github.com/rust-lang/crates.io-index +- tray-icon 0.24.2 | https://github.com/tauri-apps/tray-icon | registry+https://github.com/rust-lang/crates.io-index +- unicode-segmentation 1.13.3 | https://github.com/unicode-rs/unicode-segmentation | registry+https://github.com/rust-lang/crates.io-index +- url 2.5.8 | https://github.com/servo/rust-url | registry+https://github.com/rust-lang/crates.io-index +- uuid 1.24.0 | https://github.com/uuid-rs/uuid | registry+https://github.com/rust-lang/crates.io-index +- wasi 0.11.1+wasi-snapshot-preview1 | https://github.com/bytecodealliance/wasi | registry+https://github.com/rust-lang/crates.io-index +- wasm-bindgen-futures 0.4.76 | https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/futures | registry+https://github.com/rust-lang/crates.io-index +- wasm-bindgen-macro-support 0.2.126 | https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro-support | registry+https://github.com/rust-lang/crates.io-index +- wasm-bindgen-macro 0.2.126 | https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro | registry+https://github.com/rust-lang/crates.io-index +- wasm-bindgen-shared 0.2.126 | https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/shared | registry+https://github.com/rust-lang/crates.io-index +- wasm-bindgen 0.2.126 | https://github.com/wasm-bindgen/wasm-bindgen | registry+https://github.com/rust-lang/crates.io-index +- web-sys 0.3.103 | https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/web-sys | registry+https://github.com/rust-lang/crates.io-index +- web_atoms 0.2.5 | https://github.com/servo/html5ever | registry+https://github.com/rust-lang/crates.io-index +- window-vibrancy 0.6.0 | https://github.com/tauri-apps/tauri-plugin-vibrancy | registry+https://github.com/rust-lang/crates.io-index +- wit-bindgen 0.46.0 | https://github.com/bytecodealliance/wit-bindgen | registry+https://github.com/rust-lang/crates.io-index +- wry 0.55.1 | https://github.com/tauri-apps/wry | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- bit-set 0.8.0 | https://github.com/contain-rs/bit-set | registry+https://github.com/rust-lang/crates.io-index +- bit-vec 0.8.0 | https://github.com/contain-rs/bit-vec | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- block-buffer 0.10.4 | https://github.com/RustCrypto/utils | registry+https://github.com/rust-lang/crates.io-index +- block-buffer 0.12.1 | https://github.com/RustCrypto/utils | registry+https://github.com/rust-lang/crates.io-index +- const-oid 0.10.2 | https://github.com/RustCrypto/formats | registry+https://github.com/rust-lang/crates.io-index +- cpufeatures 0.2.17 | https://github.com/RustCrypto/utils | registry+https://github.com/rust-lang/crates.io-index +- cpufeatures 0.3.0 | https://github.com/RustCrypto/utils | registry+https://github.com/rust-lang/crates.io-index +- crypto-common 0.1.7 | https://github.com/RustCrypto/traits | registry+https://github.com/rust-lang/crates.io-index +- crypto-common 0.2.2 | https://github.com/RustCrypto/traits | registry+https://github.com/rust-lang/crates.io-index +- digest 0.10.7 | https://github.com/RustCrypto/traits | registry+https://github.com/rust-lang/crates.io-index +- digest 0.11.3 | https://github.com/RustCrypto/traits | registry+https://github.com/rust-lang/crates.io-index +- hybrid-array 0.4.13 | https://github.com/RustCrypto/hybrid-array | registry+https://github.com/rust-lang/crates.io-index +- sha2 0.10.9 | https://github.com/RustCrypto/hashes | registry+https://github.com/rust-lang/crates.io-index +- sha2 0.11.0 | https://github.com/RustCrypto/hashes | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- rand_core 0.9.5 | https://github.com/rust-random/rand | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- getrandom 0.2.17 | https://github.com/rust-random/getrandom | registry+https://github.com/rust-lang/crates.io-index +- getrandom 0.3.4 | https://github.com/rust-random/getrandom | registry+https://github.com/rust-lang/crates.io-index +- getrandom 0.4.3 | https://github.com/rust-random/getrandom | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- adler2 2.0.1 | https://github.com/oyvindln/adler2 | registry+https://github.com/rust-lang/crates.io-index +- cargo-platform 0.1.9 | https://github.com/rust-lang/cargo | registry+https://github.com/rust-lang/crates.io-index +- proc-macro-crate 1.3.1 | https://github.com/bkchr/proc-macro-crate | registry+https://github.com/rust-lang/crates.io-index +- proc-macro-crate 2.0.2 | https://github.com/bkchr/proc-macro-crate | registry+https://github.com/rust-lang/crates.io-index +- proc-macro-crate 3.5.0 | https://github.com/bkchr/proc-macro-crate | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/LICENSE-2.0 + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- proc-macro-error 1.0.4 | https://gitlab.com/CreepySkeleton/proc-macro-error | registry+https://github.com/rust-lang/crates.io-index + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2019-2020 CreepySkeleton + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- enumflags2 0.7.12 | https://github.com/meithecatte/enumflags2 | registry+https://github.com/rust-lang/crates.io-index + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; and +You must cause any modified files to carry prominent notices stating that You changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + + +Copyright 2017-2023 Maik Klein, Maja Kądziołka + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- enumflags2_derive 0.7.12 | https://github.com/meithecatte/enumflags2 | registry+https://github.com/rust-lang/crates.io-index + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; and +You must cause any modified files to carry prominent notices stating that You changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + + +Copyright [2017] [Maik Klein] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- dbus 0.9.12 | https://github.com/diwic/dbus-rs | registry+https://github.com/rust-lang/crates.io-index +- libdbus-sys 0.2.7 | https://github.com/diwic/dbus-rs | registry+https://github.com/rust-lang/crates.io-index + +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2014-2018 David Henningsson and other contributors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- softbuffer 0.4.8 | https://github.com/rust-windowing/softbuffer | registry+https://github.com/rust-lang/crates.io-index + +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 Kirill Chibisov + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- dpi 0.1.2 | https://github.com/rust-windowing/winit | registry+https://github.com/rust-lang/crates.io-index +- tao 0.35.3 | https://github.com/tauri-apps/tao | registry+https://github.com/rust-lang/crates.io-index + +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- ctor-proc-macro 0.0.7 | https://github.com/mmastrac/rust-ctor | registry+https://github.com/rust-lang/crates.io-index +- ctor 0.8.0 | https://github.com/mmastrac/rust-ctor | registry+https://github.com/rust-lang/crates.io-index + +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- bytemuck 1.25.2 | https://github.com/Lokathor/bytemuck | registry+https://github.com/rust-lang/crates.io-index + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- android_log-sys 0.3.2 | https://github.com/rust-mobile/android_log-sys-rs | registry+https://github.com/rust-lang/crates.io-index + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all +other entities that control, are controlled by, or are under common +control with that entity. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation +source, and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a +copyright notice that is included in or attached to the work +(an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including +the original version of the Work and any modifications or additions +to that Work or Derivative Works thereof, that is intentionally +submitted to Licensor for inclusion in the Work by the copyright owner +or by an individual or Legal Entity authorized to submit on behalf of +the copyright owner. For the purposes of this definition, "submitted" +means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, +and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work, +where such license applies only to those patent claims licensable +by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) +with the Work to which such Contribution(s) was submitted. If You +institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work +or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate +as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You +meet the following conditions: + +(a) You must give any other recipients of the Work or +Derivative Works a copy of this License; and + +(b) You must cause any modified files to carry prominent notices +stating that You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works +that You distribute, all copyright, patent, trademark, and +attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of +the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its +distribution, then any Derivative Works that You distribute must +include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not +pertain to any part of the Derivative Works, in at least one +of the following places: within a NOTICE text file distributed +as part of the Derivative Works; within the Source form or +documentation, if provided along with the Derivative Works; or, +within a display generated by the Derivative Works, if and +wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and +do not modify the License. You may add Your own attribution +notices within Derivative Works that You distribute, alongside +or as an addendum to the NOTICE text from the Work, provided +that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and +may provide additional or different license terms and conditions +for use, reproduction, or distribution of Your modifications, or +for any such Derivative Works as a whole, provided Your use, +reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "{}" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + +Copyright 2016 The android_log_sys Developers + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- android_logger 0.15.1 | https://github.com/rust-mobile/android_logger-rs | registry+https://github.com/rust-lang/crates.io-index + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all +other entities that control, are controlled by, or are under common +control with that entity. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation +source, and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a +copyright notice that is included in or attached to the work +(an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including +the original version of the Work and any modifications or additions +to that Work or Derivative Works thereof, that is intentionally +submitted to Licensor for inclusion in the Work by the copyright owner +or by an individual or Legal Entity authorized to submit on behalf of +the copyright owner. For the purposes of this definition, "submitted" +means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, +and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work, +where such license applies only to those patent claims licensable +by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) +with the Work to which such Contribution(s) was submitted. If You +institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work +or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate +as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You +meet the following conditions: + +(a) You must give any other recipients of the Work or +Derivative Works a copy of this License; and + +(b) You must cause any modified files to carry prominent notices +stating that You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works +that You distribute, all copyright, patent, trademark, and +attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of +the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its +distribution, then any Derivative Works that You distribute must +include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not +pertain to any part of the Derivative Works, in at least one +of the following places: within a NOTICE text file distributed +as part of the Derivative Works; within the Source form or +documentation, if provided along with the Derivative Works; or, +within a display generated by the Derivative Works, if and +wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and +do not modify the License. You may add Your own attribution +notices within Derivative Works that You distribute, alongside +or as an addendum to the NOTICE text from the Work, provided +that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and +may provide additional or different license terms and conditions +for use, reproduction, or distribution of Your modifications, or +for any such Derivative Works as a whole, provided Your use, +reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "{}" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + +Copyright 2016 The android_logger Developers + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: Apache License 2.0 (Apache-2.0) +Used by: +- anyhow 1.0.104 | https://github.com/dtolnay/anyhow | registry+https://github.com/rust-lang/crates.io-index +- async-trait 0.1.91 | https://github.com/dtolnay/async-trait | registry+https://github.com/rust-lang/crates.io-index +- cesu8 1.1.0 | https://github.com/emk/cesu8-rs | registry+https://github.com/rust-lang/crates.io-index +- dirs-sys 0.5.0 | https://github.com/dirs-dev/dirs-sys-rs | registry+https://github.com/rust-lang/crates.io-index +- dirs 6.0.0 | https://github.com/soc/dirs-rs | registry+https://github.com/rust-lang/crates.io-index +- dispatch2 0.3.1 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- dtoa 1.0.11 | https://github.com/dtolnay/dtoa | registry+https://github.com/rust-lang/crates.io-index +- dunce 1.0.5 | https://gitlab.com/kornelski/dunce | registry+https://github.com/rust-lang/crates.io-index +- dyn-clone 1.0.20 | https://github.com/dtolnay/dyn-clone | registry+https://github.com/rust-lang/crates.io-index +- erased-serde 0.4.10 | https://github.com/dtolnay/erased-serde | registry+https://github.com/rust-lang/crates.io-index +- fdeflate 0.3.7 | https://github.com/image-rs/fdeflate | registry+https://github.com/rust-lang/crates.io-index +- field-offset 0.3.6 | https://github.com/Diggsey/rust-field-offset | registry+https://github.com/rust-lang/crates.io-index +- ident_case 1.0.1 | https://github.com/TedDriggs/ident_case | registry+https://github.com/rust-lang/crates.io-index +- itoa 1.0.18 | https://github.com/dtolnay/itoa | registry+https://github.com/rust-lang/crates.io-index +- jni-sys-macros 0.4.1 | https://github.com/jni-rs/jni-sys | registry+https://github.com/rust-lang/crates.io-index +- libappindicator-sys 0.9.0 | | registry+https://github.com/rust-lang/crates.io-index +- libc 0.2.189 | https://github.com/rust-lang/libc | registry+https://github.com/rust-lang/crates.io-index +- miniz_oxide 0.8.9 | https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide | registry+https://github.com/rust-lang/crates.io-index +- ndk-sys 0.6.0+11769913 | https://github.com/rust-mobile/ndk | registry+https://github.com/rust-lang/crates.io-index +- ndk 0.9.0 | https://github.com/rust-mobile/ndk | registry+https://github.com/rust-lang/crates.io-index +- num-conv 0.2.2 | https://github.com/jhpratt/num-conv | registry+https://github.com/rust-lang/crates.io-index +- num_enum 0.7.6 | https://github.com/illicitonion/num_enum | registry+https://github.com/rust-lang/crates.io-index +- num_enum_derive 0.7.6 | https://github.com/illicitonion/num_enum | registry+https://github.com/rust-lang/crates.io-index +- objc2-app-kit 0.3.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2-cloud-kit 0.3.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2-core-data 0.3.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2-core-foundation 0.3.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2-core-graphics 0.3.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2-core-image 0.3.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2-core-location 0.3.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2-core-text 0.3.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2-exception-helper 0.1.1 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2-quartz-core 0.3.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2-ui-kit 0.3.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2-user-notifications 0.3.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2-web-kit 0.3.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- pin-project-lite 0.2.17 | https://github.com/taiki-e/pin-project-lite | registry+https://github.com/rust-lang/crates.io-index +- proc-macro2 1.0.107 | https://github.com/dtolnay/proc-macro2 | registry+https://github.com/rust-lang/crates.io-index +- process-wrap 9.1.0 | https://github.com/watchexec/process-wrap | registry+https://github.com/rust-lang/crates.io-index +- quote 1.0.47 | https://github.com/dtolnay/quote | registry+https://github.com/rust-lang/crates.io-index +- r-efi 5.3.0 | https://github.com/r-efi/r-efi | registry+https://github.com/rust-lang/crates.io-index +- r-efi 6.0.0 | https://github.com/r-efi/r-efi | registry+https://github.com/rust-lang/crates.io-index +- rand 0.9.5 | https://github.com/rust-random/rand | registry+https://github.com/rust-lang/crates.io-index +- rand_chacha 0.9.0 | https://github.com/rust-random/rand | registry+https://github.com/rust-lang/crates.io-index +- raw-window-handle 0.6.2 | https://github.com/rust-windowing/raw-window-handle | registry+https://github.com/rust-lang/crates.io-index +- rustc-hash 2.1.3 | https://github.com/rust-lang/rustc-hash | registry+https://github.com/rust-lang/crates.io-index +- rustversion 1.0.23 | https://github.com/dtolnay/rustversion | registry+https://github.com/rust-lang/crates.io-index +- semver 1.0.28 | https://github.com/dtolnay/semver | registry+https://github.com/rust-lang/crates.io-index +- serde-untagged 0.1.9 | https://github.com/dtolnay/serde-untagged | registry+https://github.com/rust-lang/crates.io-index +- serde 1.0.229 | https://github.com/serde-rs/serde | registry+https://github.com/rust-lang/crates.io-index +- serde_core 1.0.229 | https://github.com/serde-rs/serde | registry+https://github.com/rust-lang/crates.io-index +- serde_derive 1.0.229 | https://github.com/serde-rs/serde | registry+https://github.com/rust-lang/crates.io-index +- serde_derive_internals 0.29.1 | https://github.com/serde-rs/serde | registry+https://github.com/rust-lang/crates.io-index +- serde_json 1.0.151 | https://github.com/serde-rs/json | registry+https://github.com/rust-lang/crates.io-index +- serde_repr 0.1.21 | https://github.com/dtolnay/serde-repr | registry+https://github.com/rust-lang/crates.io-index +- siphasher 1.0.3 | https://github.com/jedisct1/rust-siphash | registry+https://github.com/rust-lang/crates.io-index +- syn 2.0.119 | https://github.com/dtolnay/syn | registry+https://github.com/rust-lang/crates.io-index +- syn 3.0.3 | https://github.com/dtolnay/syn | registry+https://github.com/rust-lang/crates.io-index +- sync_wrapper 1.0.2 | https://github.com/Actyx/sync_wrapper | registry+https://github.com/rust-lang/crates.io-index +- tauri-codegen 2.6.3 | https://github.com/tauri-apps/tauri | registry+https://github.com/rust-lang/crates.io-index +- tauri-macros 2.6.3 | https://github.com/tauri-apps/tauri | registry+https://github.com/rust-lang/crates.io-index +- tauri-plugin-dialog 2.7.2 | https://github.com/tauri-apps/plugins-workspace | registry+https://github.com/rust-lang/crates.io-index +- tauri-plugin-fs 2.5.1 | https://github.com/tauri-apps/plugins-workspace | registry+https://github.com/rust-lang/crates.io-index +- tauri-plugin-log 2.9.0 | https://github.com/tauri-apps/plugins-workspace | registry+https://github.com/rust-lang/crates.io-index +- tauri-plugin-opener 2.5.4 | https://github.com/tauri-apps/plugins-workspace | registry+https://github.com/rust-lang/crates.io-index +- tauri-plugin-shell 2.3.5 | https://github.com/tauri-apps/plugins-workspace | registry+https://github.com/rust-lang/crates.io-index +- tauri-plugin-single-instance 2.4.3 | https://github.com/tauri-apps/plugins-workspace | registry+https://github.com/rust-lang/crates.io-index +- tauri-plugin-store 2.4.4 | https://github.com/tauri-apps/plugins-workspace | registry+https://github.com/rust-lang/crates.io-index +- tauri-runtime-wry 2.11.4 | https://github.com/tauri-apps/tauri | registry+https://github.com/rust-lang/crates.io-index +- tauri-runtime 2.11.3 | https://github.com/tauri-apps/tauri | registry+https://github.com/rust-lang/crates.io-index +- tauri-utils 2.9.3 | https://github.com/tauri-apps/tauri | registry+https://github.com/rust-lang/crates.io-index +- tauri 2.11.5 | https://github.com/tauri-apps/tauri | registry+https://github.com/rust-lang/crates.io-index +- thiserror-impl 1.0.69 | https://github.com/dtolnay/thiserror | registry+https://github.com/rust-lang/crates.io-index +- thiserror-impl 2.0.19 | https://github.com/dtolnay/thiserror | registry+https://github.com/rust-lang/crates.io-index +- thiserror 1.0.69 | https://github.com/dtolnay/thiserror | registry+https://github.com/rust-lang/crates.io-index +- thiserror 2.0.19 | https://github.com/dtolnay/thiserror | registry+https://github.com/rust-lang/crates.io-index +- time-core 0.1.8 | https://github.com/time-rs/time | registry+https://github.com/rust-lang/crates.io-index +- time-macros 0.2.27 | https://github.com/time-rs/time | registry+https://github.com/rust-lang/crates.io-index +- time 0.3.47 | https://github.com/time-rs/time | registry+https://github.com/rust-lang/crates.io-index +- typeid 1.0.3 | https://github.com/dtolnay/typeid | registry+https://github.com/rust-lang/crates.io-index +- unic-char-property 0.9.0 | https://github.com/open-i18n/rust-unic/ | registry+https://github.com/rust-lang/crates.io-index +- unic-char-range 0.9.0 | https://github.com/open-i18n/rust-unic/ | registry+https://github.com/rust-lang/crates.io-index +- unic-common 0.9.0 | https://github.com/open-i18n/rust-unic/ | registry+https://github.com/rust-lang/crates.io-index +- unic-ucd-ident 0.9.0 | https://github.com/open-i18n/rust-unic/ | registry+https://github.com/rust-lang/crates.io-index +- unic-ucd-version 0.9.0 | https://github.com/open-i18n/rust-unic/ | registry+https://github.com/rust-lang/crates.io-index +- unicode-ident 1.0.24 | https://github.com/dtolnay/unicode-ident | registry+https://github.com/rust-lang/crates.io-index +- wasip2 1.0.1+wasi-0.2.4 | https://github.com/bytecodealliance/wasi-rs | registry+https://github.com/rust-lang/crates.io-index +- wasm-streams 0.5.0 | https://github.com/MattiasBuelens/wasm-streams/ | registry+https://github.com/rust-lang/crates.io-index +- winapi-i686-pc-windows-gnu 0.4.0 | https://github.com/retep998/winapi-rs | registry+https://github.com/rust-lang/crates.io-index +- winapi-x86_64-pc-windows-gnu 0.4.0 | https://github.com/retep998/winapi-rs | registry+https://github.com/rust-lang/crates.io-index + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------------------------------------------------------------------------------- +License: BSD 3-Clause "New" or "Revised" License (BSD-3-Clause) +Used by: +- alloc-no-stdlib 2.0.4 | https://github.com/dropbox/rust-alloc-no-stdlib | registry+https://github.com/rust-lang/crates.io-index +- brotli 8.0.4 | https://github.com/dropbox/rust-brotli | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2016 Dropbox, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------- +License: BSD 3-Clause "New" or "Revised" License (BSD-3-Clause) +Used by: +- alloc-stdlib 0.2.4 | https://github.com/dropbox/rust-alloc-no-stdlib | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) . + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------- +License: BSD 3-Clause "New" or "Revised" License (BSD-3-Clause) +Used by: +- encoding_rs 0.8.35 | https://github.com/hsivonen/encoding_rs | registry+https://github.com/rust-lang/crates.io-index + +Copyright © WHATWG (Apple, Google, Mozilla, Microsoft). + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------- +License: BSD 3-Clause "New" or "Revised" License (BSD-3-Clause) +Used by: +- atomic-write-file 0.3.0 | https://github.com/andreacorbellini/rust-atomic-write-file | registry+https://github.com/rust-lang/crates.io-index + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------- +License: ISC License (ISC) +Used by: +- libloading 0.7.4 | https://github.com/nagisa/rust_libloading/ | registry+https://github.com/rust-lang/crates.io-index + +Copyright © 2015, Simonas Kazlauskas + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without +fee is hereby granted, provided that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- uds_windows 1.2.1 | https://github.com/haraldh/rust_uds_windows | registry+https://github.com/rust-lang/crates.io-index + + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- brotli 8.0.4 | https://github.com/dropbox/rust-brotli | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- mio 1.2.2 | https://github.com/tokio-rs/mio | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2014 Carl Lerche and other MIO contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- fern 0.7.1 | https://github.com/daboross/fern | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2014-2017 David Ross + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- hyper 1.11.0 | https://github.com/hyperium/hyper | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2014-2026 Sean McArthur + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- plist 1.8.0 | https://github.com/ebarnard/rust-plist/ | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2015 Edward Barnard + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- new_debug_unreachable 1.0.6 | https://github.com/mbrubeck/rust-debug-unreachable | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2015 Jonathan Reem + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- which 8.0.5 | https://github.com/harryfei/which-rs.git | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2015 fangyuanziti + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- webkit2gtk-sys 2.0.2 | https://github.com/tauri-apps/webkit2gtk-rs | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2016 Boucher, Antoni + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- webkit2gtk 2.0.2 | https://github.com/tauri-apps/webkit2gtk-rs | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2016 Boucher, Antoni +Copyright (c) 2017-2021, The Gtk-rs Project Developers. +Copyright (c) 2021, Tauri Programme within The Commons Conservancy + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- memoffset 0.9.1 | https://github.com/Gilnaa/memoffset | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2017 Gilad Naaman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- redox_syscall 0.5.18 | https://gitlab.redox-os.org/redox-os/syscall | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2017 Redox OS Developers + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- bytes 1.12.1 | https://github.com/tokio-rs/bytes | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2018 Carl Lerche + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- want 0.3.1 | https://github.com/seanmonstar/want | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2018-2019 Sean McArthur + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- try-lock 0.2.5 | https://github.com/seanmonstar/try-lock | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2018-2023 Sean McArthur +Copyright (c) 2016 Alex Crichton + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- slab 0.4.12 | https://github.com/tokio-rs/slab | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2019 Carl Lerche + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- tracing-attributes 0.1.31 | https://github.com/tokio-rs/tracing | registry+https://github.com/rust-lang/crates.io-index +- tracing-core 0.1.36 | https://github.com/tokio-rs/tracing | registry+https://github.com/rust-lang/crates.io-index +- tracing 0.1.44 | https://github.com/tokio-rs/tracing | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2019 Tokio Contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- tower-layer 0.3.3 | https://github.com/tower-rs/tower | registry+https://github.com/rust-lang/crates.io-index +- tower-service 0.3.3 | https://github.com/tower-rs/tower | registry+https://github.com/rust-lang/crates.io-index +- tower 0.5.3 | https://github.com/tower-rs/tower | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2019 Tower Contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- tower-http 0.6.11 | https://github.com/tower-rs/tower-http | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2019-2021 Tower Contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- http-body-util 0.1.4 | https://github.com/hyperium/http-body | registry+https://github.com/rust-lang/crates.io-index +- http-body 1.1.0 | https://github.com/hyperium/http-body | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2019-2026 Sean McArthur & Hyper Contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- hyper-util 0.1.20 | https://github.com/hyperium/hyper-util | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2023-2025 Sean McArthur + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- zbus 5.13.2 | https://github.com/z-galaxy/zbus/ | registry+https://github.com/rust-lang/crates.io-index +- zbus_macros 5.13.2 | https://github.com/z-galaxy/zbus/ | registry+https://github.com/rust-lang/crates.io-index +- zbus_names 4.3.1 | https://github.com/z-galaxy/zbus/ | registry+https://github.com/rust-lang/crates.io-index +- zvariant 5.9.2 | https://github.com/z-galaxy/zbus/ | registry+https://github.com/rust-lang/crates.io-index +- zvariant_derive 5.9.2 | https://github.com/z-galaxy/zbus/ | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2024 Zeeshan Ali Khan & zbus contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- synstructure 0.13.2 | https://github.com/mystor/synstructure | registry+https://github.com/rust-lang/crates.io-index + +Copyright 2016 Nika Layzell + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- precomputed-hash 0.1.1 | https://github.com/emilio/precomputed-hash | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) 2017 Emilio Cobos Álvarez + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- cfb 0.7.3 | https://github.com/mdsteele/rust-cfb | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) 2017 Matthew D. Steele + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- darling 0.23.0 | https://github.com/TedDriggs/darling | registry+https://github.com/rust-lang/crates.io-index +- darling_core 0.23.0 | https://github.com/TedDriggs/darling | registry+https://github.com/rust-lang/crates.io-index +- darling_macro 0.23.0 | https://github.com/TedDriggs/darling | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) 2017 Ted Driggs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- ico 0.5.0 | https://github.com/mdsteele/rust-ico | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) 2018 Matthew D. Steele + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- infer 0.19.0 | https://github.com/bojand/infer | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) 2019 Bojan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- schemars 0.8.22 | https://github.com/GREsau/schemars | registry+https://github.com/rust-lang/crates.io-index +- schemars_derive 0.8.22 | https://github.com/GREsau/schemars | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) 2019 Graham Esau + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- tokio-macros 2.7.2 | https://github.com/tokio-rs/tokio | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) 2019 Yoshua Wuyts +Copyright (c) Tokio Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- urlpattern 0.3.0 | https://github.com/denoland/rust-urlpattern | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) 2021 the Deno authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- rfd 0.16.0 | https://github.com/PolyMeilex/rfd | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) 2022 Bartłomiej Maryńczak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- libredox 0.1.18 | https://gitlab.redox-os.org/redox-os/libredox.git | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) 2023 4lDO2 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- dom_query 0.27.0 | https://github.com/niklak/dom_query | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) 2023 Mykola Humanov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + +This project contains portions of code and architectural concepts originally +derived from the "nipper" project (https://github.com/importcjj/nipper), +developed by Chen Jiaju, licensed under the MIT License and the Apache License 2.0 (dual licensed). +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- is-docker 0.2.0 | https://github.com/TheLarkInn/is-docker | registry+https://github.com/rust-lang/crates.io-index +- is-wsl 0.4.0 | https://github.com/TheLarkInn/is-wsl | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) 2023 Sean Larkin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- block2 0.6.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- brotli-decompressor 5.0.3 | https://github.com/dropbox/rust-brotli-decompressor | registry+https://github.com/rust-lang/crates.io-index +- dlopen2 0.8.2 | https://github.com/OpenByteDev/dlopen2 | registry+https://github.com/rust-lang/crates.io-index +- dlopen2_derive 0.4.3 | https://github.com/OpenByteDev/dlopen2 | registry+https://github.com/rust-lang/crates.io-index +- dpi 0.1.2 | https://github.com/rust-windowing/winit | registry+https://github.com/rust-lang/crates.io-index +- objc2-encode 4.1.0 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2-foundation 0.3.2 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- objc2 0.6.4 | https://github.com/madsmtm/objc2 | registry+https://github.com/rust-lang/crates.io-index +- sigchld 0.2.4 | https://github.com/oconnor663/sigchld.rs | registry+https://github.com/rust-lang/crates.io-index +- webview2-com-macros 0.8.1 | https://github.com/wravery/webview2-rs | registry+https://github.com/rust-lang/crates.io-index +- webview2-com-sys 0.38.2 | https://github.com/wravery/webview2-rs | registry+https://github.com/rust-lang/crates.io-index +- webview2-com 0.38.2 | https://github.com/wravery/webview2-rs | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- tokio-util 0.7.19 | https://github.com/tokio-rs/tokio | registry+https://github.com/rust-lang/crates.io-index +- tokio 1.53.1 | https://github.com/tokio-rs/tokio | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) Tokio Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- simd-adler32 0.3.10 | https://github.com/mcountryman/simd-adler32 | registry+https://github.com/rust-lang/crates.io-index + +MIT License + +Copyright (c) [2021] [Marvin Countryman] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- cargo_metadata 0.19.2 | https://github.com/oli-obk/cargo_metadata | registry+https://github.com/rust-lang/crates.io-index +- endi 1.1.1 | https://github.com/zeenix/endi | registry+https://github.com/rust-lang/crates.io-index +- x11-dl 2.21.0 | https://github.com/AltF02/x11-rs.git | registry+https://github.com/rust-lang/crates.io-index +- x11 2.21.0 | https://github.com/AltF02/x11-rs.git | registry+https://github.com/rust-lang/crates.io-index +- zmij 1.0.23 | https://github.com/dtolnay/zmij | registry+https://github.com/rust-lang/crates.io-index +- zvariant_utils 3.3.0 | https://github.com/z-galaxy/zbus/ | registry+https://github.com/rust-lang/crates.io-index + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- winnow 0.5.40 | https://github.com/winnow-rs/winnow | registry+https://github.com/rust-lang/crates.io-index +- winnow 0.7.15 | https://github.com/winnow-rs/winnow | registry+https://github.com/rust-lang/crates.io-index +- winnow 1.0.4 | https://github.com/winnow-rs/winnow | registry+https://github.com/rust-lang/crates.io-index + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- atk-sys 0.18.2 | https://github.com/gtk-rs/gtk3-rs | registry+https://github.com/rust-lang/crates.io-index +- atk 0.18.2 | https://github.com/gtk-rs/gtk3-rs | registry+https://github.com/rust-lang/crates.io-index +- cairo-rs 0.18.5 | https://github.com/gtk-rs/gtk-rs-core | registry+https://github.com/rust-lang/crates.io-index +- cairo-sys-rs 0.18.2 | https://github.com/gtk-rs/gtk-rs-core | registry+https://github.com/rust-lang/crates.io-index +- gdk-pixbuf-sys 0.18.0 | https://github.com/gtk-rs/gtk-rs-core | registry+https://github.com/rust-lang/crates.io-index +- gdk-pixbuf 0.18.5 | https://github.com/gtk-rs/gtk-rs-core | registry+https://github.com/rust-lang/crates.io-index +- gdk-sys 0.18.2 | https://github.com/gtk-rs/gtk3-rs | registry+https://github.com/rust-lang/crates.io-index +- gdk 0.18.2 | https://github.com/gtk-rs/gtk3-rs | registry+https://github.com/rust-lang/crates.io-index +- gdkwayland-sys 0.18.2 | https://github.com/gtk-rs/gtk3-rs | registry+https://github.com/rust-lang/crates.io-index +- gdkx11-sys 0.18.2 | https://github.com/gtk-rs/gtk3-rs | registry+https://github.com/rust-lang/crates.io-index +- gdkx11 0.18.2 | https://github.com/gtk-rs/gtk3-rs | registry+https://github.com/rust-lang/crates.io-index +- gio-sys 0.18.1 | https://github.com/gtk-rs/gtk-rs-core | registry+https://github.com/rust-lang/crates.io-index +- gio 0.18.4 | https://github.com/gtk-rs/gtk-rs-core | registry+https://github.com/rust-lang/crates.io-index +- glib-macros 0.18.5 | https://github.com/gtk-rs/gtk-rs-core | registry+https://github.com/rust-lang/crates.io-index +- glib-sys 0.18.1 | https://github.com/gtk-rs/gtk-rs-core | registry+https://github.com/rust-lang/crates.io-index +- glib 0.18.5 | https://github.com/gtk-rs/gtk-rs-core | registry+https://github.com/rust-lang/crates.io-index +- gobject-sys 0.18.0 | https://github.com/gtk-rs/gtk-rs-core | registry+https://github.com/rust-lang/crates.io-index +- gtk-sys 0.18.2 | https://github.com/gtk-rs/gtk3-rs | registry+https://github.com/rust-lang/crates.io-index +- gtk3-macros 0.18.2 | https://github.com/gtk-rs/gtk3-rs | registry+https://github.com/rust-lang/crates.io-index +- gtk 0.18.2 | https://github.com/gtk-rs/gtk3-rs | registry+https://github.com/rust-lang/crates.io-index +- pango-sys 0.18.0 | https://github.com/gtk-rs/gtk-rs-core | registry+https://github.com/rust-lang/crates.io-index +- pango 0.18.3 | https://github.com/gtk-rs/gtk-rs-core | registry+https://github.com/rust-lang/crates.io-index + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- javascriptcore-rs-sys 1.1.1 | https://github.com/tauri-apps/javascriptcore-rs | registry+https://github.com/rust-lang/crates.io-index +- soup3-sys 0.5.0 | https://gitlab.gnome.org/World/Rust/soup3-rs | registry+https://github.com/rust-lang/crates.io-index +- soup3 0.5.0 | https://gitlab.gnome.org/World/Rust/soup3-rs | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) + +Copyright (c) 2013-2017, The Gtk-rs Project Developers. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- javascriptcore-rs 1.1.2 | https://github.com/tauri-apps/javascriptcore-rs | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) + +Copyright (c) 2013-2021, The Gtk-rs Project Developers. +Copyright (c) 2021, Tauri Programme within The Commons Conservancy. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- phf 0.13.1 | https://github.com/rust-phf/rust-phf | registry+https://github.com/rust-lang/crates.io-index +- phf_generator 0.13.1 | https://github.com/rust-phf/rust-phf | registry+https://github.com/rust-lang/crates.io-index +- phf_macros 0.13.1 | https://github.com/rust-phf/rust-phf | registry+https://github.com/rust-lang/crates.io-index +- phf_shared 0.13.1 | https://github.com/rust-phf/rust-phf | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) + +Copyright (c) 2014-2022 Steven Fackler, Yuki Okushi + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- aho-corasick 1.1.4 | https://github.com/BurntSushi/aho-corasick | registry+https://github.com/rust-lang/crates.io-index +- byteorder 1.5.0 | https://github.com/BurntSushi/byteorder | registry+https://github.com/rust-lang/crates.io-index +- memchr 2.8.3 | https://github.com/BurntSushi/memchr | registry+https://github.com/rust-lang/crates.io-index +- walkdir 2.5.0 | https://github.com/BurntSushi/walkdir | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- nix 0.30.1 | https://github.com/nix-rust/nix | registry+https://github.com/rust-lang/crates.io-index +- nix 0.31.3 | https://github.com/nix-rust/nix | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) + +Copyright (c) 2015 Carl Lerche + nix-rust Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- strsim 0.11.1 | https://github.com/rapidfuzz/strsim-rs | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) + +Copyright (c) 2015 Danny Guo +Copyright (c) 2016 Titus Wormer +Copyright (c) 2018 Akash Kurdekar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- combine 4.6.7 | https://github.com/Marwes/combine | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) + +Copyright (c) 2015 Markus Westerlind + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- derive_more-impl 2.1.1 | https://github.com/JelteF/derive_more | registry+https://github.com/rust-lang/crates.io-index +- derive_more 2.1.1 | https://github.com/JelteF/derive_more | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) + +Copyright (c) 2016 Jelte Fennema + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- same-file 1.0.6 | https://github.com/BurntSushi/same-file | registry+https://github.com/rust-lang/crates.io-index +- winapi-util 0.1.11 | https://github.com/BurntSushi/winapi-util | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) + +Copyright (c) 2017 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- redox_users 0.5.2 | https://gitlab.redox-os.org/redox-os/users | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) + +Copyright (c) 2017 Jose Narvaez + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- os_pipe 1.2.3 | https://github.com/oconnor663/os_pipe.rs | registry+https://github.com/rust-lang/crates.io-index +- shared_child 1.1.1 | https://github.com/oconnor663/shared_child.rs | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- open 5.4.0 | https://github.com/Byron/open-rs | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) +===================== + +Copyright © `2015` `Sebastian Thiel` + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the “Software”), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- generic-array 0.14.7 | https://github.com/fizyk20/generic-array.git | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) + +Copyright (c) 2015 Bartłomiej Kamiński + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------- +License: MIT License (MIT) +Used by: +- quick-xml 0.38.4 | https://github.com/tafia/quick-xml | registry+https://github.com/rust-lang/crates.io-index + +The MIT License (MIT) + +Copyright (c) 2016 Johann Tuffe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +------------------------------------------------------------------------------- +License: Mozilla Public License 2.0 (MPL-2.0) +Used by: +- dtoa-short 0.3.5 | https://github.com/upsuper/dtoa-short | registry+https://github.com/rust-lang/crates.io-index + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + +------------------------------------------------------------------------------- +License: Mozilla Public License 2.0 (MPL-2.0) +Used by: +- cssparser-macros 0.6.1 | https://github.com/servo/rust-cssparser | registry+https://github.com/rust-lang/crates.io-index +- cssparser 0.36.0 | https://github.com/servo/rust-cssparser | registry+https://github.com/rust-lang/crates.io-index + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + +------------------------------------------------------------------------------- +License: Mozilla Public License 2.0 (MPL-2.0) +Used by: +- option-ext 0.2.0 | https://github.com/soc/option-ext.git | registry+https://github.com/rust-lang/crates.io-index +- selectors 0.36.1 | https://github.com/servo/stylo | registry+https://github.com/rust-lang/crates.io-index + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + +------------------------------------------------------------------------------- +License: Unicode License v3 (Unicode-3.0) +Used by: +- unicode-ident 1.0.24 | https://github.com/dtolnay/unicode-ident | registry+https://github.com/rust-lang/crates.io-index + +UNICODE LICENSE V3 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2023 Unicode, Inc. + +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR +SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT +DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of data files and any associated documentation (the "Data Files") or +software and any associated documentation (the "Software") to deal in the +Data Files or Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, and/or sell +copies of the Data Files or Software, and to permit persons to whom the +Data Files or Software are furnished to do so, provided that either (a) +this copyright and permission notice appear with all copies of the Data +Files or Software, or (b) this copyright and permission notice appear in +associated Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF +THIRD PARTY RIGHTS. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE +BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA +FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in these Data Files or Software without prior written +authorization of the copyright holder. + +------------------------------------------------------------------------------- +License: Unicode License v3 (Unicode-3.0) +Used by: +- icu_collections 2.1.1 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- icu_locale_core 2.1.1 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- icu_normalizer 2.1.1 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- icu_normalizer_data 2.1.1 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- icu_properties 2.1.2 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- icu_properties_data 2.1.2 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- icu_provider 2.1.1 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- litemap 0.8.2 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- potential_utf 0.1.5 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- tinystr 0.8.3 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- writeable 0.6.3 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- yoke-derive 0.8.2 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- yoke 0.8.3 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- zerofrom-derive 0.1.7 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- zerofrom 0.1.8 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- zerotrie 0.2.4 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- zerovec-derive 0.11.3 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index +- zerovec 0.11.6 | https://github.com/unicode-org/icu4x | registry+https://github.com/rust-lang/crates.io-index + +UNICODE LICENSE V3 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 2020-2024 Unicode, Inc. + +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR +SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT +DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of data files and any associated documentation (the "Data Files") or +software and any associated documentation (the "Software") to deal in the +Data Files or Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, and/or sell +copies of the Data Files or Software, and to permit persons to whom the +Data Files or Software are furnished to do so, provided that either (a) +this copyright and permission notice appear with all copies of the Data +Files or Software, or (b) this copyright and permission notice appear in +associated Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF +THIRD PARTY RIGHTS. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE +BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA +FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in these Data Files or Software without prior written +authorization of the copyright holder. + +SPDX-License-Identifier: Unicode-3.0 + +— + +Portions of ICU4X may have been adapted from ICU4C and/or ICU4J. +ICU 1.8.1 to ICU 57.1 © 1995-2016 International Business Machines Corporation and others. + +------------------------------------------------------------------------------- +License: zlib License (Zlib) +Used by: +- foldhash 0.2.0 | https://github.com/orlp/foldhash | registry+https://github.com/rust-lang/crates.io-index + +Copyright (c) 2024 Orson Peters + +This software is provided 'as-is', without any express or implied warranty. In +no event will the authors be held liable for any damages arising from the use of +this software. + +Permission is granted to anyone to use this software for any purpose, including +commercial applications, and to alter it and redistribute it freely, subject to +the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim + that you wrote the original software. If you use this software in a product, + an acknowledgment in the product documentation would be appreciated but is + not required. + +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. + +FRONTEND DEPENDENCIES +===================== + +------------------------------------------------------------------------------- +@floating-ui/core@1.8.0 | MIT | https://github.com/floating-ui/floating-ui + +MIT License + +Copyright (c) 2021-present Floating UI contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +@floating-ui/dom@1.8.0 | MIT | https://github.com/floating-ui/floating-ui + +MIT License + +Copyright (c) 2021-present Floating UI contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +@floating-ui/react-dom@2.1.9 | MIT | https://github.com/floating-ui/floating-ui + +MIT License + +Copyright (c) 2021-present Floating UI contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +@floating-ui/react@0.27.20 | MIT | https://github.com/floating-ui/floating-ui + +MIT License + +Copyright (c) 2021-present Floating UI contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +@floating-ui/utils@0.2.12 | MIT | https://github.com/floating-ui/floating-ui + +MIT License + +Copyright (c) 2021-present Floating UI contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +@mantine/core@9.5.0 | MIT | https://github.com/mantinedev/mantine + +MIT License + +Copyright (c) 2021 Vitaly Rtishchev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +@mantine/hooks@9.5.0 | MIT | https://github.com/mantinedev/mantine + +MIT License + +Copyright (c) 2021 Vitaly Rtishchev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +@tabler/icons-react@3.46.0 | MIT | https://github.com/tabler/tabler-icons + +MIT License + +Copyright (c) 2020-2026 Paweł Kuna + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +@tabler/icons@3.46.0 | MIT | https://github.com/tabler/tabler-icons + +MIT License + +Copyright (c) 2020-2026 Paweł Kuna + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +@tauri-apps/api@2.11.1 | Apache-2.0 OR MIT | https://github.com/tauri-apps/tauri + +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + +MIT License + +Copyright (c) 2017 - Present Tauri Apps Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +@types/react@19.2.18 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped + +MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE + +------------------------------------------------------------------------------- +clsx@2.1.1 | MIT | https://github.com/lukeed/clsx + +MIT License + +Copyright (c) Luke Edwards (lukeed.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +csstype@3.2.3 | MIT | https://github.com/frenic/csstype + +Copyright (c) 2017-2018 Fredrik Nicol + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +detect-node-es@1.1.0 | MIT | https://github.com/thekashey/detect-node + +MIT License + +Copyright (c) 2017 Ilya Kantor + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +get-nonce@1.0.1 | MIT | https://github.com/theKashey/get-nonce + +MIT License + +Copyright (c) 2020 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +react-dom@19.2.8 | MIT | https://github.com/react/react + +MIT License + +Copyright (c) Meta Platforms, Inc. and affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +react-number-format@5.4.5 | MIT | https://github.com/s-yadav/react-number-format + +MIT License + +Copyright (c) 2020-present Sudhanshu Yadav + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +react-remove-scroll-bar@2.3.8 | MIT | https://github.com/theKashey/react-remove-scroll-bar + +Vendored verbatim upstream license for react-remove-scroll-bar@2.3.8 +Source: https://github.com/theKashey/react-remove-scroll-bar/blob/8ca9ba5ea52de03308fe8ced94f7b159a44d28ff/LICENSE +SHA-256: a79aae0c0f21990d9d963bb3c5a79cdcea9a46f8523ba55c58d7fe776b6ebc84 + +MIT License + +Copyright (c) 2025 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +react-remove-scroll@2.7.2 | MIT | https://github.com/theKashey/react-remove-scroll + +MIT License + +Copyright (c) 2017 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +react-style-singleton@2.2.3 | MIT | https://github.com/theKashey/react-style-singleton + +MIT License + +Copyright (c) 2017 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +react@19.2.8 | MIT | https://github.com/react/react + +MIT License + +Copyright (c) Meta Platforms, Inc. and affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +scheduler@0.27.0 | MIT | https://github.com/facebook/react + +MIT License + +Copyright (c) Meta Platforms, Inc. and affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +tabbable@6.5.0 | MIT | https://github.com/focus-trap/tabbable + +The MIT License (MIT) + +Copyright (c) 2015 David Clark + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +tagged-tag@1.0.0 | MIT | https://github.com/sindresorhus/tagged-tag + +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +tslib@2.8.1 | 0BSD | https://github.com/Microsoft/tslib + +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +------------------------------------------------------------------------------- +type-fest@5.8.0 | (MIT OR CC0-1.0) | https://github.com/sindresorhus/type-fest + +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. + +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------- +use-callback-ref@1.3.3 | MIT | https://github.com/theKashey/use-callback-ref + +MIT License + +Copyright (c) 2017 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------- +use-sidecar@1.1.3 | MIT | https://github.com/theKashey/use-sidecar + +MIT License + +Copyright (c) 2017 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/desktop/VERSION b/desktop/VERSION deleted file mode 100644 index 0d91a54..0000000 --- a/desktop/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.3.0 diff --git a/desktop/about.hbs b/desktop/about.hbs new file mode 100644 index 0000000..fecbfca --- /dev/null +++ b/desktop/about.hbs @@ -0,0 +1,12 @@ +RUST DEPENDENCIES +================= +{{#each licenses}} +------------------------------------------------------------------------------- +License: {{name}} ({{id}}) +Used by: +{{#each used_by}} +- {{crate.name}} {{crate.version}} | {{crate.repository}} | {{crate.source}} +{{/each}} + +{{{text}}} +{{/each}} diff --git a/desktop/about.toml b/desktop/about.toml new file mode 100644 index 0000000..5753ea5 --- /dev/null +++ b/desktop/about.toml @@ -0,0 +1,14 @@ +accepted = [ + "Apache-2.0", + "MIT", + "BSD-2-Clause", + "BSD-3-Clause", + "ISC", + "MPL-2.0", + "Unicode-3.0", + "Zlib", + "OpenSSL", +] +ignore-build-dependencies = true +ignore-dev-dependencies = true +workarounds = ["ring", "rustls", "rustix"] diff --git a/desktop/eslint.config.js b/desktop/eslint.config.js new file mode 100644 index 0000000..766fffc --- /dev/null +++ b/desktop/eslint.config.js @@ -0,0 +1,31 @@ +import eslint from '@eslint/js'; +import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; +import tseslint from 'typescript-eslint'; + +export default tseslint.config( + { ignores: ['dist', 'src-tauri', 'web', 'scripts', 'vite.config.ts'] }, + eslint.configs.recommended, + ...tseslint.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + { + files: ['src/**/*.{ts,tsx}'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + rules: { + 'react-hooks/set-state-in-effect': 'off', + }, + }, + { + files: ['src/**/*.test.{ts,tsx}', 'src/test/**/*.{ts,tsx}'], + rules: { + '@typescript-eslint/no-explicit-any': 'off', + 'react-refresh/only-export-components': 'off', + }, + }, +); diff --git a/desktop/index.html b/desktop/index.html new file mode 100644 index 0000000..8753cd2 --- /dev/null +++ b/desktop/index.html @@ -0,0 +1,15 @@ + + + + + + + + VidXP + + + +
+ + + diff --git a/desktop/licenses/npm/react-remove-scroll-bar-2.3.8-LICENSE.txt b/desktop/licenses/npm/react-remove-scroll-bar-2.3.8-LICENSE.txt new file mode 100644 index 0000000..7c08c39 --- /dev/null +++ b/desktop/licenses/npm/react-remove-scroll-bar-2.3.8-LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Anton Korzunov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/desktop/licenses/uv-LICENSE-MIT.txt b/desktop/licenses/uv-LICENSE-MIT.txt new file mode 100644 index 0000000..986c98b --- /dev/null +++ b/desktop/licenses/uv-LICENSE-MIT.txt @@ -0,0 +1,19 @@ +MIT License + +Copyright (c) 2025 Astral Software Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/desktop/model-cache-catalog.json b/desktop/model-cache-catalog.json new file mode 100644 index 0000000..9bdf1f6 --- /dev/null +++ b/desktop/model-cache-catalog.json @@ -0,0 +1,27 @@ +[ + { + "id": "dropbox-dash/faster-whisper-large-v3-turbo", + "label": "dropbox-dash/faster-whisper-large-v3-turbo", + "relative_artifact": "models--dropbox-dash--faster-whisper-large-v3-turbo/snapshots/0a363e9161cbc7ed1431c9597a8ceaf0c4f78fcf/model.bin" + }, + { + "id": "google/siglip2-base-patch16-224", + "label": "google/siglip2-base-patch16-224", + "relative_artifact": "models--google--siglip2-base-patch16-224/snapshots/75de2d55ec2d0b4efc50b3e9ad70dba96a7b2fa2/model.safetensors" + }, + { + "id": "Qwen/Qwen3-Embedding-0.6B", + "label": "Qwen/Qwen3-Embedding-0.6B", + "relative_artifact": "models--Qwen--Qwen3-Embedding-0.6B/snapshots/97b0c614be4d77ee51c0cef4e5f07c00f9eb65b3/model.safetensors" + }, + { + "id": "sface", + "label": "sface", + "relative_artifact": "opencv-zoo/face_recognition_sface_2021dec.onnx" + }, + { + "id": "yunet", + "label": "yunet", + "relative_artifact": "opencv-zoo/face_detection_yunet_2026may.onnx" + } +] diff --git a/desktop/package-lock.json b/desktop/package-lock.json index 962ca19..f88a215 100644 --- a/desktop/package-lock.json +++ b/desktop/package-lock.json @@ -1,232 +1,5245 @@ { "name": "vidxp-desktop", - "version": "0.3.0", + "version": "0.4.0-b.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vidxp-desktop", - "version": "0.3.0", + "version": "0.4.0-b.1", + "dependencies": { + "@mantine/core": "9.5.0", + "@tabler/icons-react": "3.46.0", + "@tauri-apps/api": "2.11.1", + "react": "19.2.8", + "react-dom": "19.2.8" + }, "devDependencies": { - "@tauri-apps/cli": "2.11.4" + "@eslint/js": "10.0.1", + "@tauri-apps/cli": "2.11.4", + "@testing-library/jest-dom": "7.0.0", + "@testing-library/react": "16.3.2", + "@testing-library/user-event": "14.6.1", + "@types/node": "26.0.0", + "@types/react": "19.2.18", + "@types/react-dom": "19.2.4", + "@vitejs/plugin-react": "6.0.5", + "eslint": "10.8.0", + "eslint-plugin-react-hooks": "7.1.1", + "eslint-plugin-react-refresh": "0.5.3", + "jsdom": "29.1.1", + "license-checker-rseidelsohn": "4.4.2", + "typescript": "6.0.3", + "typescript-eslint": "8.65.0", + "vite": "8.2.0", + "vitest": "4.1.10" } }, - "node_modules/@tauri-apps/cli": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.4.tgz", - "integrity": "sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ==", + "node_modules/@adobe/css-tools": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz", + "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", "dev": true, - "license": "Apache-2.0 OR MIT", - "bin": { - "tauri": "tauri.js" + "license": "MIT" + }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" }, "engines": { - "node": ">= 10" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/tauri" + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, - "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "2.11.4", - "@tauri-apps/cli-darwin-x64": "2.11.4", - "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.4", - "@tauri-apps/cli-linux-arm64-gnu": "2.11.4", - "@tauri-apps/cli-linux-arm64-musl": "2.11.4", - "@tauri-apps/cli-linux-riscv64-gnu": "2.11.4", - "@tauri-apps/cli-linux-x64-gnu": "2.11.4", - "@tauri-apps/cli-linux-x64-musl": "2.11.4", - "@tauri-apps/cli-win32-arm64-msvc": "2.11.4", - "@tauri-apps/cli-win32-ia32-msvc": "2.11.4", - "@tauri-apps/cli-win32-x64-msvc": "2.11.4" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@tauri-apps/cli-darwin-arm64": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.4.tgz", - "integrity": "sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ==", - "cpu": [ - "arm64" - ], + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, "engines": { - "node": ">= 10" + "node": ">=6.9.0" } }, - "node_modules/@tauri-apps/cli-darwin-x64": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.4.tgz", - "integrity": "sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A==", - "cpu": [ - "x64" - ], + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=6.9.0" } }, - "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.4.tgz", - "integrity": "sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ==", - "cpu": [ - "arm" - ], + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, "engines": { - "node": ">= 10" + "node": ">=6.9.0" } }, - "node_modules/@tauri-apps/cli-linux-arm64-gnu": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.4.tgz", - "integrity": "sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA==", - "cpu": [ - "arm64" - ], + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, "engines": { - "node": ">= 10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@tauri-apps/cli-linux-arm64-musl": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.4.tgz", - "integrity": "sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw==", - "cpu": [ - "arm64" - ], + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=6.9.0" } }, - "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.4.tgz", - "integrity": "sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ==", - "cpu": [ - "riscv64" - ], + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=6.9.0" } }, - "node_modules/@tauri-apps/cli-linux-x64-gnu": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.4.tgz", - "integrity": "sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ==", - "cpu": [ - "x64" - ], + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=6.9.0" } }, - "node_modules/@tauri-apps/cli-linux-x64-musl": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.4.tgz", - "integrity": "sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A==", - "cpu": [ - "x64" + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", + "integrity": "sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.3.0.tgz", + "integrity": "sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "linux" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, - "node_modules/@tauri-apps/cli-win32-arm64-msvc": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.4.tgz", - "integrity": "sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ==", - "cpu": [ - "arm64" + "node_modules/@csstools/css-color-parser": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.10.tgz", + "integrity": "sha512-UZhQLIUyJaaMepqehrCODwCg2KW25vFvLWBmqYFaPclYvvxzj/sG8LBOhBFCp11i9uE7t1EyS+RAoV9tztPFyw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.1.0", + "@csstools/css-calc": "^3.3.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "win32" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" } }, - "node_modules/@tauri-apps/cli-win32-ia32-msvc": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.4.tgz", - "integrity": "sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA==", - "cpu": [ - "ia32" + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.7.tgz", + "integrity": "sha512-fQ+05118eQS1cofO3aJpB5efgpBZMvIzwr/sbC8kDLVA5XLG8q1kJV5yzrUAI1f7lvhPnm8fgIjzFB8/O/5Dig==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", "dev": true, - "license": "Apache-2.0 OR MIT", - "optional": true, - "os": [ - "win32" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=20.19.0" } }, - "node_modules/@tauri-apps/cli-win32-x64-msvc": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.4.tgz", - "integrity": "sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw==", - "cpu": [ - "x64" - ], + "node_modules/@emnapi/core": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-2.0.0-alpha.3.tgz", + "integrity": "sha512-AZypUeJ/yByuxyS7BlSNRDOMLMlROYtjYdIAuBmJssVz1UJDSeYxLrdizhXCFYhedC5bqd/ASy8EuNXbVVXp9g==", "dev": true, - "license": "Apache-2.0 OR MIT", + "license": "MIT", "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@emnapi/wasi-threads": "2.0.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "2.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-2.0.0-alpha.3.tgz", + "integrity": "sha512-hFPAhMUjJD9BSyCANEISPOogeXC9Zo9ZQl7L6vKnaVsMkCtzznaW/naYypeyl0Gv5rYfWYsZbpixTMpjDJzQeA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-2.0.1.tgz", + "integrity": "sha512-9DsSk+o5NBX0CCJT8s0EROGSGxjR/tKu6aBTaVyq+SjAEQH4XcdcRxPBRzsBLizTTJ49MJjF+jgu3qnO9GLQcQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", + "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", + "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.27.20", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.20.tgz", + "integrity": "sha512-CMqMy7OaXl9W0eq1Uy7L7i2Y/anPvHmFmESd2CEw0t5YvZhcVCeo4MBevAmswRllX7Y2dEidA4ozGPunLSTQpw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.9", + "@floating-ui/utils": "^0.2.12", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", + "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.8.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT" + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mantine/core": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@mantine/core/-/core-9.5.0.tgz", + "integrity": "sha512-lUZtPfW+ZIXthofPyw+SVgWNiV/OkJ498r3OZeuekPgM23p2AspqHzHjEGhe5DMSTyhma6BhIHF2H10dAp0ibw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.27.19", + "clsx": "^2.1.1", + "react-number-format": "^5.4.5", + "react-remove-scroll": "^2.7.2", + "type-fest": "^5.8.0" + }, + "peerDependencies": { + "@mantine/hooks": "9.5.0", + "react": "^19.2.0", + "react-dom": "^19.2.0" + } + }, + "node_modules/@mantine/hooks": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-9.5.0.tgz", + "integrity": "sha512-d67+7dQW0ZJFiWXqZgwcPrZK0KxKMzAX+Sv663g40xhISseiUoK0f8k/Ss2amOA09IhFayeeaqprVRc4Fp5yEw==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "react": "^19.2.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.2.tgz", + "integrity": "sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.3", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.3" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", + "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", + "dev": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.142.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.142.0.tgz", + "integrity": "sha512-7W+2q5AKQVU36fkaryontrHn3YDt1RyUYXatw9i5H8ocYe2sPKSFB6eS8WNPeRKiN1qAWWZUPm7gwFzJGrccqQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.1.tgz", + "integrity": "sha512-02hOeOSryYxVrOIphmLAsqnCJWxwlzFk+pEt/N/i6OgT3lShHO7xGCU5cpgchRDHboAEbSjzgGh+O/u1GswQmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.1.tgz", + "integrity": "sha512-fMsTOnN0OjFm3CyppWPitKnc8UlliVARUULW6cfU6AIqjdtgmSFWSk9vecHzZduv/yMWIHDlRhM1e8Iff9uAfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.1.tgz", + "integrity": "sha512-1wjKdz/XLGKHaTNHjQveQ/B23TKx4ItAqm1JbyVuvNPc4Ze0Fb48s49TAd/2zcplPl8okE/UbTgmlVfwT7eFeQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.1.tgz", + "integrity": "sha512-Fa0jHR07E7YBN4vOEsbVf2briYNsuOowfLJaXULZM0ldMlaCaj2LJgLMbMe4iacRyZmvR8efFhgR9wKuGclQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.1.tgz", + "integrity": "sha512-pzkgu1SSHGgRRyRZ4fbmSgmajbVt+epaLP99NDjFft69v/ypfTi6swBMiVdh2EkQ0OSnHE1lZDM7DRGkyAzUpA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.1.tgz", + "integrity": "sha512-QI5SEDY8cbiYWHx0VO4vIc3UlS6a32vXHjU8Qy/17adEmZIPuByJg13UEvo9c/UCiUkdcVWY83C+b+JrwnNyUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.1.tgz", + "integrity": "sha512-Sm41FyCeXqmYcERoYOCbGIL5hNfd8w9LQ7Y61Bev48HkcjaJqV/iiVOaiDxjVTRMS+QKrZmD8cfPt4uMVnvM+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.1.tgz", + "integrity": "sha512-2x+WhXTGl9yJYPbltW/BSEPTVz9OIWQyER4N+gJEDWkkn904eRcBzELqh/Hf7K0w/ubGbKNMv0ZC+94QK/IFEg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.1.tgz", + "integrity": "sha512-eEjmQpuRQayHPWWnywaWHkFT3ToPbP3RYy42VVd/B9aBGDA+Ol25EIWHxKQST3IiWJjikCWUF7KtbfqwZrzVwQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.1.tgz", + "integrity": "sha512-/Orga1fZYkLc/56jBICcHrKchl8Z2UKdDSr3LG9ToWO1lQ6a4Livk9Xz+9WN91zsz5QR3XQz2NNoSDEvP6qadw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.1.tgz", + "integrity": "sha512-xxBJRL+0q0Kce7orznGWLuylHDY65vuARXZRpX+hPdv+DqK2c3NlCsVA98tlWzWNEE7yPqA/1NQ5nnCrj49Y5A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.1.tgz", + "integrity": "sha512-M6AdXIXw3s+/8XpKMzdGDEXGS1S7kwUsy+rcTIUIOx5Ge4nXKCtAFHFV9YKkXvGcC5WMoTjAteLzlsQROVI0Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.2.1.tgz", + "integrity": "sha512-/TX0SoRGojHzSAHpfVBbavRVSazg5U3h3Y3VXfcc0cdugq6kxdqw8LPGFiPr+/7gE/60zRcsOY2Vi9b9eT0jww==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "2.0.0-alpha.3", + "@emnapi/runtime": "2.0.0-alpha.3", + "@napi-rs/wasm-runtime": "^1.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.1.tgz", + "integrity": "sha512-EvRrivJieyHG+AO9lleZWgq+g0+S7oV2C51yuqlcyU/R9net+sI4Pj0F+lUoP2bEr6TWX3SqFaaS0SzfLxSzkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.1.tgz", + "integrity": "sha512-Z4eCmn5QJ/5+azF9knpLWKfVd9aidn0mAe9TpJgvBLId9Ax3t0+JVxBmT25Bv7NBbVW1TZyKjQjQReouMeH5UQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tabler/icons": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.46.0.tgz", + "integrity": "sha512-f2RYFl3fzPwj5WO82x6en0dmkjefxEfOm16D1ByM6cj/McNiwOkL4VaPUoP9VVIrXAD9WnTSVFr70px703b//A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-react": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.46.0.tgz", + "integrity": "sha512-CCm7xJWhDT2PH4ZIFkP6AgYKtVhq0gpYkjUN+GVh1AzmIQaa77OW0bQPBPQiTE0PsXMR9oSxFqA3qBglzPyrVQ==", + "license": "MIT", + "dependencies": { + "@tabler/icons": "3.46.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "react": ">= 16" + } + }, + "node_modules/@tauri-apps/api": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.1.tgz", + "integrity": "sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA==", + "license": "Apache-2.0 OR MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.4.tgz", + "integrity": "sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "2.11.4", + "@tauri-apps/cli-darwin-x64": "2.11.4", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.4", + "@tauri-apps/cli-linux-arm64-gnu": "2.11.4", + "@tauri-apps/cli-linux-arm64-musl": "2.11.4", + "@tauri-apps/cli-linux-riscv64-gnu": "2.11.4", + "@tauri-apps/cli-linux-x64-gnu": "2.11.4", + "@tauri-apps/cli-linux-x64-musl": "2.11.4", + "@tauri-apps/cli-win32-arm64-msvc": "2.11.4", + "@tauri-apps/cli-win32-ia32-msvc": "2.11.4", + "@tauri-apps/cli-win32-x64-msvc": "2.11.4" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.4.tgz", + "integrity": "sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.4.tgz", + "integrity": "sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.4.tgz", + "integrity": "sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.4.tgz", + "integrity": "sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.4.tgz", + "integrity": "sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.4.tgz", + "integrity": "sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.4.tgz", + "integrity": "sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.4.tgz", + "integrity": "sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.4.tgz", + "integrity": "sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.4.tgz", + "integrity": "sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.4.tgz", + "integrity": "sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">= 10" } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-7.0.0.tgz", + "integrity": "sha512-HKAH9C6mBo5yBG6yRO5i43L2iisencAo5z+o5P/saHUoY+miC5ivXRxHBJcFyB5ypPNxHJdK3BoF/3O4DIptMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=22", + "npm": ">=6", + "yarn": ">=1" + }, + "peerDependencies": { + "@testing-library/dom": ">=10 <11" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "16.3.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", + "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.0.0.tgz", + "integrity": "sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", + "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.65.0.tgz", + "integrity": "sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.65.0", + "@typescript-eslint/type-utils": "8.65.0", + "@typescript-eslint/utils": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.65.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.65.0.tgz", + "integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz", + "integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.65.0", + "@typescript-eslint/types": "^8.65.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.65.0.tgz", + "integrity": "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz", + "integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.65.0.tgz", + "integrity": "sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0", + "@typescript-eslint/utils": "8.65.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.65.0.tgz", + "integrity": "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz", + "integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.65.0", + "@typescript-eslint/tsconfig-utils": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.65.0.tgz", + "integrity": "sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.65.0.tgz", + "integrity": "sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.65.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.5.tgz", + "integrity": "sha512-BOVzne/NL162sMdResB25mUv+vWMF5NoAjNf09TeGlE7ZpszZWSD3winycicLJw72yeVsoCn/2kOhEuCvEShMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.10", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.10", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.9", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.9.tgz", + "integrity": "sha512-cp447VUsGS07+n1Dqf7YSQ8maeJrjEhaDxTm1ZefbqDtypHBC5GzGMQbklR6IPR13Y8OAJRHZWEMtZipJLCttg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/browserslist": { + "version": "4.28.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", + "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.44", + "caniuse-lite": "^1.0.30001806", + "electron-to-chromium": "^1.5.393", + "node-releases": "^2.0.51", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.399", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.399.tgz", + "integrity": "sha512-lEcqhErbHjXRvd41rnWLpzbyU/IXfIYo7QwaFWmxGeLiLyY2TBCdHnWY88vB+p3ubnihRypDm66panXl7TylLA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.8.0.tgz", + "integrity": "sha512-nuKKvN+oIBO0koN7Tm7dlkmnkc21mtt0QJLwAKzjLq14y6lRTdVG36MZHJ8eQHwdJMwZbQNMlPOYedMq/oVJvQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.7.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.2", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.3.tgz", + "integrity": "sha512-5EMmLCV98Pi4o/f/3DP/v/tNqLHMIc9I8LKClNDWhZ9JTho89/kQcitCXQBMG7sAfVRK0Ie3T2EDOzp1YXYiVA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^9 || ^10" + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/hosted-git-info": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.3.tgz", + "integrity": "sha512-HVJyzUrLIL1c0QmviVh5E8VGyUS7xCFPS6yydaVd1UegW+ibV/CohqTH9MkOLDp5o+rb82DMo77PTuc9F/8GKw==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.1", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/license-checker-rseidelsohn": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/license-checker-rseidelsohn/-/license-checker-rseidelsohn-4.4.2.tgz", + "integrity": "sha512-Sf8WaJhd2vELvCne+frS9AXqnY/vv591s2/nZcJDwTnoNgltG4mAmoenffVb8L2YPRYbxARLyrHJBC38AVfpuA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "chalk": "4.1.2", + "debug": "^4.3.4", + "lodash.clonedeep": "^4.5.0", + "mkdirp": "^1.0.4", + "nopt": "^7.2.0", + "read-installed-packages": "^2.0.1", + "semver": "^7.3.5", + "spdx-correct": "^3.1.1", + "spdx-expression-parse": "^3.0.1", + "spdx-satisfies": "^5.0.1", + "treeify": "^1.1.0" + }, + "bin": { + "license-checker-rseidelsohn": "bin/license-checker-rseidelsohn.js" + }, + "engines": { + "node": ">=18", + "npm": ">=8" + } + }, + "node_modules/license-checker-rseidelsohn/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", + "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.8" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/react-number-format": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/react-number-format/-/react-number-format-5.4.5.tgz", + "integrity": "sha512-y8O2yHHj3w0aE9XO8d2BCcUOOdQTRSVq+WIuMlLVucAm5XNjJAy+BoOJiuQMldVYVOKTMyvVNfnbl2Oqp+YxGw==", + "license": "MIT", + "peerDependencies": { + "react": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/read-installed-packages": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/read-installed-packages/-/read-installed-packages-2.0.1.tgz", + "integrity": "sha512-t+fJOFOYaZIjBpTVxiV8Mkt7yQyy4E6MSrrnt5FmPd4enYvpU/9DYGirDmN1XQwkfeuWIhM/iu0t2rm6iSr0CA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^3.1.0", + "debug": "^4.3.4", + "read-package-json": "^6.0.0", + "semver": "2 || 3 || 4 || 5 || 6 || 7", + "slide": "~1.1.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.2" + } + }, + "node_modules/read-package-json": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", + "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", + "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rolldown": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.1.tgz", + "integrity": "sha512-4FKJhg8d3OiyQOA6Q1Q0hoFFpW9/OoX+VsHzpECsdsIZoOArrAK90gl59YK/Z+gnDel45bgJZK03ozH/9bCqEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.142.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.2.1", + "@rolldown/binding-darwin-arm64": "1.2.1", + "@rolldown/binding-darwin-x64": "1.2.1", + "@rolldown/binding-freebsd-x64": "1.2.1", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.1", + "@rolldown/binding-linux-arm64-gnu": "1.2.1", + "@rolldown/binding-linux-arm64-musl": "1.2.1", + "@rolldown/binding-linux-ppc64-gnu": "1.2.1", + "@rolldown/binding-linux-s390x-gnu": "1.2.1", + "@rolldown/binding-linux-x64-gnu": "1.2.1", + "@rolldown/binding-linux-x64-musl": "1.2.1", + "@rolldown/binding-openharmony-arm64": "1.2.1", + "@rolldown/binding-wasm32-wasi": "1.2.1", + "@rolldown/binding-win32-arm64-msvc": "1.2.1", + "@rolldown/binding-win32-x64-msvc": "1.2.1" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "*" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", + "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-find-index": "^1.0.2", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/spdx-ranges": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", + "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", + "dev": true, + "license": "(MIT AND CC-BY-3.0)" + }, + "node_modules/spdx-satisfies": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-5.0.1.tgz", + "integrity": "sha512-Nwor6W6gzFp8XX4neaKQ7ChV4wmpSh2sSDemMFSzHxpTw460jxFYeOn+jq4ybnSSw/5sc3pjka9MQPouksQNpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-compare": "^1.0.0", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tabbable": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.5.0.tgz", + "integrity": "sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==", + "license": "MIT" + }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "7.4.10", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.10.tgz", + "integrity": "sha512-GgouD1B+sWwvkaEq8vXC15DjQitxbvs12oIXELpconwm+Tg3zfcEv4jgzq3vtKverDXsg3VI8aRgNL2Nra0Iog==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.10" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.4.10", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.10.tgz", + "integrity": "sha512-KnQjp53ZekKgm/r3l+u8kJGGzYgrWdP8+Mql7a4vijh2WE0IrZWspQj/TpTxDho/YxO+AnOZnIjQcCD+q6iJsw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.8.0.tgz", + "integrity": "sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA==", + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.65.0.tgz", + "integrity": "sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.65.0", + "@typescript-eslint/parser": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0", + "@typescript-eslint/utils": "8.65.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/undici": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", + "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vite": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.0.tgz", + "integrity": "sha512-pn+CFpM0lwDeKwmOq1ZaBK/9sjorZcgqxki6MbY/jPEVd9vichIlmlD4HmQ5wdP5EgqQCFRaACBxMC7uEGc6lQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.23", + "rolldown": "~1.2.0", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", + "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.10", + "@vitest/mocker": "4.1.10", + "@vitest/pretty-format": "4.1.10", + "@vitest/runner": "4.1.10", + "@vitest/snapshot": "4.1.10", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.10", + "@vitest/browser-preview": "4.1.10", + "@vitest/browser-webdriverio": "4.1.10", + "@vitest/coverage-istanbul": "4.1.10", + "@vitest/coverage-v8": "4.1.10", + "@vitest/ui": "4.1.10", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } } } } diff --git a/desktop/package.json b/desktop/package.json index ec701f5..2bb9787 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -1,9 +1,20 @@ { "name": "vidxp-desktop", "private": true, - "version": "0.3.0", + "version": "0.4.0-b.1", "type": "module", "scripts": { + "dev": "vite", + "prebuild": "npm run sync:branding", + "build": "tsc -b && vite build", + "typecheck": "tsc -b --pretty false", + "lint": "eslint . --max-warnings 0", + "test": "vitest run", + "check": "npm run typecheck && npm run lint && npm run test && npm run build", + "notices:write": "node scripts/generate-notices.mjs --write", + "notices:check": "node scripts/generate-notices.mjs", + "model-catalog:write": "uv run --frozen python scripts/model-catalog.py --write", + "model-catalog:check": "uv run --frozen python scripts/model-catalog.py --check", "tauri": "tauri", "sync:branding": "node scripts/sync-branding.mjs", "icons": "npm run sync:branding && tauri icon ../docs/images/logo.png --output src-tauri/icons", @@ -14,7 +25,31 @@ "sidecar:windows": "powershell -ExecutionPolicy Bypass -File scripts/fetch-uv.ps1", "sidecar:unix": "bash scripts/fetch-uv.sh" }, + "dependencies": { + "@mantine/core": "9.5.0", + "@tabler/icons-react": "3.46.0", + "@tauri-apps/api": "2.11.1", + "react": "19.2.8", + "react-dom": "19.2.8" + }, "devDependencies": { - "@tauri-apps/cli": "2.11.4" + "@eslint/js": "10.0.1", + "@tauri-apps/cli": "2.11.4", + "@testing-library/jest-dom": "7.0.0", + "@testing-library/react": "16.3.2", + "@testing-library/user-event": "14.6.1", + "@types/node": "26.0.0", + "@types/react": "19.2.18", + "@types/react-dom": "19.2.4", + "@vitejs/plugin-react": "6.0.5", + "eslint": "10.8.0", + "eslint-plugin-react-hooks": "7.1.1", + "eslint-plugin-react-refresh": "0.5.3", + "jsdom": "29.1.1", + "license-checker-rseidelsohn": "4.4.2", + "typescript": "6.0.3", + "typescript-eslint": "8.65.0", + "vite": "8.2.0", + "vitest": "4.1.10" } } diff --git a/desktop/runtime-constraints.txt b/desktop/runtime-constraints.txt deleted file mode 100644 index d564a7c..0000000 --- a/desktop/runtime-constraints.txt +++ /dev/null @@ -1,499 +0,0 @@ -# This file was autogenerated by uv via the following command: -# uv export --frozen --extra local-worker --extra frontend --no-dev --no-emit-project --no-hashes --format requirements-txt --output-file desktop/runtime-constraints.txt -aiohappyeyeballs==2.7.1 - # via aiohttp -aiohttp==3.14.3 - # via kubernetes -aiosignal==1.4.0 - # via aiohttp -altair==6.2.2 - # via streamlit -annotated-doc==0.0.5 - # via typer -annotated-types==0.8.0 - # via pydantic -anyio==4.14.2 - # via - # httpx - # httpx2 - # openai - # starlette - # streamlit - # watchfiles -attrs==26.1.0 - # via - # aiohttp - # jsonschema - # referencing -av==18.0.0 - # via faster-whisper -bcrypt==5.0.0 - # via chromadb -blinker==1.9.0 - # via streamlit -build==1.5.0 - # via chromadb -certifi==2026.7.22 - # via - # httpcore - # httpx - # kubernetes - # requests -charset-normalizer==3.4.9 - # via requests -chromadb==1.5.9 - # via vidxp -click==8.4.2 - # via - # huggingface-hub - # streamlit - # uvicorn -colorama==0.4.6 ; os_name == 'nt' or sys_platform == 'win32' - # via - # build - # click - # tqdm - # typer -ctranslate2==4.8.1 - # via faster-whisper -dbos==2.28.0 - # via vidxp -distro==1.9.0 - # via openai -durationpy==0.10 - # via kubernetes -faster-whisper==1.2.1 - # via vidxp -filelock==3.32.0 - # via - # huggingface-hub - # torch - # vidxp -flatbuffers==25.12.19 - # via onnxruntime -frozenlist==1.8.0 - # via - # aiohttp - # aiosignal -fsspec==2026.7.0 - # via - # huggingface-hub - # torch -genai-prices==0.0.72 - # via pydantic-ai-slim -gitdb==4.0.12 - # via gitpython -gitpython==3.1.57 - # via streamlit -googleapis-common-protos==1.75.0 - # via opentelemetry-exporter-otlp-proto-grpc -greenlet==3.5.4 - # via sqlalchemy -griffelib==2.1.0 - # via pydantic-ai-slim -grpcio==1.83.0 - # via - # chromadb - # opentelemetry-exporter-otlp-proto-grpc -h11==0.16.0 - # via - # httpcore - # httpcore2 - # uvicorn -hf-xet==1.5.2 ; platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64' - # via huggingface-hub -httpcore==1.0.9 - # via httpx -httpcore2==2.9.1 - # via httpx2 -httptools==0.8.0 - # via - # streamlit - # uvicorn -httpx==0.28.1 - # via - # chromadb - # huggingface-hub - # openai - # pydantic-ai-slim - # pydantic-graph -httpx2==2.9.1 - # via genai-prices -huggingface-hub==1.25.1 - # via - # faster-whisper - # sentence-transformers - # tokenizers - # transformers - # vidxp -idna==3.18 - # via - # anyio - # httpx - # httpx2 - # requests - # yarl -importlib-resources==7.1.0 - # via chromadb -itsdangerous==2.2.0 - # via streamlit -jinja2==3.1.6 - # via - # altair - # pydeck - # torch -jiter==0.16.0 - # via openai -joblib==1.5.3 - # via scikit-learn -jsonschema==4.26.0 - # via - # altair - # chromadb -jsonschema-specifications==2025.9.1 - # via jsonschema -kubernetes==36.0.3 - # via chromadb -logfire-api==4.39.0 - # via pydantic-graph -markdown-it-py==4.2.0 - # via rich -markupsafe==3.0.3 - # via jinja2 -mdurl==0.1.2 - # via markdown-it-py -mmh3==5.2.1 - # via chromadb -mpmath==1.3.0 - # via sympy -multidict==6.7.1 - # via - # aiohttp - # yarl -narwhals==2.24.0 - # via - # altair - # scikit-learn -networkx==3.6.1 - # via torch -numpy==2.4.6 ; python_full_version < '3.12' - # via - # chromadb - # ctranslate2 - # onnxruntime - # opencv-python-headless - # pandas - # pydeck - # scikit-learn - # scipy - # sentence-transformers - # streamlit - # transformers - # vidxp -numpy==2.5.1 ; python_full_version >= '3.12' - # via - # chromadb - # ctranslate2 - # onnxruntime - # opencv-python-headless - # pandas - # pydeck - # scikit-learn - # scipy - # sentence-transformers - # streamlit - # transformers - # vidxp -oauthlib==3.3.1 - # via requests-oauthlib -onnxruntime==1.28.0 - # via - # chromadb - # faster-whisper -openai==2.50.0 - # via pydantic-ai-slim -opencv-python-headless==5.0.0.93 - # via vidxp -opentelemetry-api==1.44.0 - # via - # chromadb - # opentelemetry-exporter-otlp-proto-grpc - # opentelemetry-sdk - # opentelemetry-semantic-conventions - # pydantic-ai-slim -opentelemetry-exporter-otlp-proto-common==1.44.0 - # via opentelemetry-exporter-otlp-proto-grpc -opentelemetry-exporter-otlp-proto-grpc==1.44.0 - # via chromadb -opentelemetry-proto==1.44.0 - # via - # opentelemetry-exporter-otlp-proto-common - # opentelemetry-exporter-otlp-proto-grpc -opentelemetry-sdk==1.44.0 - # via - # chromadb - # opentelemetry-exporter-otlp-proto-grpc -opentelemetry-semantic-conventions==0.65b0 - # via opentelemetry-sdk -orjson==3.11.9 - # via chromadb -overrides==7.7.0 - # via chromadb -packaging==26.2 - # via - # altair - # build - # huggingface-hub - # onnxruntime - # pooch - # streamlit - # transformers - # vidxp -pandas==3.0.5 - # via streamlit -pillow==12.3.0 - # via - # streamlit - # vidxp -platformdirs==4.11.0 - # via - # pooch - # vidxp -pooch==1.9.0 - # via vidxp -propcache==0.5.2 - # via - # aiohttp - # yarl -protobuf==7.35.1 - # via - # googleapis-common-protos - # onnxruntime - # opentelemetry-proto - # streamlit -psutil==7.2.2 - # via vidxp -psycopg==3.3.4 - # via dbos -psycopg-binary==3.3.4 ; implementation_name != 'pypy' - # via psycopg -pyarrow==24.0.0 - # via streamlit -pybase64==1.4.3 - # via chromadb -pydantic==2.13.4 - # via - # chromadb - # genai-prices - # openai - # pydantic-ai-slim - # pydantic-graph - # pydantic-settings - # vidxp -pydantic-ai-slim==2.20.0 - # via vidxp -pydantic-core==2.46.4 - # via pydantic -pydantic-graph==2.20.0 - # via pydantic-ai-slim -pydantic-settings==2.14.2 - # via - # chromadb - # vidxp -pydeck==0.9.3 - # via streamlit -pygments==2.20.0 - # via rich -pypika==0.51.1 - # via chromadb -pyproject-hooks==1.2.0 - # via build -python-dateutil==2.9.0.post0 - # via - # dbos - # kubernetes - # pandas -python-dotenv==1.2.2 - # via - # pydantic-settings - # uvicorn -python-multipart==0.0.32 - # via streamlit -pyyaml==6.0.3 - # via - # chromadb - # ctranslate2 - # dbos - # huggingface-hub - # kubernetes - # transformers - # uvicorn -referencing==0.37.0 - # via - # jsonschema - # jsonschema-specifications -regex==2026.7.19 - # via - # tiktoken - # transformers -requests==2.34.2 - # via - # kubernetes - # pooch - # requests-oauthlib - # streamlit - # tiktoken -requests-oauthlib==2.0.0 - # via kubernetes -rich==15.0.0 - # via - # chromadb - # typer - # vidxp -rpds-py==2026.6.3 - # via - # jsonschema - # referencing -safetensors==0.8.0 - # via transformers -scikit-learn==1.9.0 - # via sentence-transformers -scipy==1.17.1 ; python_full_version < '3.12' - # via - # scikit-learn - # sentence-transformers -scipy==1.18.0 ; python_full_version >= '3.12' - # via - # scikit-learn - # sentence-transformers -sentence-transformers==5.6.1 - # via vidxp -setuptools==83.0.0 - # via - # ctranslate2 - # torch -shellingham==1.5.4 - # via typer -six==1.17.0 - # via - # kubernetes - # python-dateutil -smmap==5.0.3 - # via gitdb -sniffio==1.3.1 - # via openai -sqlalchemy==2.0.51 - # via - # dbos - # vidxp -starlette==1.3.1 - # via streamlit -streamlit==1.60.0 - # via vidxp -sympy==1.14.0 - # via torch -tenacity==9.1.4 - # via - # chromadb - # streamlit -threadpoolctl==3.6.0 - # via scikit-learn -tiktoken==0.13.0 - # via pydantic-ai-slim -tokenizers==0.22.2 - # via - # chromadb - # faster-whisper - # transformers -toml==0.10.2 - # via streamlit -torch==2.13.0 ; sys_platform != 'linux' and sys_platform != 'win32' - # via - # sentence-transformers - # vidxp -torch==2.13.0+cpu ; sys_platform == 'linux' or sys_platform == 'win32' - # via - # sentence-transformers - # vidxp -tqdm==4.70.0 - # via - # chromadb - # faster-whisper - # huggingface-hub - # openai - # sentence-transformers - # transformers -transformers==5.14.1 - # via - # sentence-transformers - # vidxp -truststore==0.10.4 - # via - # httpcore2 - # httpx2 -typer==0.27.0 - # via - # chromadb - # transformers - # typer-slim - # vidxp -typer-slim==0.24.0 - # via dbos -typing-extensions==4.16.0 - # via - # aiohttp - # aiosignal - # altair - # anyio - # chromadb - # grpcio - # httpx2 - # huggingface-hub - # openai - # opentelemetry-api - # opentelemetry-exporter-otlp-proto-grpc - # opentelemetry-sdk - # opentelemetry-semantic-conventions - # psycopg - # pydantic - # pydantic-core - # referencing - # sentence-transformers - # sqlalchemy - # starlette - # streamlit - # torch - # typing-inspection -typing-inspection==0.4.2 - # via - # pydantic - # pydantic-ai-slim - # pydantic-graph - # pydantic-settings -tzdata==2026.3 ; sys_platform == 'emscripten' or sys_platform == 'win32' - # via - # pandas - # psycopg -urllib3==2.7.0 - # via - # kubernetes - # requests -uvicorn==0.51.0 - # via - # chromadb - # streamlit -uvloop==0.22.1 ; platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32' - # via uvicorn -watchdog==6.0.0 ; sys_platform != 'darwin' - # via streamlit -watchfiles==1.2.0 - # via uvicorn -websocket-client==1.9.0 - # via kubernetes -websockets==16.1.1 - # via - # dbos - # streamlit - # uvicorn -yarl==1.24.5 - # via aiohttp diff --git a/desktop/runtime-manifest.json b/desktop/runtime-manifest.json index 0478be3..be32bcd 100644 --- a/desktop/runtime-manifest.json +++ b/desktop/runtime-manifest.json @@ -1,10 +1,9 @@ { "schema_version": 1, - "desktop_version": "0.3.0", + "desktop_version": "0.4.0-b.1", "package_name": "vidxp", - "package_version": "0.3.0", + "package_version": "0.4.0-b.1", "dependency_index": "https://pypi.org/simple", - "dependency_constraints_sha256": "d3ed16906841952017f112903356bfe433a8515a37aa3f56e4af4dfa1f985835", "python_version": "3.14.6", "uv_version": "0.12.0", "surfaces": { diff --git a/desktop/scripts/generate-notices.mjs b/desktop/scripts/generate-notices.mjs new file mode 100644 index 0000000..0063425 --- /dev/null +++ b/desktop/scripts/generate-notices.mjs @@ -0,0 +1,158 @@ +import { execFileSync } from 'node:child_process'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { + mkdtempSync, + readFileSync, + readdirSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { createHash } from 'node:crypto'; +import { tmpdir } from 'node:os'; + +const desktop = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +const repository = resolve(desktop, '..'); +const temporary = mkdtempSync(join(tmpdir(), 'vidxp-notices-')); +const rustNotices = join(temporary, 'rust.txt'); +const destination = join(desktop, 'THIRD_PARTY_NOTICES.txt'); +const cargoLock = join(desktop, 'src-tauri', 'Cargo.lock'); +const preferredArtifact = /^(licen[cs]e|copying|notice)(?:[._-].*)?$/i; +const documentationArtifact = /^(readme|changelog)(?:[._-].*)?$/i; + +const vendoredArtifacts = new Map([ + ['react-remove-scroll-bar@2.3.8', { + path: join(desktop, 'licenses', 'npm', 'react-remove-scroll-bar-2.3.8-LICENSE.txt'), + source: 'https://github.com/theKashey/react-remove-scroll-bar/blob/8ca9ba5ea52de03308fe8ced94f7b159a44d28ff/LICENSE', + sha256: 'a79aae0c0f21990d9d963bb3c5a79cdcea9a46f8523ba55c58d7fe776b6ebc84', + }], +]); + +function packageRoot(metadata) { + if (!metadata.licenseFile) return null; + return dirname(metadata.licenseFile); +} + +function publishedLicenseArtifacts(metadata) { + const root = packageRoot(metadata); + if (!root) return []; + const preferred = readdirSync(root, { withFileTypes: true }) + .filter((entry) => entry.isFile() && preferredArtifact.test(entry.name)) + .map((entry) => join(root, entry.name)) + .sort((left, right) => left.localeCompare(right)); + if (preferred.length > 0) return preferred; + const selected = metadata.licenseFile; + return selected && !documentationArtifact.test(selected.split(/[\\/]/).at(-1) ?? '') + ? [selected] + : []; +} + +function frontendLicenseText(identity, metadata) { + const artifacts = publishedLicenseArtifacts(metadata); + if (artifacts.length > 0) { + return artifacts.map((path) => readFileSync(path, 'utf8').trim()).join('\n\n'); + } + const vendored = vendoredArtifacts.get(identity); + if (vendored) { + const contents = readFileSync(vendored.path, 'utf8').replace(/\r\n?/g, '\n').trim(); + const actual = createHash('sha256').update(`${contents}\n`, 'utf8').digest('hex'); + if (actual !== vendored.sha256) { + throw new Error(`${identity} vendored license digest ${actual} does not match ${vendored.sha256}.`); + } + return `Vendored verbatim upstream license for ${identity}\nSource: ${vendored.source}\nSHA-256: ${vendored.sha256}\n\n${contents}`; + } + throw new Error(`${identity} has no published license artifact and no exact, provenance-pinned vendored exception for ${metadata.licenses}.`); +} + +try { + const lockBefore = readFileSync(cargoLock); + execFileSync( + 'cargo', + [ + 'about', 'generate', '--locked', '--frozen', + '--manifest-path', 'src-tauri/Cargo.toml', + '-c', 'about.toml', '-o', rustNotices, 'about.hbs', + ], + { cwd: desktop, stdio: 'inherit' }, + ); + const lockAfter = readFileSync(cargoLock); + if (!lockBefore.equals(lockAfter)) { + throw new Error('cargo-about modified desktop/src-tauri/Cargo.lock.'); + } + + const checker = join( + desktop, + 'node_modules', + 'license-checker-rseidelsohn', + 'bin', + 'license-checker-rseidelsohn.js', + ); + const npmInventory = JSON.parse(execFileSync( + process.execPath, + [checker, '--production', '--json'], + { cwd: desktop, encoding: 'utf8' }, + )); + const frontend = ['FRONTEND DEPENDENCIES', '=====================', '']; + for (const [identity, metadata] of Object.entries(npmInventory).sort(([left], [right]) => left.localeCompare(right))) { + if (identity.startsWith('vidxp-desktop@')) continue; + const licenses = String(metadata.licenses ?? ''); + const source = String(metadata.repository ?? ''); + if (!licenses || /unknown|unlicensed/i.test(licenses)) { + throw new Error(`${identity} has an unresolved shipped license.`); + } + if (!source) throw new Error(`${identity} has no published source repository.`); + frontend.push('-------------------------------------------------------------------------------'); + frontend.push(`${identity} | ${licenses} | ${source}`); + frontend.push(''); + frontend.push(frontendLicenseText(identity, metadata)); + frontend.push(''); + } + + const sidecars = JSON.parse(readFileSync(join(desktop, 'sidecars.json'), 'utf8')); + const projectLicense = readFileSync(join(repository, 'LICENSE'), 'utf8').trim(); + const uvMitLicense = readFileSync(join(desktop, 'licenses', 'uv-LICENSE-MIT.txt'), 'utf8').trim(); + const artifact = [ + 'VidXP Desktop Legal Notices', + '===========================', + '', + 'This artifact is generated from locked production dependency graphs and bundled sidecar metadata.', + '', + 'VIDXP PROJECT LICENSE', + '=====================', + 'VidXP Desktop and VidXP | MIT | https://github.com/grayhatdevelopers/vidxp', + '', + projectLicense, + '', + 'BUNDLED EXECUTABLES', + '===================', + `uv ${sidecars.uv_version} | MIT OR Apache-2.0 | https://github.com/astral-sh/uv/tree/${sidecars.uv_version}`, + 'The complete MIT terms from the pinned uv release follow. The complete Apache-2.0 terms are included in the Rust dependency section below.', + '', + uvMitLicense, + '', + readFileSync(rustNotices, 'utf8') + .replace(/^\- vidxp-desktop [^\n]+\n/m, '') + .trim(), + '', + frontend.join('\n').trim(), + '', + ].join('\n').replace(/\r\n?/g, '\n').replace(/[ \t]+$/gm, ''); + if (process.argv.includes('--write')) { + writeFileSync(destination, artifact, 'utf8'); + } else if (readFileSync(destination, 'utf8').replace(/\r\n?/g, '\n') !== artifact) { + const generated = join(temporary, 'THIRD_PARTY_NOTICES.txt'); + writeFileSync(generated, artifact, 'utf8'); + try { + execFileSync( + 'git', + ['diff', '--no-index', '--', destination, generated], + { cwd: desktop, stdio: 'inherit' }, + ); + } catch (error) { + if (error?.status !== 1) throw error; + } + throw new Error('THIRD_PARTY_NOTICES.txt is stale; run npm run notices:write.'); + } +} finally { + rmSync(temporary, { recursive: true, force: true }); +} diff --git a/desktop/scripts/model-catalog.py b/desktop/scripts/model-catalog.py new file mode 100644 index 0000000..be30acc --- /dev/null +++ b/desktop/scripts/model-catalog.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[2] +sys.path.insert(0, str(ROOT / "src")) + +from vidxp.local_probe import desktop_model_cache_catalog # noqa: E402 + + +CATALOG_PATH = ROOT / "desktop" / "model-cache-catalog.json" + + +def rendered_catalog() -> str: + return json.dumps( + desktop_model_cache_catalog(), + indent=2, + ensure_ascii=False, + ) + "\n" + + +def main() -> int: + parser = argparse.ArgumentParser() + mode = parser.add_mutually_exclusive_group(required=True) + mode.add_argument("--write", action="store_true") + mode.add_argument("--check", action="store_true") + arguments = parser.parse_args() + derived = rendered_catalog() + if arguments.write: + CATALOG_PATH.write_text(derived, encoding="utf-8", newline="\n") + return 0 + if CATALOG_PATH.read_text(encoding="utf-8") != derived: + raise SystemExit( + "desktop/model-cache-catalog.json is stale; run npm run " + "model-catalog:write from desktop/." + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/desktop/scripts/sync-branding.mjs b/desktop/scripts/sync-branding.mjs index 218f170..98968d2 100644 --- a/desktop/scripts/sync-branding.mjs +++ b/desktop/scripts/sync-branding.mjs @@ -1,10 +1,12 @@ -import { copyFileSync } from "node:fs"; +import { copyFileSync, mkdirSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const desktopRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const source = resolve(desktopRoot, "../docs/images/logo.png"); -const favicon = resolve(desktopRoot, "web/icon.png"); +const publicDirectory = resolve(desktopRoot, "public"); +const favicon = resolve(publicDirectory, "icon.png"); +mkdirSync(publicDirectory, { recursive: true }); copyFileSync(source, favicon); console.log("Synced the VidXP desktop favicon from the shared icon."); diff --git a/desktop/scripts/verify-windows-gui.ps1 b/desktop/scripts/verify-windows-gui.ps1 new file mode 100644 index 0000000..524724e --- /dev/null +++ b/desktop/scripts/verify-windows-gui.ps1 @@ -0,0 +1,14 @@ +$path = "desktop/src-tauri/target/release/vidxp-desktop.exe" +$stream = [System.IO.File]::OpenRead($path) +try { + $reader = [System.IO.BinaryReader]::new($stream) + $stream.Position = 0x3c + $peOffset = $reader.ReadInt32() + $stream.Position = $peOffset + 4 + 20 + 68 + $subsystem = $reader.ReadUInt16() + if ($subsystem -ne 2) { + throw "Expected Windows GUI subsystem 2, found $subsystem." + } +} finally { + $stream.Dispose() +} diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock index 1ca8142..8f30ed1 100644 --- a/desktop/src-tauri/Cargo.lock +++ b/desktop/src-tauri/Cargo.lock @@ -230,7 +230,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84790c55b5704b0d35130bf16a4ce22a8e70eb0ea773522557524d9a4852663d" dependencies = [ - "nix", + "nix 0.30.1", "rand", ] @@ -1647,7 +1647,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.61.2", ] [[package]] @@ -2152,6 +2152,18 @@ dependencies = [ "libc", ] +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags 2.13.1", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "num-conv" version = "0.2.2" @@ -2718,6 +2730,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "process-wrap" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e842efad9119158434d193c6682e2ebee4b44d6ad801d7b349623b3f57cdf55" +dependencies = [ + "indexmap 2.14.0", + "nix 0.31.3", + "tracing", + "windows 0.62.2", +] + [[package]] name = "quick-xml" version = "0.38.4" @@ -3495,8 +3519,8 @@ dependencies = [ "tao-macros", "unicode-segmentation", "url", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", "windows-version", "x11-dl", ] @@ -3566,7 +3590,7 @@ dependencies = [ "webkit2gtk", "webview2-com", "window-vibrancy", - "windows", + "windows 0.61.3", ] [[package]] @@ -3728,7 +3752,7 @@ dependencies = [ "tauri-plugin", "thiserror 2.0.19", "url", - "windows", + "windows 0.61.3", "zbus", ] @@ -3769,6 +3793,22 @@ dependencies = [ "zbus", ] +[[package]] +name = "tauri-plugin-store" +version = "2.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6708afbe549f176b712066e71648ba8fafba20789453718260c7ca356733cb0c" +dependencies = [ + "dunce", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.19", + "tokio", + "tracing", +] + [[package]] name = "tauri-runtime" version = "2.11.3" @@ -3791,7 +3831,7 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows", + "windows 0.61.3", ] [[package]] @@ -3816,7 +3856,7 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows", + "windows 0.61.3", "wry", ] @@ -4000,9 +4040,21 @@ dependencies = [ "mio", "pin-project-lite", "socket2", + "tokio-macros", "windows-sys 0.61.2", ] +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "tokio-util" version = "0.7.19" @@ -4373,11 +4425,12 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vidxp-desktop" -version = "0.3.0" # x-release-please-version +version = "0.4.0-b.1" dependencies = [ "atomic-write-file", "hex", "log", + "process-wrap", "serde", "serde_json", "sha2 0.11.0", @@ -4388,7 +4441,9 @@ dependencies = [ "tauri-plugin-opener", "tauri-plugin-shell", "tauri-plugin-single-instance", - "wait-timeout", + "tauri-plugin-store", + "which", + "windows 0.62.2", ] [[package]] @@ -4411,15 +4466,6 @@ dependencies = [ "libc", ] -[[package]] -name = "wait-timeout" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" -dependencies = [ - "libc", -] - [[package]] name = "walkdir" version = "2.5.0" @@ -4596,8 +4642,8 @@ checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", "windows-implement", "windows-interface", ] @@ -4620,8 +4666,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" dependencies = [ "thiserror 2.0.19", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", +] + +[[package]] +name = "which" +version = "8.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3ef584124b911bcc3875c2f1472e80f24361ceb789bd1c62b3e9a3df9ff43c" +dependencies = [ + "libc", ] [[package]] @@ -4676,11 +4731,23 @@ version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-collections", - "windows-core", - "windows-future", + "windows-collections 0.2.0", + "windows-core 0.61.2", + "windows-future 0.2.1", "windows-link 0.1.3", - "windows-numerics", + "windows-numerics 0.2.0", +] + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections 0.3.2", + "windows-core 0.62.2", + "windows-future 0.3.2", + "windows-numerics 0.3.1", ] [[package]] @@ -4689,7 +4756,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core", + "windows-core 0.61.2", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core 0.62.2", ] [[package]] @@ -4701,8 +4777,21 @@ dependencies = [ "windows-implement", "windows-interface", "windows-link 0.1.3", - "windows-result", - "windows-strings", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", ] [[package]] @@ -4711,9 +4800,20 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core", + "windows-core 0.61.2", "windows-link 0.1.3", - "windows-threading", + "windows-threading 0.1.0", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", + "windows-threading 0.2.1", ] [[package]] @@ -4756,10 +4856,20 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core", + "windows-core 0.61.2", "windows-link 0.1.3", ] +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -4769,6 +4879,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-strings" version = "0.4.2" @@ -4778,6 +4897,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -4871,6 +4999,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-version" version = "0.1.7" @@ -5105,8 +5242,8 @@ dependencies = [ "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", "windows-version", "x11-dl", ] diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml index d6f17a7..8a20d1e 100644 --- a/desktop/src-tauri/Cargo.toml +++ b/desktop/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vidxp-desktop" -version = "0.3.0" # x-release-please-version +version = "0.4.0-b.1" # x-release-please-version description = "The VidXP desktop launcher and local runtime supervisor" edition = "2024" rust-version = "1.97" @@ -12,12 +12,14 @@ crate-type = ["staticlib", "cdylib", "rlib"] [build-dependencies] serde_json = "1.0.151" +sha2 = "0.11.0" tauri-build = { version = "2.6.3", features = [] } [dependencies] atomic-write-file = "0.3.0" hex = "0.4.3" log = "0.4.29" +process-wrap = { version = "9.1.0", features = ["std"] } serde = { version = "1.0.229", features = ["derive"] } serde_json = "1.0.151" sha2 = "0.11.0" @@ -27,4 +29,8 @@ tauri-plugin-dialog = "2.7.2" tauri-plugin-opener = "2.5.4" tauri-plugin-shell = "2.3.5" tauri-plugin-single-instance = "2.4.3" -wait-timeout = "0.2.1" +tauri-plugin-store = "2.4.4" +which = "8.0.0" + +[target.'cfg(windows)'.dependencies] +windows = { version = "0.62.2", features = ["Win32_System_Threading"] } diff --git a/desktop/src-tauri/build.rs b/desktop/src-tauri/build.rs index ae6d059..f5c6f33 100644 --- a/desktop/src-tauri/build.rs +++ b/desktop/src-tauri/build.rs @@ -1,5 +1,9 @@ fn main() { - let manifest: serde_json::Value = + use sha2::{Digest, Sha256}; + use std::fmt::Write; + use std::path::{Path, PathBuf}; + + let mut manifest: serde_json::Value = serde_json::from_slice(include_bytes!("../runtime-manifest.json")) .expect("desktop/runtime-manifest.json must be valid JSON"); let expected = manifest["uv_version"] @@ -11,7 +15,7 @@ fn main() { } else { "" }; - let sidecar = std::path::PathBuf::from("binaries").join(format!("uv-{target}{suffix}")); + let sidecar = PathBuf::from("binaries").join(format!("uv-{target}{suffix}")); let output = std::process::Command::new(&sidecar) .arg("--version") .output() @@ -29,5 +33,62 @@ fn main() { actual.trim(), expected ); + + let constraints = + PathBuf::from(std::env::var_os("OUT_DIR").expect("Cargo must provide OUT_DIR")) + .join("runtime-constraints.txt"); + let project = Path::new("../.."); + let export = std::process::Command::new(&sidecar) + .args([ + "export", + "--frozen", + "--extra", + "local-worker", + "--extra", + "frontend", + "--no-dev", + "--no-emit-project", + "--no-hashes", + "--format", + "requirements-txt", + "--project", + ]) + .arg(project) + .output() + .unwrap_or_else(|error| { + panic!( + "{} could not export the desktop runtime constraints: {error}", + sidecar.display() + ) + }); + assert!( + export.status.success(), + "{} failed to export the desktop runtime constraints: {}", + sidecar.display(), + String::from_utf8_lossy(&export.stderr).trim() + ); + let normalized = String::from_utf8(export.stdout) + .expect("the desktop runtime constraints must be UTF-8") + .replace("\r\n", "\n"); + std::fs::write(&constraints, normalized.as_bytes()) + .expect("Cargo must be able to normalize the desktop runtime constraints"); + let digest = Sha256::digest(normalized.as_bytes()).iter().fold( + String::with_capacity(64), + |mut encoded, byte| { + write!(&mut encoded, "{byte:02x}").expect("writing to a string cannot fail"); + encoded + }, + ); + manifest["dependency_constraints_sha256"] = serde_json::Value::String(digest); + let embedded_manifest = constraints.with_file_name("runtime-manifest.json"); + let mut serialized = serde_json::to_vec_pretty(&manifest) + .expect("desktop/runtime-manifest.json must be serializable"); + serialized.push(b'\n'); + std::fs::write(&embedded_manifest, serialized) + .expect("Cargo must be able to write the embedded runtime manifest"); + println!("cargo:rerun-if-changed=../../pyproject.toml"); + println!("cargo:rerun-if-changed=../../uv.lock"); + println!("cargo:rerun-if-changed=../runtime-manifest.json"); + tauri_build::build() } diff --git a/desktop/src-tauri/capabilities/main.json b/desktop/src-tauri/capabilities/main.json index f3f4ca4..4d4fe77 100644 --- a/desktop/src-tauri/capabilities/main.json +++ b/desktop/src-tauri/capabilities/main.json @@ -1,9 +1,17 @@ { "$schema": "../gen/schemas/desktop-schema.json", "identifier": "main-window", - "description": "The bundled setup interface; no shell or filesystem API is exposed.", + "description": "The bundled setup interface with narrow controls for its undecorated main window.", "windows": [ "main" ], - "permissions": [] + "permissions": [ + "core:window:allow-close", + "core:event:allow-listen", + "core:event:allow-unlisten", + "core:window:allow-is-maximized", + "core:window:allow-minimize", + "core:window:allow-start-dragging", + "core:window:allow-toggle-maximize" + ] } diff --git a/desktop/src-tauri/src/activation.rs b/desktop/src-tauri/src/activation.rs new file mode 100644 index 0000000..84eb199 --- /dev/null +++ b/desktop/src-tauri/src/activation.rs @@ -0,0 +1,121 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "snake_case")] +pub(crate) enum ActivationStage { + Prepared, + ProfileWritten, + Committed, + RollingBack, + RolledBack, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum ActivationRecovery { + RollBack, + Complete, +} + +pub(crate) fn activation_recovery( + stage: &ActivationStage, + candidate_authorities_match: bool, +) -> ActivationRecovery { + match stage { + ActivationStage::RollingBack | ActivationStage::RolledBack => ActivationRecovery::RollBack, + ActivationStage::Committed => ActivationRecovery::Complete, + ActivationStage::Prepared | ActivationStage::ProfileWritten + if candidate_authorities_match => + { + ActivationRecovery::Complete + } + ActivationStage::Prepared | ActivationStage::ProfileWritten => ActivationRecovery::RollBack, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + enum StartupResult { + Previous, + Candidate, + } + + #[derive(Clone, Copy, Debug)] + enum FailureBoundary { + FinalizeRename, + PreparedJournalWrite, + ProfileStoreSave, + ProfileWrittenJournalWrite, + ActivePointerWrite, + CommittedJournalWrite, + CommittedJournalRemoval, + RollbackMarkerWrite, + RollbackPointerWrite, + RollbackStoreSave, + RolledBackMarkerWrite, + RolledBackJournalRemoval, + } + + fn startup_after(boundary: FailureBoundary) -> StartupResult { + use FailureBoundary::*; + let (journal, authorities_match) = match boundary { + FinalizeRename | PreparedJournalWrite => return StartupResult::Previous, + ProfileStoreSave => (ActivationStage::Prepared, false), + ProfileWrittenJournalWrite => (ActivationStage::Prepared, false), + ActivePointerWrite => (ActivationStage::ProfileWritten, false), + CommittedJournalWrite => (ActivationStage::ProfileWritten, true), + CommittedJournalRemoval => (ActivationStage::Committed, true), + RollbackMarkerWrite => (ActivationStage::ProfileWritten, false), + RollbackPointerWrite | RollbackStoreSave | RolledBackMarkerWrite => { + (ActivationStage::RollingBack, true) + } + RolledBackJournalRemoval => (ActivationStage::RolledBack, true), + }; + match activation_recovery(&journal, authorities_match) { + ActivationRecovery::RollBack => StartupResult::Previous, + ActivationRecovery::Complete => StartupResult::Candidate, + } + } + + #[test] + fn every_activation_failure_boundary_has_an_unambiguous_startup_result() { + use FailureBoundary::*; + for boundary in [ + FinalizeRename, + PreparedJournalWrite, + ProfileStoreSave, + ProfileWrittenJournalWrite, + ActivePointerWrite, + RollbackMarkerWrite, + RollbackPointerWrite, + RollbackStoreSave, + RolledBackMarkerWrite, + RolledBackJournalRemoval, + ] { + assert_eq!( + startup_after(boundary), + StartupResult::Previous, + "{boundary:?}" + ); + } + for boundary in [CommittedJournalWrite, CommittedJournalRemoval] { + assert_eq!( + startup_after(boundary), + StartupResult::Candidate, + "{boundary:?}" + ); + } + } + + #[test] + fn rollback_markers_permanently_prevent_candidate_recommit() { + for stage in [ActivationStage::RollingBack, ActivationStage::RolledBack] { + assert_eq!( + activation_recovery(&stage, true), + ActivationRecovery::RollBack + ); + } + } +} diff --git a/desktop/src-tauri/src/background_process.rs b/desktop/src-tauri/src/background_process.rs new file mode 100644 index 0000000..220cd44 --- /dev/null +++ b/desktop/src-tauri/src/background_process.rs @@ -0,0 +1,541 @@ +use std::{ + io::Read, + process::{Command, ExitStatus, Stdio}, + sync::{ + Arc, + atomic::{AtomicBool, Ordering}, + mpsc::{self, Receiver, TryRecvError}, + }, + thread, + time::{Duration, Instant}, +}; + +use process_wrap::std::{ChildWrapper, CommandWrap}; + +#[cfg(windows)] +use process_wrap::std::JobObject; +#[cfg(unix)] +use process_wrap::std::ProcessGroup; + +#[derive(Clone, Copy)] +pub struct BackgroundPolicy { + pub timeout: Duration, + pub max_output_bytes: usize, +} + +#[derive(Clone, Default)] +pub struct CancellationToken(Arc); + +impl CancellationToken { + pub fn cancel(&self) { + self.0.store(true, Ordering::Release); + } + + pub fn is_cancelled(&self) -> bool { + self.0.load(Ordering::Acquire) + } + + pub fn same(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.0, &other.0) + } +} + +#[derive(Debug)] +pub struct BackgroundOutput { + pub status: ExitStatus, + pub stdout: Vec, + pub stderr: Vec, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum BackgroundErrorKind { + Start, + Monitor, + Timeout, + Cancelled, + Output, + OutputTooLarge, +} + +#[derive(Debug)] +pub struct BackgroundError { + pub kind: BackgroundErrorKind, + pub detail: String, +} + +struct OutputReader { + receiver: Receiver>>, + handle: Option>, + result: Option>>, +} + +impl OutputReader { + fn poll(&mut self) -> Result { + if self.result.is_some() { + return Ok(true); + } + match self.receiver.try_recv() { + Ok(result) => { + self.result = Some(result); + Ok(true) + } + Err(TryRecvError::Empty) => Ok(false), + Err(TryRecvError::Disconnected) => Err(BackgroundError { + kind: BackgroundErrorKind::Output, + detail: "an output reader stopped without returning its result".into(), + }), + } + } + + fn finish(mut self) -> Result, BackgroundError> { + let result = self.result.take().ok_or_else(|| BackgroundError { + kind: BackgroundErrorKind::Output, + detail: "an output reader was collected before it finished".into(), + })?; + self.handle + .take() + .expect("reader handle is retained until collection") + .join() + .map_err(|_| BackgroundError { + kind: BackgroundErrorKind::Output, + detail: "an output reader panicked".into(), + })?; + result.map_err(|error| BackgroundError { + kind: BackgroundErrorKind::Output, + detail: error.to_string(), + }) + } +} + +fn read_bounded(stream: impl Read + Send + 'static, limit: usize) -> OutputReader { + let (sender, receiver) = mpsc::sync_channel(1); + let handle = thread::spawn(move || { + let mut bytes = Vec::new(); + let result = stream + .take(limit as u64 + 1) + .read_to_end(&mut bytes) + .map(|_| bytes); + let _ = sender.send(result); + }); + OutputReader { + receiver, + handle: Some(handle), + result: None, + } +} + +fn wrapped(command: Command) -> CommandWrap { + let mut wrapped = CommandWrap::from(command); + #[cfg(windows)] + wrapped.wrap(JobObject); + #[cfg(unix)] + wrapped.wrap(ProcessGroup::leader()); + wrapped +} + +fn spawn_owned(command: Command) -> std::io::Result> { + let mut wrapped = wrapped(command); + #[cfg(windows)] + { + use std::os::windows::process::CommandExt; + use windows::Win32::System::Threading::{CREATE_NO_WINDOW, CREATE_SUSPENDED}; + + // JobObject starts the child suspended so it can establish whole-tree ownership before + // allowing it to run. Apply both flags at the final spawn boundary: every desktop command + // stays console-free without weakening job supervision. + wrapped.spawn_with(|command| { + command.creation_flags((CREATE_NO_WINDOW | CREATE_SUSPENDED).0); + command.spawn() + }) + } + #[cfg(not(windows))] + wrapped.spawn() +} + +pub struct OwnedChild(Box); + +impl OwnedChild { + #[cfg(test)] + pub fn id(&self) -> u32 { + self.0.id() + } + + pub fn try_wait(&mut self) -> std::io::Result> { + self.0.try_wait() + } + + pub fn terminate_and_reap(&mut self) { + let _ = self.0.kill(); + let _ = self.0.wait(); + } +} + +impl Drop for OwnedChild { + fn drop(&mut self) { + self.terminate_and_reap(); + } +} + +pub fn spawn_service(mut command: Command) -> Result { + command + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()); + spawn_owned(command) + .map(OwnedChild) + .map_err(|error| BackgroundError { + kind: BackgroundErrorKind::Start, + detail: error.to_string(), + }) +} + +fn finish_error( + child: &mut OwnedChild, + mut stdout: OutputReader, + mut stderr: OutputReader, + kind: BackgroundErrorKind, + detail: String, +) -> BackgroundError { + child.terminate_and_reap(); + let cleanup_deadline = Instant::now() + Duration::from_secs(2); + while Instant::now() < cleanup_deadline { + let stdout_done = stdout.poll().unwrap_or(true); + let stderr_done = stderr.poll().unwrap_or(true); + if stdout_done && stderr_done { + let _ = stdout.finish(); + let _ = stderr.finish(); + return BackgroundError { kind, detail }; + } + thread::sleep(Duration::from_millis(10)); + } + BackgroundError { + kind: BackgroundErrorKind::Output, + detail: format!( + "{detail}; owned process output pipes did not close after whole-tree termination" + ), + } +} + +fn run_with_monitor( + mut command: Command, + policy: BackgroundPolicy, + cancellation: Option<&CancellationToken>, + mut monitor: F, +) -> Result +where + F: FnMut(&mut OwnedChild) -> std::io::Result>, +{ + command + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + let mut child = spawn_owned(command) + .map(OwnedChild) + .map_err(|error| BackgroundError { + kind: BackgroundErrorKind::Start, + detail: error.to_string(), + })?; + let mut stdout = read_bounded( + child.0.stdout().take().expect("background stdout is piped"), + policy.max_output_bytes, + ); + let mut stderr = read_bounded( + child.0.stderr().take().expect("background stderr is piped"), + policy.max_output_bytes, + ); + let deadline = Instant::now() + policy.timeout; + let status = loop { + if cancellation.is_some_and(CancellationToken::is_cancelled) { + return Err(finish_error( + &mut child, + stdout, + stderr, + BackgroundErrorKind::Cancelled, + "the operation was cancelled".into(), + )); + } + if stdout.result.as_ref().is_some_and(|result| { + result + .as_ref() + .is_ok_and(|bytes| bytes.len() > policy.max_output_bytes) + }) || stderr.result.as_ref().is_some_and(|result| { + result + .as_ref() + .is_ok_and(|bytes| bytes.len() > policy.max_output_bytes) + }) { + return Err(finish_error( + &mut child, + stdout, + stderr, + BackgroundErrorKind::OutputTooLarge, + format!( + "the operation returned more than {} bytes per output stream", + policy.max_output_bytes + ), + )); + } + if let Err(error) = stdout.poll().and_then(|_| stderr.poll()) { + return Err(finish_error( + &mut child, + stdout, + stderr, + error.kind, + error.detail, + )); + } + if Instant::now() >= deadline { + return Err(finish_error( + &mut child, + stdout, + stderr, + BackgroundErrorKind::Timeout, + format!( + "the operation exceeded {} seconds", + policy.timeout.as_secs() + ), + )); + } + match monitor(&mut child) { + Ok(Some(status)) => break status, + Ok(None) => thread::sleep(Duration::from_millis(50)), + Err(error) => { + return Err(finish_error( + &mut child, + stdout, + stderr, + BackgroundErrorKind::Monitor, + error.to_string(), + )); + } + } + }; + while !(stdout.poll()? && stderr.poll()?) { + if cancellation.is_some_and(CancellationToken::is_cancelled) { + return Err(finish_error( + &mut child, + stdout, + stderr, + BackgroundErrorKind::Cancelled, + "the operation was cancelled while collecting process output".into(), + )); + } + if Instant::now() >= deadline { + return Err(finish_error( + &mut child, + stdout, + stderr, + BackgroundErrorKind::Timeout, + format!( + "the operation exceeded {} seconds while descendants retained its output pipes", + policy.timeout.as_secs() + ), + )); + } + thread::sleep(Duration::from_millis(10)); + } + let stdout = stdout.finish()?; + let stderr = stderr.finish()?; + if stdout.len() > policy.max_output_bytes || stderr.len() > policy.max_output_bytes { + return Err(BackgroundError { + kind: BackgroundErrorKind::OutputTooLarge, + detail: format!( + "the operation returned more than {} bytes per output stream", + policy.max_output_bytes + ), + }); + } + Ok(BackgroundOutput { + status, + stdout, + stderr, + }) +} + +pub fn run( + command: Command, + policy: BackgroundPolicy, + cancellation: Option<&CancellationToken>, +) -> Result { + run_with_monitor(command, policy, cancellation, |child| child.try_wait()) +} + +pub async fn run_async( + command: Command, + policy: BackgroundPolicy, + cancellation: CancellationToken, +) -> Result { + tauri::async_runtime::spawn_blocking(move || run(command, policy, Some(&cancellation))) + .await + .map_err(|error| BackgroundError { + kind: BackgroundErrorKind::Monitor, + detail: format!("the background monitor stopped unexpectedly: {error}"), + })? +} + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(windows)] + #[test] + fn windows_console_probe() { + if std::env::var_os("VIDXP_WINDOWS_CONSOLE_PROBE").is_none() { + return; + } + + unsafe extern "system" { + fn GetConsoleWindow() -> *mut std::ffi::c_void; + } + + assert!(unsafe { GetConsoleWindow() }.is_null()); + } + + #[cfg(windows)] + fn console_probe_command() -> Command { + let mut command = Command::new(std::env::current_exe().expect("current test executable")); + command + .args([ + "--exact", + "background_process::tests::windows_console_probe", + ]) + .env("VIDXP_WINDOWS_CONSOLE_PROBE", "1"); + command + } + + fn shell_command(script: &str) -> Command { + if cfg!(windows) { + let mut command = Command::new("cmd"); + command.args(["/c", script]); + command + } else { + let mut command = Command::new("sh"); + command.args(["-c", script]); + command + } + } + + #[test] + fn bounded_runner_captures_output() { + let result = run( + shell_command("echo runner"), + BackgroundPolicy { + timeout: Duration::from_secs(2), + max_output_bytes: 1024, + }, + None, + ) + .expect("background command"); + assert!(result.status.success()); + assert!(String::from_utf8_lossy(&result.stdout).contains("runner")); + } + + #[cfg(windows)] + #[test] + fn captured_commands_do_not_create_a_windows_console() { + let result = run( + console_probe_command(), + BackgroundPolicy { + timeout: Duration::from_secs(5), + max_output_bytes: 4096, + }, + None, + ) + .expect("console probe"); + assert!( + result.status.success(), + "console probe failed: {}", + String::from_utf8_lossy(&result.stderr) + ); + } + + #[cfg(windows)] + #[test] + fn service_commands_do_not_create_a_windows_console() { + let mut child = spawn_service(console_probe_command()).expect("console probe service"); + let deadline = Instant::now() + Duration::from_secs(5); + loop { + if let Some(status) = child.try_wait().expect("console probe status") { + assert!(status.success(), "console probe failed"); + break; + } + assert!(Instant::now() < deadline, "console probe timed out"); + thread::sleep(Duration::from_millis(10)); + } + } + + #[test] + fn timeout_terminates_the_owned_process_tree() { + let script = if cfg!(windows) { + "ping 127.0.0.1 -n 10 > nul" + } else { + "sleep 10" + }; + let error = run( + shell_command(script), + BackgroundPolicy { + timeout: Duration::from_millis(100), + max_output_bytes: 1024, + }, + None, + ) + .expect_err("timeout"); + assert_eq!(error.kind, BackgroundErrorKind::Timeout); + } + + #[test] + fn cancellation_terminates_the_owned_process_tree() { + let cancellation = CancellationToken::default(); + cancellation.cancel(); + let error = run( + shell_command("echo never"), + BackgroundPolicy { + timeout: Duration::from_secs(2), + max_output_bytes: 1024, + }, + Some(&cancellation), + ) + .expect_err("cancelled"); + assert_eq!(error.kind, BackgroundErrorKind::Cancelled); + } + + #[test] + fn monitor_failure_terminates_and_reaps_the_owned_process_tree() { + let script = if cfg!(windows) { + "ping 127.0.0.1 -n 10 > nul" + } else { + "sleep 10" + }; + let error = run_with_monitor( + shell_command(script), + BackgroundPolicy { + timeout: Duration::from_secs(2), + max_output_bytes: 1024, + }, + None, + |_| Err(std::io::Error::other("injected monitor failure")), + ) + .expect_err("monitor failure"); + assert_eq!(error.kind, BackgroundErrorKind::Monitor); + } + + #[test] + fn inherited_output_pipe_cannot_outlive_the_operation_deadline() { + let script = if cfg!(windows) { + "start \"\" /b cmd /c \"ping 127.0.0.1 -n 10 ^> nul\" & echo root-finished" + } else { + "(sleep 10) & echo root-finished" + }; + let started = Instant::now(); + let error = run( + shell_command(script), + BackgroundPolicy { + timeout: Duration::from_millis(150), + max_output_bytes: 1024, + }, + None, + ) + .expect_err("inherited pipe timeout"); + assert_eq!(error.kind, BackgroundErrorKind::Timeout); + assert!(started.elapsed() < Duration::from_secs(3)); + } +} diff --git a/desktop/src-tauri/src/browser_readiness.rs b/desktop/src-tauri/src/browser_readiness.rs new file mode 100644 index 0000000..17225df --- /dev/null +++ b/desktop/src-tauri/src/browser_readiness.rs @@ -0,0 +1,269 @@ +use std::{ + fs, + io::{Read, Write}, + net::{SocketAddr, TcpStream}, + path::Path, + thread, + time::{Duration, Instant}, +}; + +use serde::Deserialize; + +use crate::background_process::{CancellationToken, OwnedChild}; + +const READINESS_PRODUCT: &str = "dev.grayhat.vidxp"; +const READINESS_PROTOCOL_VERSION: u32 = 1; + +#[derive(Debug, Deserialize)] +struct ReadinessMarker { + product: String, + protocol_version: u32, + nonce: String, + port: u16, + #[serde(rename = "pid")] + _pid: u32, +} + +fn marker_matches(contents: &[u8], nonce: &str, port: u16) -> bool { + serde_json::from_slice::(contents).is_ok_and(|marker| { + marker.product == READINESS_PRODUCT + && marker.protocol_version == READINESS_PROTOCOL_VERSION + && marker.nonce == nonce + && marker.port == port + }) +} + +fn streamlit_health_is_ready(address: SocketAddr) -> bool { + let Ok(mut stream) = TcpStream::connect_timeout(&address, Duration::from_millis(150)) else { + return false; + }; + let timeout = Some(Duration::from_millis(250)); + if stream.set_read_timeout(timeout).is_err() || stream.set_write_timeout(timeout).is_err() { + return false; + } + if stream + .write_all(b"GET /_stcore/health HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n") + .is_err() + { + return false; + } + let mut response = Vec::new(); + if stream.take(8192).read_to_end(&mut response).is_err() { + return false; + } + let response = String::from_utf8_lossy(&response); + let Some((headers, body)) = response.split_once("\r\n\r\n") else { + return false; + }; + (headers.starts_with("HTTP/1.1 200") || headers.starts_with("HTTP/1.0 200")) + && body.trim() == "ok" +} + +pub fn wait_for_browser_readiness( + process: &mut OwnedChild, + marker_path: &Path, + nonce: &str, + port: u16, + deadline: Instant, + cancellation: &CancellationToken, +) -> Result<(), String> { + let address = SocketAddr::from(([127, 0, 0, 1], port)); + while Instant::now() < deadline { + if cancellation.is_cancelled() { + process.terminate_and_reap(); + let _ = fs::remove_file(marker_path); + return Err("VidXP interface startup was cancelled.".into()); + } + if let Some(status) = process + .try_wait() + .map_err(|error| format!("Could not inspect the interface process: {error}"))? + { + let _ = fs::remove_file(marker_path); + return Err(format!( + "The VidXP interface exited during startup ({status})." + )); + } + if fs::read(marker_path).is_ok_and(|contents| { + marker_matches(&contents, nonce, port) && streamlit_health_is_ready(address) + }) { + let _ = fs::remove_file(marker_path); + return Ok(()); + } + thread::sleep(Duration::from_millis(50)); + } + process.terminate_and_reap(); + let _ = fs::remove_file(marker_path); + Err("The VidXP interface did not publish its launch identity and become ready in 30 seconds. Another process may have captured the reserved port.".into()) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::{net::TcpListener, process::Command}; + + fn sleeping_command() -> Command { + if cfg!(windows) { + let mut command = Command::new("cmd"); + command.args(["/c", "ping 127.0.0.1 -n 20 > nul"]); + command + } else { + let mut command = Command::new("sh"); + command.args(["-c", "sleep 20"]); + command + } + } + + fn short_command() -> Command { + if cfg!(windows) { + let mut command = Command::new("cmd"); + command.args(["/c", "exit 0"]); + command + } else { + let mut command = Command::new("sh"); + command.args(["-c", "exit 0"]); + command + } + } + + fn temporary_marker(name: &str) -> std::path::PathBuf { + std::env::temp_dir().join(format!( + "vidxp-readiness-{name}-{}-{}.json", + std::process::id(), + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .expect("clock") + .as_nanos() + )) + } + + fn health_server(listener: TcpListener) -> thread::JoinHandle<()> { + thread::spawn(move || { + if let Ok((mut stream, _)) = listener.accept() { + let mut request = [0_u8; 1024]; + let _ = stream.read(&mut request); + let _ = stream.write_all( + b"HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nok", + ); + } + }) + } + + #[test] + fn readiness_marker_rejects_stale_service_and_wrong_nonce() { + let correct = br#"{"product":"dev.grayhat.vidxp","protocol_version":1,"nonce":"new","port":43123,"pid":99}"#; + assert!(marker_matches(correct, "new", 43123)); + assert!(!marker_matches(correct, "old", 43123)); + assert!(!marker_matches(correct, "new", 43124)); + assert!(!marker_matches(b"not-json", "new", 43123)); + } + + #[test] + fn readiness_requires_the_expected_marker_even_when_a_captured_port_is_healthy() { + let listener = TcpListener::bind(("127.0.0.1", 0)).expect("listener"); + let port = listener.local_addr().expect("address").port(); + listener + .set_nonblocking(true) + .expect("nonblocking listener"); + let server = thread::spawn(move || { + let deadline = Instant::now() + Duration::from_secs(1); + while Instant::now() < deadline { + match listener.accept() { + Ok((mut stream, _)) => { + let _ = stream.write_all( + b"HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nok", + ); + return; + } + Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { + thread::sleep(Duration::from_millis(10)); + } + Err(_) => return, + } + } + }); + let mut process = + crate::background_process::spawn_service(sleeping_command()).expect("sleeping process"); + let marker = temporary_marker("captured"); + let result = wait_for_browser_readiness( + &mut process, + &marker, + "launch", + port, + Instant::now() + Duration::from_millis(300), + &CancellationToken::default(), + ); + assert!(result.is_err()); + server.join().expect("server"); + } + + #[test] + fn readiness_fails_when_the_supervised_child_exits() { + let mut process = + crate::background_process::spawn_service(short_command()).expect("short process"); + let result = wait_for_browser_readiness( + &mut process, + &temporary_marker("exit"), + "launch", + 9, + Instant::now() + Duration::from_secs(2), + &CancellationToken::default(), + ); + assert!( + result + .expect_err("child exit") + .contains("exited during startup") + ); + } + + #[test] + fn readiness_accepts_a_marker_pid_different_from_the_supervised_launcher() { + let listener = TcpListener::bind(("127.0.0.1", 0)).expect("listener"); + let port = listener.local_addr().expect("address").port(); + let server = health_server(listener); + let mut process = + crate::background_process::spawn_service(sleeping_command()).expect("sleeping process"); + let marker = temporary_marker("success"); + fs::write( + &marker, + serde_json::json!({ + "product": READINESS_PRODUCT, + "protocol_version": READINESS_PROTOCOL_VERSION, + "nonce": "launch", + "port": port, + "pid": process.id() + 1, + }) + .to_string(), + ) + .expect("marker"); + wait_for_browser_readiness( + &mut process, + &marker, + "launch", + port, + Instant::now() + Duration::from_secs(2), + &CancellationToken::default(), + ) + .expect("ready"); + assert!(!marker.exists()); + server.join().expect("server"); + } + + #[test] + fn readiness_cancellation_is_bounded() { + let cancelled = CancellationToken::default(); + cancelled.cancel(); + let mut process = + crate::background_process::spawn_service(sleeping_command()).expect("sleeping process"); + let started = Instant::now(); + let result = wait_for_browser_readiness( + &mut process, + &temporary_marker("cancel"), + "launch", + 9, + Instant::now() + Duration::from_secs(20), + &cancelled, + ); + assert!(result.expect_err("cancelled").contains("cancelled")); + assert!(started.elapsed() < Duration::from_secs(2)); + } +} diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs index c2bb1e2..f098d92 100644 --- a/desktop/src-tauri/src/lib.rs +++ b/desktop/src-tauri/src/lib.rs @@ -3,14 +3,13 @@ use std::{ collections::{BTreeMap, BTreeSet}, env, fs, io::{self, Write}, - net::{SocketAddr, TcpListener, TcpStream}, + net::TcpListener, path::{Path, PathBuf}, - process::{Child, Command, Output, Stdio}, + process::Command, sync::{ - Mutex, - atomic::{AtomicBool, Ordering}, + Arc, Mutex, OnceLock, + atomic::{AtomicBool, AtomicU64, Ordering}, }, - thread, time::{Duration, Instant, SystemTime, UNIX_EPOCH}, }; @@ -24,15 +23,30 @@ use tauri::{ }; use tauri_plugin_dialog::{DialogExt, MessageDialogButtons, MessageDialogKind}; use tauri_plugin_opener::OpenerExt; -use tauri_plugin_shell::{ - ShellExt, - process::{Command as ShellCommand, CommandChild, CommandEvent}, +use tauri_plugin_shell::ShellExt; + +mod activation; +mod background_process; +mod browser_readiness; +mod lifecycle; +mod media_setup; +mod target_profiles; + +use activation::{ActivationRecovery, ActivationStage, activation_recovery}; +use lifecycle::{ + ActiveOperationGuard, ActiveOperations, DesktopAction, DesktopActivation, DesktopCloseAction, + UiProcessAction, action_for_activation, close_action, ui_process_action, }; -use wait_timeout::ChildExt; +use media_setup::{SystemInstallPlan, display_command, required_encoder_missing}; -const RUNTIME_MANIFEST_BYTES: &[u8] = include_bytes!("../../runtime-manifest.json"); -const RUNTIME_CONSTRAINTS_BYTES: &[u8] = include_bytes!("../../runtime-constraints.txt"); +const RUNTIME_MANIFEST_BYTES: &[u8] = + include_bytes!(concat!(env!("OUT_DIR"), "/runtime-manifest.json")); +const RUNTIME_CONSTRAINTS_BYTES: &[u8] = + include_bytes!(concat!(env!("OUT_DIR"), "/runtime-constraints.txt")); +const MODEL_CACHE_CATALOG_BYTES: &[u8] = include_bytes!("../../model-cache-catalog.json"); const PRODUCT_DATA_DIRECTORY_NAME: &str = "VidXP"; +const MAX_SETUP_OUTPUT_BYTES: usize = 4 * 1024 * 1024; +static READINESS_SEQUENCE: AtomicU64 = AtomicU64::new(0); #[derive(Clone, Deserialize, Serialize)] struct CapabilitySpec { @@ -77,6 +91,13 @@ struct InstallRequest { surfaces: Vec, prepare_models: bool, model_directory: Option, + draft_id: String, +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +struct ManagedSetupDraft { + id: String, + previous_profile_id: Option, } #[derive(Serialize)] @@ -88,9 +109,17 @@ struct InstallResult { prepared: bool, } +#[derive(Serialize)] +struct InstallTransitionResult { + install: InstallResult, + setup: target_profiles::TargetState, +} + #[derive(Serialize)] struct RuntimeStatus { + state: RuntimeState, ready: bool, + runtime_profile: Option, package_version: String, capabilities: Vec, surfaces: Vec, @@ -98,6 +127,41 @@ struct RuntimeStatus { detail: String, } +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)] +#[serde(rename_all = "snake_case")] +enum RuntimeState { + NeverConfigured, + Ready, + Broken, +} + +#[derive(Clone, Deserialize, Serialize)] +struct CachedModelEntry { + id: String, + label: String, +} + +#[derive(Deserialize)] +struct ModelCacheCatalogEntry { + id: String, + label: String, + relative_artifact: String, +} + +#[derive(Serialize)] +struct ModelDirectoryInventory { + directory: String, + exists: bool, + readable: bool, + total_bytes: u64, + file_count: u64, + recognized_models: Vec, + empty: bool, + verification_required: bool, + truncated: bool, + detail: String, +} + #[derive(Clone, Serialize)] struct MediaRuntimeStatus { ready: bool, @@ -115,13 +179,7 @@ struct VerifiedMediaRuntime { ffprobe: PathBuf, } -struct SystemInstallPlan { - manager: String, - command: Vec, - automatic: bool, -} - -#[derive(Clone, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] struct ActiveRuntime { schema_version: u32, manifest_sha256: String, @@ -134,6 +192,7 @@ struct ActiveRuntime { model_directory: PathBuf, } +#[derive(Clone)] struct DesktopPaths { private_data: PathBuf, data: PathBuf, @@ -143,40 +202,506 @@ struct DesktopPaths { python: PathBuf, models: PathBuf, active_runtime: PathBuf, + activation_journal: PathBuf, +} + +type WorkerStopper = dyn Fn(&Path, &DesktopPaths, Instant) + Send + Sync; + +struct ActiveWorkerOperation { + id: u64, + runtime: PathBuf, + paths: DesktopPaths, + stop_claimed: bool, +} + +#[derive(Default)] +struct WorkerStopState { + next_id: u64, + active: Option, + last_stopped_runtime: Option, +} + +struct WorkerStopSupervisor { + state: Mutex, + stopper: Arc, +} + +impl Default for WorkerStopSupervisor { + fn default() -> Self { + Self { + state: Mutex::new(WorkerStopState::default()), + stopper: Arc::new(stop_worker_before), + } + } +} + +impl WorkerStopSupervisor { + #[cfg(test)] + fn with_stopper(stopper: Arc) -> Self { + Self { + state: Mutex::new(WorkerStopState::default()), + stopper, + } + } + + fn register( + self: &Arc, + runtime: PathBuf, + paths: DesktopPaths, + ) -> Result { + let mut state = self + .state + .lock() + .map_err(|_| "The preparation worker supervisor is unavailable.".to_string())?; + if state.active.is_some() { + return Err("Another worker-backed managed operation is already active.".into()); + } + state.next_id += 1; + let id = state.next_id; + state.last_stopped_runtime = None; + state.active = Some(ActiveWorkerOperation { + id, + runtime, + paths, + stop_claimed: false, + }); + Ok(WorkerOperationGuard { + supervisor: self.clone(), + id, + settled: false, + }) + } + + fn claim(&self, id: u64) -> Option<(PathBuf, DesktopPaths)> { + let mut state = self.state.lock().ok()?; + let active = state.active.as_mut()?; + if active.id != id || active.stop_claimed { + return None; + } + active.stop_claimed = true; + Some((active.runtime.clone(), active.paths.clone())) + } + + fn finish(&self, id: u64, runtime: PathBuf) { + if let Ok(mut state) = self.state.lock() + && state.active.as_ref().is_some_and(|active| active.id == id) + { + state.active = None; + state.last_stopped_runtime = Some(runtime); + } + } + + fn stop_active_before(&self, deadline: Instant) -> Option { + let claim = { + let mut state = self.state.lock().ok()?; + if let Some(active) = state.active.as_mut() { + if active.stop_claimed { + return Some(active.runtime.clone()); + } + active.stop_claimed = true; + Some((active.id, active.runtime.clone(), active.paths.clone())) + } else { + return state.last_stopped_runtime.clone(); + } + }; + let (id, runtime, paths) = claim?; + (self.stopper)(&runtime, &paths, deadline); + self.finish(id, runtime.clone()); + Some(runtime) + } +} + +struct WorkerOperationGuard { + supervisor: Arc, + id: u64, + settled: bool, +} + +impl WorkerOperationGuard { + fn stop_before(&mut self, deadline: Instant) { + if self.settled { + return; + } + if let Some((runtime, paths)) = self.supervisor.claim(self.id) { + (self.supervisor.stopper)(&runtime, &paths, deadline); + self.supervisor.finish(self.id, runtime); + } + self.settled = true; + } +} + +impl Drop for WorkerOperationGuard { + fn drop(&mut self) { + self.stop_before(Instant::now() + Duration::from_secs(5)); + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +struct ActivationJournal { + schema_version: u32, + stage: ActivationStage, + previous_active_bytes: Option>, + previous_targets: target_profiles::TargetState, + candidate_active: ActiveRuntime, + candidate_targets: target_profiles::TargetState, +} + +#[derive(Debug, Default, Eq, PartialEq)] +struct RuntimeReconciliation { + removed_directories: usize, + reclaimed_bytes: u64, + failures: Vec, } struct ManagedUi { - process: Child, + process: background_process::OwnedChild, url: String, + profile_id: String, } struct DesktopState { ui_process: Mutex>, - operation_process: Mutex>, - operation_worker_runtime: Mutex>, - operation_active: AtomicBool, + worker_stop: Arc, + operation_cancellation: Arc>>, + transition: Arc>, + browser_open_active: AtomicBool, + shutdown: background_process::CancellationToken, shutdown_started: AtomicBool, + active_operations: Arc, } impl Default for DesktopState { fn default() -> Self { Self { ui_process: Mutex::new(None), - operation_process: Mutex::new(None), - operation_worker_runtime: Mutex::new(None), - operation_active: AtomicBool::new(false), + worker_stop: Arc::new(WorkerStopSupervisor::default()), + operation_cancellation: Arc::new(Mutex::new(None)), + transition: Arc::new(Mutex::new(TransitionState::default())), + browser_open_active: AtomicBool::new(false), + shutdown: background_process::CancellationToken::default(), shutdown_started: AtomicBool::new(false), + active_operations: Arc::new(ActiveOperations::default()), + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum DraftPhase { + Draft, + Applying, + Committed, + Cancelled, +} + +#[derive(Clone, Debug)] +struct DraftRecord { + draft: ManagedSetupDraft, + phase: DraftPhase, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum TransitionKind { + Revalidate, + Adopt, + Select, + Delete, + InstallMedia, + InstallRuntime, + PrepareModels, + RecoverActivation, + OpenBrowser, +} + +#[derive(Clone, Copy, Debug)] +struct ActiveTransition { + id: u64, + kind: TransitionKind, +} + +#[derive(Default)] +struct TransitionState { + next_id: u64, + active: Option, + draft: Option, +} + +fn transition_error( + code: target_profiles::TargetErrorCode, + message: impl Into, +) -> target_profiles::TargetError { + target_profiles::TargetError { + code, + message: message.into(), + } +} + +fn track_target_operation( + state: &DesktopState, +) -> Result { + state.active_operations.register().map_err(|message| { + transition_error(target_profiles::TargetErrorCode::OperationConflict, message) + }) +} + +struct TransitionGuard { + shared: Arc>, + id: u64, + applying_draft: Option, +} + +impl TransitionGuard { + fn commit_draft(&mut self) { + let Some(draft_id) = self.applying_draft.take() else { + return; + }; + if let Ok(mut transition) = self.shared.lock() + && let Some(record) = transition.draft.as_mut() + && record.draft.id == draft_id + && record.phase == DraftPhase::Applying + { + record.phase = DraftPhase::Committed; + } + } +} + +impl Drop for TransitionGuard { + fn drop(&mut self) { + let Ok(mut transition) = self.shared.lock() else { + return; + }; + if transition.active.is_some_and(|active| active.id == self.id) { + transition.active = None; + } + if let Some(draft_id) = self.applying_draft.take() + && let Some(record) = transition.draft.as_mut() + && record.draft.id == draft_id + && record.phase == DraftPhase::Applying + { + record.phase = DraftPhase::Draft; + } + } +} + +struct TargetTransitionCoordinator; + +impl TargetTransitionCoordinator { + fn begin( + state: &DesktopState, + kind: TransitionKind, + ) -> Result { + let mut transition = state.transition.lock().map_err(|_| { + transition_error( + target_profiles::TargetErrorCode::StoreUnavailable, + "The target transition coordinator is unavailable.", + ) + })?; + if let Some(active) = transition.active { + return Err(transition_error( + target_profiles::TargetErrorCode::OperationConflict, + format!( + "Another target transition ({:?}) is already active.", + active.kind + ), + )); + } + transition.next_id = transition.next_id.wrapping_add(1).max(1); + let id = transition.next_id; + transition.active = Some(ActiveTransition { id, kind }); + Ok(TransitionGuard { + shared: state.transition.clone(), + id, + applying_draft: None, + }) + } + + fn begin_apply( + state: &DesktopState, + draft_id: &str, + kind: TransitionKind, + ) -> Result { + let mut guard = Self::begin(state, kind)?; + let mut transition = state.transition.lock().map_err(|_| { + transition_error( + target_profiles::TargetErrorCode::StoreUnavailable, + "The managed setup draft is unavailable.", + ) + })?; + let record = transition.draft.as_mut().ok_or_else(|| { + transition_error( + target_profiles::TargetErrorCode::DraftMismatch, + "This managed setup draft has expired.", + ) + })?; + if record.draft.id != draft_id { + return Err(transition_error( + target_profiles::TargetErrorCode::DraftMismatch, + "A stale managed setup screen cannot modify the current draft.", + )); + } + if record.phase != DraftPhase::Draft { + return Err(transition_error( + target_profiles::TargetErrorCode::DraftApplying, + "This managed setup draft is already applying or has finished.", + )); + } + record.phase = DraftPhase::Applying; + guard.applying_draft = Some(draft_id.to_owned()); + Ok(guard) + } + + fn begin_managed_draft( + app: &AppHandle, + state: &DesktopState, + ) -> Result { + let mut transition = state.transition.lock().map_err(|_| { + transition_error( + target_profiles::TargetErrorCode::StoreUnavailable, + "The managed setup draft could not be created.", + ) + })?; + if transition.active.is_some() { + return Err(transition_error( + target_profiles::TargetErrorCode::OperationConflict, + "Another target transition is already active.", + )); + } + if let Some(record) = &transition.draft + && record.phase == DraftPhase::Draft + { + return Ok(record.draft.clone()); + } + let current = target_profiles::current_state(app)?; + let seed = format!( + "{}:{}:{}", + std::process::id(), + SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_err(|error| { + transition_error( + target_profiles::TargetErrorCode::ValidationRequired, + format!("The system clock is invalid: {error}"), + ) + })? + .as_nanos(), + current.selected_profile_id.as_deref().unwrap_or_default() + ); + let draft = ManagedSetupDraft { + id: hex::encode(Sha256::digest(seed.as_bytes())), + previous_profile_id: current.selected_profile_id, + }; + transition.draft = Some(DraftRecord { + draft: draft.clone(), + phase: DraftPhase::Draft, + }); + Ok(draft) + } + + fn cancel_managed_draft( + app: &AppHandle, + state: &DesktopState, + draft_id: &str, + ) -> Result { + Self::cancel_draft(state, draft_id)?; + target_profiles::current_state(app) + } + + fn cancel_draft( + state: &DesktopState, + draft_id: &str, + ) -> Result<(), target_profiles::TargetError> { + let mut transition = state.transition.lock().map_err(|_| { + transition_error( + target_profiles::TargetErrorCode::StoreUnavailable, + "The managed setup draft could not be cancelled.", + ) + })?; + if transition.active.is_some() { + return Err(transition_error( + target_profiles::TargetErrorCode::DraftApplying, + "Managed setup is applying and cannot be cancelled until it settles.", + )); + } + let record = transition.draft.as_mut().ok_or_else(|| { + transition_error( + target_profiles::TargetErrorCode::DraftMismatch, + "This managed setup draft has expired.", + ) + })?; + if record.draft.id != draft_id { + return Err(transition_error( + target_profiles::TargetErrorCode::DraftMismatch, + "A stale managed setup screen cannot cancel the current draft.", + )); } + match record.phase { + DraftPhase::Draft => {} + DraftPhase::Applying => { + return Err(transition_error( + target_profiles::TargetErrorCode::DraftApplying, + "Managed setup is applying and cannot be cancelled until it settles.", + )); + } + DraftPhase::Committed | DraftPhase::Cancelled => { + return Err(transition_error( + target_profiles::TargetErrorCode::DraftMismatch, + "This managed setup draft has already finished.", + )); + } + } + record.phase = DraftPhase::Cancelled; + Ok(()) } } -struct OperationGuard<'a> { - active: &'a AtomicBool, +struct OperationCancellationGuard { + slot: Arc>>, + token: background_process::CancellationToken, + _active: ActiveOperationGuard, +} + +impl OperationCancellationGuard { + fn register(state: &DesktopState) -> Result { + let token = background_process::CancellationToken::default(); + let active = state.active_operations.register()?; + let mut slot = state + .operation_cancellation + .lock() + .map_err(|_| "The setup cancellation supervisor is unavailable.".to_string())?; + if state.shutdown.is_cancelled() { + return Err("VidXP Desktop is shutting down.".into()); + } + if slot.is_some() { + return Err("Another cancellable Desktop operation is already active.".into()); + } + *slot = Some(token.clone()); + drop(slot); + Ok(Self { + slot: state.operation_cancellation.clone(), + token, + _active: active, + }) + } + + fn token(&self) -> background_process::CancellationToken { + self.token.clone() + } } -impl Drop for OperationGuard<'_> { +impl Drop for OperationCancellationGuard { fn drop(&mut self) { - self.active.store(false, Ordering::Release); + if let Ok(mut active) = self.slot.lock() + && active.as_ref().is_some_and(|token| token.same(&self.token)) + { + active.take(); + } + } +} + +fn cancel_active_operation(state: &DesktopState) { + if let Ok(active) = state.operation_cancellation.lock() + && let Some(cancellation) = active.as_ref() + { + cancellation.cancel(); } } @@ -241,6 +766,7 @@ fn desktop_paths_from_roots(private_data: &Path, cache: &Path, local_data: &Path runtimes: private_data.join("runtimes"), python: private_data.join("python"), active_runtime: private_data.join("active-runtime.json"), + activation_journal: private_data.join("activation-journal.json"), models: data.join("models"), private_data: private_data.to_path_buf(), data, @@ -314,6 +840,119 @@ fn model_directory(paths: &DesktopPaths, requested: Option<&str>) -> Result Option { + static CATALOG: OnceLock> = OnceLock::new(); + let catalog = CATALOG.get_or_init(|| { + serde_json::from_slice(MODEL_CACHE_CATALOG_BYTES) + .expect("the generated model cache catalog must be valid") + }); + let path = relative + .to_string_lossy() + .replace('\\', "/") + .to_ascii_lowercase(); + catalog + .iter() + .find(|entry| path.ends_with(&entry.relative_artifact.to_ascii_lowercase())) + .map(|entry| CachedModelEntry { + id: entry.id.clone(), + label: entry.label.clone(), + }) +} + +fn inventory_model_directory(directory: &Path) -> ModelDirectoryInventory { + let resolved = fs::canonicalize(directory).unwrap_or_else(|_| directory.to_path_buf()); + let mut inventory = ModelDirectoryInventory { + directory: resolved.to_string_lossy().into_owned(), + exists: directory.exists(), + readable: true, + total_bytes: 0, + file_count: 0, + recognized_models: Vec::new(), + empty: true, + verification_required: false, + truncated: false, + detail: String::new(), + }; + if !inventory.exists { + inventory.detail = "No model directory exists yet; no cached models were found.".into(); + return inventory; + } + if !directory.is_dir() { + inventory.readable = false; + inventory.detail = "The selected model location is not a readable directory.".into(); + return inventory; + } + let root = match fs::read_dir(directory) { + Ok(entries) => entries, + Err(error) => { + inventory.readable = false; + inventory.detail = format!("The selected model directory could not be read: {error}"); + return inventory; + } + }; + let mut pending = vec![(directory.to_path_buf(), root)]; + let mut recognized = BTreeMap::::new(); + let mut visited = 0_u64; + while let Some((_parent, entries)) = pending.pop() { + for entry in entries { + visited += 1; + if visited > MAX_MODEL_INVENTORY_ENTRIES { + inventory.truncated = true; + break; + } + let Ok(entry) = entry else { + inventory.truncated = true; + continue; + }; + let Ok(file_type) = entry.file_type() else { + inventory.truncated = true; + continue; + }; + if file_type.is_symlink() { + continue; + } + let path = entry.path(); + if file_type.is_dir() { + match fs::read_dir(&path) { + Ok(children) => pending.push((path, children)), + Err(_) => inventory.truncated = true, + } + } else if file_type.is_file() { + inventory.file_count += 1; + if let Ok(metadata) = entry.metadata() { + inventory.total_bytes = inventory.total_bytes.saturating_add(metadata.len()); + } else { + inventory.truncated = true; + } + if let Ok(relative) = path.strip_prefix(directory) + && let Some(model) = recognize_cached_model(relative) + { + recognized.insert(model.id, model.label); + } + } + } + if inventory.truncated && visited > MAX_MODEL_INVENTORY_ENTRIES { + break; + } + } + inventory.recognized_models = recognized + .into_iter() + .map(|(id, label)| CachedModelEntry { id, label }) + .collect(); + inventory.empty = inventory.file_count == 0; + inventory.verification_required = inventory.file_count > 0; + inventory.detail = if inventory.empty { + "No cached models were found.".into() + } else if inventory.truncated { + "Cached files were found. The bounded inventory is partial; preparation must verify required artifacts.".into() + } else { + "Cached files detected; verification required. VidXP will reuse valid cached files and download only missing material.".into() + }; + inventory +} + fn selected_capabilities( manifest: &RuntimeManifest, requested: &[String], @@ -373,14 +1012,6 @@ fn base_package_specification(manifest: &RuntimeManifest) -> String { format!("{}=={}", manifest.package_name, manifest.package_version) } -fn package_index(package_version: &str) -> &'static str { - if package_version.split_once('-').is_some() { - "https://test.pypi.org/simple" - } else { - "https://pypi.org/simple" - } -} - fn package_acquisition_arguments(manifest: &RuntimeManifest, python: &Path) -> Vec { vec![ "pip".into(), @@ -390,7 +1021,7 @@ fn package_acquisition_arguments(manifest: &RuntimeManifest, python: &Path) -> V "--no-config".into(), "--no-deps".into(), "--default-index".into(), - package_index(&manifest.package_version).into(), + manifest.dependency_index.clone(), "--index-strategy".into(), "first-index".into(), base_package_specification(manifest), @@ -459,15 +1090,15 @@ fn executable_candidates(name: &str) -> Vec { let mut directories = env::var_os("PATH") .map(|value| env::split_paths(&value).collect::>()) .unwrap_or_default(); - if cfg!(windows) { - if let Some(local) = env::var_os("LOCALAPPDATA") { - directories.push( - PathBuf::from(local) - .join("Microsoft") - .join("WinGet") - .join("Links"), - ); - } + if cfg!(windows) + && let Some(local) = env::var_os("LOCALAPPDATA") + { + directories.push( + PathBuf::from(local) + .join("Microsoft") + .join("WinGet") + .join("Links"), + ); } if cfg!(target_os = "macos") { directories.extend([ @@ -501,7 +1132,7 @@ fn resolve_system_executable(name: &str) -> Option { .and_then(|candidate| fs::canonicalize(&candidate).ok().or(Some(candidate))) } -fn combined_output(output: &Output) -> String { +fn combined_output(output: &background_process::BackgroundOutput) -> String { format!( "{}\n{}", String::from_utf8_lossy(&output.stdout), @@ -509,83 +1140,8 @@ fn combined_output(output: &Output) -> String { ) } -fn required_encoder_missing(output: &str, encoder: &str) -> bool { - !output - .lines() - .flat_map(|line| line.split_whitespace()) - .any(|token| token == encoder) -} - fn system_install_plan() -> Option { - if cfg!(windows) { - resolve_system_executable("winget")?; - return Some(SystemInstallPlan { - manager: "Windows Package Manager".into(), - command: vec![ - "winget".into(), - "install".into(), - "--id".into(), - "Gyan.FFmpeg".into(), - "--exact".into(), - "--source".into(), - "winget".into(), - "--accept-package-agreements".into(), - "--accept-source-agreements".into(), - ], - automatic: true, - }); - } - if cfg!(target_os = "macos") { - let brew = resolve_system_executable("brew")?; - return Some(SystemInstallPlan { - manager: "Homebrew".into(), - command: vec![ - brew.to_string_lossy().into_owned(), - "install".into(), - "ffmpeg".into(), - ], - automatic: true, - }); - } - if resolve_system_executable("apt-get").is_some() { - return Some(SystemInstallPlan { - manager: "APT".into(), - command: vec![ - "sudo".into(), - "apt-get".into(), - "install".into(), - "ffmpeg".into(), - ], - automatic: false, - }); - } - if resolve_system_executable("dnf").is_some() { - return Some(SystemInstallPlan { - manager: "DNF".into(), - command: vec![ - "sudo".into(), - "dnf".into(), - "install".into(), - "ffmpeg".into(), - ], - automatic: false, - }); - } - None -} - -fn display_command(arguments: &[String]) -> String { - arguments - .iter() - .map(|argument| { - if argument.contains(char::is_whitespace) { - format!("\"{}\"", argument.replace('"', "\\\"")) - } else { - argument.clone() - } - }) - .collect::>() - .join(" ") + media_setup::system_install_plan(resolve_system_executable) } fn inspect_media_runtime() -> MediaRuntimeStatus { @@ -667,7 +1223,15 @@ fn verified_media_runtime() -> Result { } fn clean_environment(paths: &DesktopPaths) -> Vec<(String, String)> { - let mut environment: Vec<_> = std::env::vars() + clean_environment_from(paths, std::env::vars()) +} + +fn clean_environment_from( + paths: &DesktopPaths, + source: impl IntoIterator, +) -> Vec<(String, String)> { + let mut environment: Vec<_> = source + .into_iter() .filter(|(key, _)| { let upper = key.to_ascii_uppercase(); !upper.starts_with("VIDXP_") @@ -704,28 +1268,24 @@ fn clean_environment(paths: &DesktopPaths) -> Vec<(String, String)> { fn configured_command(executable_path: &Path, paths: &DesktopPaths) -> Command { let mut command = Command::new(executable_path); - hide_child_console(&mut command); command.env_clear(); command.envs(clean_environment(paths)); command } -#[cfg(windows)] -fn hide_child_console(command: &mut Command) { - use std::os::windows::process::CommandExt; - - const CREATE_NO_WINDOW: u32 = 0x0800_0000; - command.creation_flags(CREATE_NO_WINDOW); -} - -#[cfg(not(windows))] -fn hide_child_console(_command: &mut Command) {} - -fn checked_output(mut command: Command, operation: &str) -> Result { - hide_child_console(&mut command); - let output = command - .output() - .map_err(|error| format!("{operation} could not start: {error}"))?; +fn checked_output( + command: Command, + operation: &str, +) -> Result { + let output = background_process::run( + command, + background_process::BackgroundPolicy { + timeout: Duration::from_secs(30), + max_output_bytes: 1024 * 1024, + }, + None, + ) + .map_err(|error| format!("{operation} failed: {}", error.detail))?; if output.status.success() { return Ok(output); } @@ -740,6 +1300,11 @@ fn active_runtime(paths: &DesktopPaths) -> Result { .map_err(|_| "Local video processing has not been configured yet.".to_string())?; let active: ActiveRuntime = serde_json::from_slice(&contents) .map_err(|error| format!("The active runtime pointer is invalid: {error}"))?; + validate_active_runtime_pointer(&active)?; + Ok(active) +} + +fn validate_active_runtime_pointer(active: &ActiveRuntime) -> Result<(), String> { if active.schema_version != 2 || active.manifest_sha256 != manifest_digest() { return Err("The desktop runtime needs to be installed for this app version.".into()); } @@ -750,7 +1315,7 @@ fn active_runtime(paths: &DesktopPaths) -> Result { { return Err("The active runtime profile identity is invalid.".into()); } - Ok(active) + Ok(()) } fn runtime_directory(paths: &DesktopPaths, active: &ActiveRuntime) -> PathBuf { @@ -769,65 +1334,467 @@ fn write_active_runtime(paths: &DesktopPaths, active: &ActiveRuntime) -> Result< .map_err(|error| format!("Could not activate the validated runtime: {error}")) } -async fn supervised_output( - state: &DesktopState, - command: ShellCommand, - operation: &str, -) -> Result<(Vec, Vec), String> { - if state.shutdown_started.load(Ordering::Acquire) { - return Err(format!( - "{operation} was cancelled because VidXP is closing." - )); - } - let (mut events, child) = command - .spawn() - .map_err(|error| format!("{operation} could not start: {error}"))?; - { - let mut active_child = state - .operation_process - .lock() - .map_err(|_| "The setup process supervisor is unavailable.".to_string())?; - if active_child.is_some() { - drop(active_child); - let _ = child.kill(); - return Err("Another desktop setup process is already running.".into()); - } - *active_child = Some(child); - } - - let mut stdout = Vec::new(); - let mut stderr = Vec::new(); - let mut exit_code = None; - while let Some(event) = events.recv().await { - match event { - CommandEvent::Stdout(bytes) => stdout.extend(bytes), - CommandEvent::Stderr(bytes) => stderr.extend(bytes), - CommandEvent::Error(error) => stderr.extend(error.as_bytes()), - CommandEvent::Terminated(status) => { - exit_code = status.code; - break; - } - _ => {} - } +fn write_activation_journal( + paths: &DesktopPaths, + journal: &ActivationJournal, +) -> Result<(), String> { + fs::create_dir_all(&paths.private_data) + .map_err(|error| format!("Could not create the activation journal directory: {error}"))?; + let mut destination = AtomicWriteFile::options() + .open(&paths.activation_journal) + .map_err(|error| format!("Could not stage the activation journal: {error}"))?; + serde_json::to_writer(&mut destination, journal) + .map_err(|error| format!("Could not serialize the activation journal: {error}"))?; + destination + .flush() + .and_then(|_| destination.commit()) + .map_err(|error| format!("Could not persist the activation journal: {error}")) +} + +fn read_active_runtime_snapshot(paths: &DesktopPaths) -> Result>, String> { + match fs::read(&paths.active_runtime) { + Ok(bytes) => Ok(Some(bytes)), + Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(None), + Err(error) => Err(format!( + "Could not snapshot the previous active runtime pointer: {error}" + )), + } +} + +fn restore_active_runtime(paths: &DesktopPaths, previous: Option<&[u8]>) -> Result<(), String> { + match previous { + Some(bytes) => { + let mut destination = AtomicWriteFile::options() + .open(&paths.active_runtime) + .map_err(|error| { + format!("Could not stage the previous runtime pointer: {error}") + })?; + destination.write_all(bytes).map_err(|error| { + format!("Could not restore the previous runtime pointer: {error}") + })?; + destination + .flush() + .and_then(|_| destination.commit()) + .map_err(|error| format!("Could not restore the previous runtime pointer: {error}")) + } + None if paths.active_runtime.exists() => fs::remove_file(&paths.active_runtime) + .map_err(|error| format!("Could not restore the empty runtime selection: {error}")), + None => Ok(()), + } +} + +fn clear_activation_journal(paths: &DesktopPaths) -> Result<(), String> { + if paths.activation_journal.exists() { + fs::remove_file(&paths.activation_journal) + .map_err(|error| format!("Could not clear the activation journal: {error}"))?; + } + Ok(()) +} + +fn managed_runtime_projection_for( + paths: &DesktopPaths, + active: &ActiveRuntime, +) -> target_profiles::ManagedRuntimeProjection { + let runtime = runtime_directory(paths, active); + let requested_executable = executable(&runtime, "vidxp"); + let executable = fs::canonicalize(&requested_executable).unwrap_or(requested_executable); + target_profiles::ManagedRuntimeProjection { + runtime_profile: active.profile.clone(), + executable, + data_root: paths.data.clone(), + repository_root: paths.repository.clone(), + model_directory: active.model_directory.clone(), + package_version: active.package_version.clone(), + capabilities: active.capabilities.clone(), + surfaces: active.surfaces.clone(), + } +} + +fn resolved_path(path: &Path) -> PathBuf { + fs::canonicalize(path).unwrap_or_else(|_| path.to_path_buf()) +} + +fn same_path(left: &Path, right: &Path) -> bool { + let left = resolved_path(left); + let right = resolved_path(right); + #[cfg(windows)] + { + left.to_string_lossy() + .eq_ignore_ascii_case(&right.to_string_lossy()) + } + #[cfg(not(windows))] + { + left == right + } +} + +fn path_is_confined(path: &Path, root: &Path) -> bool { + let path = resolved_path(path); + let root = resolved_path(root); + #[cfg(windows)] + { + let path = path.to_string_lossy().to_ascii_lowercase(); + let root = root.to_string_lossy().to_ascii_lowercase(); + path == root || path.starts_with(&format!("{root}\\")) + } + #[cfg(not(windows))] + { + path.starts_with(root) } - if let Ok(mut active_child) = state.operation_process.lock() { - active_child.take(); +} + +fn managed_probe_error(message: impl Into) -> target_profiles::TargetError { + target_profiles::TargetError { + code: target_profiles::TargetErrorCode::InvalidDataRoot, + message: message.into(), } - if exit_code == Some(0) { - return Ok((stdout, stderr)); +} + +fn validate_managed_projection( + paths: &DesktopPaths, + projection: &target_profiles::ManagedRuntimeProjection, + desktop_version: &str, + cancellation: Option<&background_process::CancellationToken>, +) -> Result { + let runtime = paths.runtimes.join(&projection.runtime_profile); + let validated = target_profiles::validate_executable_using( + &projection.executable, + desktop_version, + cancellation, + |executable| configured_command(executable, paths), + )?; + for (label, reported, authoritative) in [ + ("data", &validated.data_root, &projection.data_root), + ( + "repository", + &validated.repository_root, + &projection.repository_root, + ), + ("model", &validated.model_root, &projection.model_directory), + ] { + if !same_path(reported, authoritative) { + return Err(managed_probe_error(format!( + "The managed probe reported {label} root {}, but VidXP Desktop owns {}.", + reported.display(), + authoritative.display() + ))); + } } - let detail = String::from_utf8_lossy(&stderr).trim().to_owned(); - Err(format!( - "{operation} failed{}: {detail}", - exit_code.map_or_else(String::new, |code| format!(" with exit code {code}")) - )) + if !path_is_confined(&validated.executable, &runtime) + || !path_is_confined(&validated.runtime.python_executable, &runtime) + || !same_path(&validated.runtime.prefix, &runtime) + { + return Err(managed_probe_error( + "The managed probe reported a launcher or Python runtime outside the active Desktop-owned environment.", + )); + } + Ok(validated) +} + +fn managed_runtime_projection( + paths: &DesktopPaths, +) -> Option { + let contents = fs::read(&paths.active_runtime).ok()?; + let active: ActiveRuntime = serde_json::from_slice(&contents).ok()?; + if !active + .profile + .chars() + .all(|character| character.is_ascii_hexdigit() || character == '-') + { + log::warn!("Ignoring an active managed runtime with an invalid profile identity"); + return None; + } + Some(managed_runtime_projection_for(paths, &active)) +} + +fn candidate_authorities_match( + app: &AppHandle, + paths: &DesktopPaths, + journal: &ActivationJournal, +) -> bool { + let active_matches = fs::read(&paths.active_runtime) + .ok() + .and_then(|bytes| serde_json::from_slice::(&bytes).ok()) + .is_some_and(|active| active == journal.candidate_active); + let targets_match = target_profiles::current_state(app) + .is_ok_and(|targets| targets == journal.candidate_targets); + active_matches && targets_match +} + +fn mark_journal_stage( + paths: &DesktopPaths, + journal: &mut ActivationJournal, + stage: ActivationStage, +) -> Result<(), String> { + journal.stage = stage; + write_activation_journal(paths, journal) +} + +fn finish_journal_cleanup(paths: &DesktopPaths, context: &str) { + if let Err(error) = clear_activation_journal(paths) { + log::warn!("{context}; activation journal cleanup will be retried: {error}"); + } +} + +fn owned_runtime_directory_name(name: &str) -> bool { + let mut parts = name.split('-'); + let Some(digest) = parts.next() else { + return false; + }; + let Some(timestamp) = parts.next() else { + return false; + }; + parts.next().is_none() + && digest.len() == 64 + && digest + .chars() + .all(|character| character.is_ascii_hexdigit()) + && !timestamp.is_empty() + && timestamp + .chars() + .all(|character| character.is_ascii_digit()) +} + +fn owned_staging_directory_name(name: &str) -> bool { + let Some(remainder) = name.strip_prefix(".staging-") else { + return false; + }; + let mut parts = remainder.split('-'); + let (Some(digest), Some(timestamp), Some(pid)) = (parts.next(), parts.next(), parts.next()) + else { + return false; + }; + parts.next().is_none() + && digest.len() == 64 + && digest + .chars() + .all(|character| character.is_ascii_hexdigit()) + && !timestamp.is_empty() + && timestamp + .chars() + .all(|character| character.is_ascii_digit()) + && !pid.is_empty() + && pid.chars().all(|character| character.is_ascii_digit()) +} + +fn directory_size(path: &Path) -> io::Result { + let mut total = 0_u64; + for entry in fs::read_dir(path)? { + let entry = entry?; + let metadata = entry.path().symlink_metadata()?; + if metadata.file_type().is_symlink() { + continue; + } + if metadata.is_dir() { + total = total.saturating_add(directory_size(&entry.path())?); + } else if metadata.is_file() { + total = total.saturating_add(metadata.len()); + } + } + Ok(total) +} + +fn reconcile_managed_runtime_storage(paths: &DesktopPaths) -> RuntimeReconciliation { + let mut report = RuntimeReconciliation::default(); + let mut retained = BTreeSet::new(); + let preserve_unidentified_finalized = match fs::read(&paths.active_runtime) { + Ok(contents) => match serde_json::from_slice::(&contents) { + Ok(active) => { + retained.insert(active.profile); + false + } + Err(_) => true, + }, + Err(error) => error.kind() != io::ErrorKind::NotFound, + }; + if let Ok(contents) = fs::read(&paths.activation_journal) + && let Ok(journal) = serde_json::from_slice::(&contents) + { + retained.insert(journal.candidate_active.profile); + if let Some(previous) = journal.previous_active_bytes + && let Ok(active) = serde_json::from_slice::(&previous) + { + retained.insert(active.profile); + } + } + let Ok(entries) = fs::read_dir(&paths.runtimes) else { + return report; + }; + for entry in entries.flatten() { + let path = entry.path(); + let name = entry.file_name().to_string_lossy().into_owned(); + let Ok(file_type) = entry.file_type() else { + continue; + }; + if !file_type.is_dir() || file_type.is_symlink() || retained.contains(&name) { + continue; + } + let finalized = owned_runtime_directory_name(&name); + if (!finalized && !owned_staging_directory_name(&name)) + || (finalized && preserve_unidentified_finalized) + { + continue; + } + if !path_is_confined(&path, &paths.runtimes) { + report.failures.push(format!( + "Refused to reconcile a runtime path outside {}: {}", + paths.runtimes.display(), + path.display() + )); + continue; + } + let bytes = directory_size(&path).unwrap_or_default(); + match fs::remove_dir_all(&path) { + Ok(()) => { + report.removed_directories += 1; + report.reclaimed_bytes = report.reclaimed_bytes.saturating_add(bytes); + } + Err(error) => report.failures.push(format!( + "Could not remove untracked Desktop runtime {}: {error}", + path.display() + )), + } + } + report +} + +fn log_runtime_reconciliation(paths: &DesktopPaths) { + let report = reconcile_managed_runtime_storage(paths); + if report.removed_directories > 0 { + log::info!( + "Reconciled {} obsolete managed runtime directories and reclaimed {} bytes", + report.removed_directories, + report.reclaimed_bytes + ); + } + for failure in report.failures { + log::warn!("Managed runtime storage cleanup failed: {failure}"); + } +} + +fn rollback_activation( + app: &AppHandle, + paths: &DesktopPaths, + journal: &mut ActivationJournal, + runtime: &Path, + activation_error: &str, +) -> String { + if let Err(error) = mark_journal_stage(paths, journal, ActivationStage::RollingBack) { + return format!( + "{activation_error}. Rollback could not be durably started: {error}. VidXP Desktop will recover the existing activation journal on its next start. The candidate runtime remains at {}.", + runtime.display() + ); + } + let active_restore = restore_active_runtime(paths, journal.previous_active_bytes.as_deref()); + let target_restore = target_profiles::replace_state(app, journal.previous_targets.clone()) + .map_err(|error| error.to_string()); + if let (Err(active_error), Err(target_error)) = (&active_restore, &target_restore) { + return format!( + "{activation_error}. Rollback remains incomplete (runtime pointer: {active_error}; target profile: {target_error}); startup will retry it. The candidate runtime remains at {}.", + runtime.display() + ); + } + if let Err(error) = active_restore { + return format!( + "{activation_error}. Target profiles were restored, but the runtime pointer could not be restored: {error}; startup will retry rollback. The candidate runtime remains at {}.", + runtime.display() + ); + } + if let Err(error) = target_restore { + return format!( + "{activation_error}. The runtime pointer was restored, but target profiles could not be restored: {error}; startup will retry rollback. The candidate runtime remains at {}.", + runtime.display() + ); + } + if let Err(error) = mark_journal_stage(paths, journal, ActivationStage::RolledBack) { + log::warn!( + "Managed activation rolled back, but its completion marker could not be written: {error}" + ); + } + finish_journal_cleanup(paths, "Rolled back a failed managed activation"); + format!( + "{activation_error}. The candidate runtime was retained at {}, while the previous active runtime and target remain selected.", + runtime.display() + ) +} + +fn recover_interrupted_activation(app: &AppHandle, state: &DesktopState) -> Result<(), String> { + let _transition = TargetTransitionCoordinator::begin(state, TransitionKind::RecoverActivation) + .map_err(|error| error.to_string())?; + let paths = desktop_paths(app)?; + if !paths.activation_journal.exists() { + return Ok(()); + } + let contents = fs::read(&paths.activation_journal) + .map_err(|error| format!("Could not read the activation journal: {error}"))?; + let mut journal: ActivationJournal = serde_json::from_slice(&contents) + .map_err(|error| format!("The activation journal is invalid: {error}"))?; + if journal.schema_version != 2 { + return Err(format!( + "The activation journal uses unsupported schema version {}.", + journal.schema_version + )); + } + let authorities_match = candidate_authorities_match(app, &paths, &journal); + match activation_recovery(&journal.stage, authorities_match) { + ActivationRecovery::Complete => { + write_active_runtime(&paths, &journal.candidate_active)?; + target_profiles::replace_state(app, journal.candidate_targets.clone()) + .map_err(|error| error.to_string())?; + mark_journal_stage(&paths, &mut journal, ActivationStage::Committed)?; + } + ActivationRecovery::RollBack => { + mark_journal_stage(&paths, &mut journal, ActivationStage::RollingBack)?; + restore_active_runtime(&paths, journal.previous_active_bytes.as_deref())?; + target_profiles::replace_state(app, journal.previous_targets.clone()) + .map_err(|error| error.to_string())?; + mark_journal_stage(&paths, &mut journal, ActivationStage::RolledBack)?; + } + } + finish_journal_cleanup(&paths, "Recovered an interrupted managed activation"); + Ok(()) +} + +fn initialize_target_profiles(app: &AppHandle) -> Result { + let manifest = manifest()?; + let paths = desktop_paths(app)?; + target_profiles::initialize( + app, + managed_runtime_projection(&paths), + &manifest.desktop_version, + ) + .map_err(|error| error.to_string()) +} + +async fn supervised_output( + command: Command, + cancellation: background_process::CancellationToken, + operation: &str, +) -> Result { + let output = background_process::run_async( + command, + background_process::BackgroundPolicy { + timeout: Duration::from_secs(30 * 60), + max_output_bytes: MAX_SETUP_OUTPUT_BYTES, + }, + cancellation, + ) + .await + .map_err(|error| format!("{operation} failed: {}", error.detail))?; + if output.status.success() { + return Ok(output); + } + let stderr = String::from_utf8_lossy(&output.stderr).trim().to_owned(); + let stdout = String::from_utf8_lossy(&output.stdout).trim().to_owned(); + let detail = if stderr.is_empty() { stdout } else { stderr }; + Err(format!("{operation} failed ({}): {detail}", output.status)) } async fn uv_output( app: &AppHandle, - state: &DesktopState, paths: &DesktopPaths, arguments: Vec, + cancellation: background_process::CancellationToken, operation: &str, ) -> Result<(), String> { let mut command = app @@ -844,7 +1811,8 @@ async fn uv_output( .env("UV_PYTHON_INSTALL_DIR", &paths.python) .env("UV_NO_CONFIG", "1") .env("UV_MANAGED_PYTHON", "1"); - supervised_output(state, command, operation).await?; + let command: Command = command.into(); + supervised_output(command, cancellation, operation).await?; Ok(()) } @@ -853,7 +1821,7 @@ fn run_vidxp( paths: &DesktopPaths, arguments: &[String], operation: &str, -) -> Result { +) -> Result { let mut command = configured_command(&executable(runtime, "vidxp"), paths); command .arg("--index-dir") @@ -863,40 +1831,363 @@ fn run_vidxp( } async fn run_vidxp_supervised( - app: &AppHandle, - state: &DesktopState, runtime: &Path, paths: &DesktopPaths, arguments: &[String], + cancellation: background_process::CancellationToken, operation: &str, ) -> Result<(), String> { - let mut command = app - .shell() - .command(executable(runtime, "vidxp")) - .env_clear(); - for (key, value) in clean_environment(paths) { - command = command.env(key, value); - } - command = command + let mut command = configured_command(&executable(runtime, "vidxp"), paths); + command .arg("--index-dir") .arg(&paths.repository) .args(arguments); - supervised_output(state, command, operation).await?; + supervised_output(command, cancellation, operation).await?; Ok(()) } #[tauri::command] -fn runtime_manifest() -> Result { +fn runtime_manifest(state: tauri::State<'_, DesktopState>) -> Result { + let _active = state.active_operations.register()?; manifest() } #[tauri::command] -fn media_runtime_status() -> MediaRuntimeStatus { - inspect_media_runtime() +fn target_state( + app: AppHandle, + state: tauri::State<'_, DesktopState>, +) -> Result { + let _active = track_target_operation(&state)?; + target_profiles::current_state(&app) +} + +#[tauri::command] +async fn refresh_target_state( + app: AppHandle, + state: tauri::State<'_, DesktopState>, +) -> Result { + let _active = track_target_operation(&state)?; + let manifest = manifest().map_err(|error| target_profiles::TargetError { + code: target_profiles::TargetErrorCode::ValidationRequired, + message: error, + })?; + let desktop_version = manifest.desktop_version; + let transition = TargetTransitionCoordinator::begin(&state, TransitionKind::Revalidate)?; + let cancellation = state.shutdown.clone(); + tauri::async_runtime::spawn_blocking(move || { + let _transition = transition; + match target_profiles::selected_profile(&app) { + Ok(profile) => { + if profile.kind == target_profiles::TargetKind::Managed { + let validation = (|| { + let paths = desktop_paths(&app).map_err(|message| { + transition_error( + target_profiles::TargetErrorCode::ManagedRuntimeUnavailable, + message, + ) + })?; + let active = active_runtime(&paths).map_err(|message| { + transition_error( + target_profiles::TargetErrorCode::ManagedRuntimeUnavailable, + message, + ) + })?; + if profile.managed_runtime_profile.as_deref() + != Some(active.profile.as_str()) + { + return Err(transition_error( + target_profiles::TargetErrorCode::ManagedRuntimeUnavailable, + "The selected managed target does not match the active Desktop runtime.", + )); + } + let projection = managed_runtime_projection_for(&paths, &active); + validate_managed_projection( + &paths, + &projection, + &desktop_version, + Some(&cancellation), + ) + })(); + let _ = target_profiles::persist_selected_validation(&app, validation); + } else { + let _ = target_profiles::validated_selected_profile_with_cancellation( + &app, + &desktop_version, + Some(&cancellation), + ); + } + } + Err(error) + if error.code == target_profiles::TargetErrorCode::SelectedProfileMissing => {} + Err(error) => return Err(error), + } + target_profiles::current_state(&app) + }) + .await + .map_err(|error| target_profiles::TargetError { + code: target_profiles::TargetErrorCode::ValidationRequired, + message: format!("Target revalidation stopped unexpectedly: {error}"), + })? +} + +#[tauri::command] +async fn discover_local_targets( + state: tauri::State<'_, DesktopState>, +) -> Result, String> { + let _active = state.active_operations.register()?; + tauri::async_runtime::spawn_blocking(target_profiles::discover_local_targets) + .await + .map_err(|error| format!("Target discovery stopped unexpectedly: {error}")) +} + +#[tauri::command] +fn choose_local_executable( + app: AppHandle, + state: tauri::State<'_, DesktopState>, +) -> Result, String> { + let _active = state.active_operations.register()?; + app.dialog() + .file() + .set_title("Choose an existing VidXP executable") + .blocking_pick_file() + .map(|path| { + path.into_path() + .map(|path| path.to_string_lossy().into_owned()) + .map_err(|error| format!("The selected executable path is invalid: {error}")) + }) + .transpose() +} + +#[tauri::command] +async fn inspect_local_target( + state: tauri::State<'_, DesktopState>, + executable: String, +) -> Result { + let _active = track_target_operation(&state)?; + let manifest = manifest().map_err(|error| target_profiles::TargetError { + code: target_profiles::TargetErrorCode::ValidationRequired, + message: error, + })?; + let desktop_version = manifest.desktop_version; + let cancellation = state.shutdown.clone(); + tauri::async_runtime::spawn_blocking(move || { + target_profiles::inspect_executable_with_cancellation( + Path::new(&executable), + &desktop_version, + &cancellation, + ) + }) + .await + .map_err(|error| { + transition_error( + target_profiles::TargetErrorCode::ValidationRequired, + format!("Target inspection stopped unexpectedly: {error}"), + ) + })? } #[tauri::command] -fn choose_model_directory(app: AppHandle) -> Result, String> { +async fn adopt_local_target( + app: AppHandle, + state: tauri::State<'_, DesktopState>, + executable: String, + display_name: Option, +) -> Result { + let _active = track_target_operation(&state)?; + let manifest = manifest().map_err(|error| target_profiles::TargetError { + code: target_profiles::TargetErrorCode::ValidationRequired, + message: error, + })?; + let transition = TargetTransitionCoordinator::begin(&state, TransitionKind::Adopt)?; + let desktop_version = manifest.desktop_version; + let cancellation = state.shutdown.clone(); + tauri::async_runtime::spawn_blocking(move || { + let _transition = transition; + let canonical = + fs::canonicalize(Path::new(&executable)).unwrap_or_else(|_| PathBuf::from(&executable)); + let validated = target_profiles::validate_executable_using( + &canonical, + &desktop_version, + Some(&cancellation), + |path| Command::new(path), + )?; + let setup = target_profiles::adopt_validated(&app, validated, display_name)?; + stop_ui_process(&app.state::()); + Ok(setup) + }) + .await + .map_err(|error| { + transition_error( + target_profiles::TargetErrorCode::ValidationRequired, + format!("Target adoption stopped unexpectedly: {error}"), + ) + })? +} + +#[tauri::command] +async fn select_target_profile( + app: AppHandle, + state: tauri::State<'_, DesktopState>, + profile_id: String, +) -> Result { + let _active = track_target_operation(&state)?; + let manifest = manifest().map_err(|error| target_profiles::TargetError { + code: target_profiles::TargetErrorCode::ValidationRequired, + message: error, + })?; + let transition = TargetTransitionCoordinator::begin(&state, TransitionKind::Select)?; + let desktop_version = manifest.desktop_version; + let cancellation = state.shutdown.clone(); + tauri::async_runtime::spawn_blocking(move || { + let _transition = transition; + let candidate = target_profiles::current_state(&app)? + .profiles + .into_iter() + .find(|profile| profile.id == profile_id) + .ok_or_else(|| { + transition_error( + target_profiles::TargetErrorCode::ProfileNotFound, + "The selected VidXP target no longer exists.", + ) + })?; + let setup = if candidate.kind == target_profiles::TargetKind::Managed { + let paths = desktop_paths(&app).map_err(|message| { + transition_error( + target_profiles::TargetErrorCode::ManagedRuntimeUnavailable, + message, + ) + })?; + let active = active_runtime(&paths).map_err(|message| { + transition_error( + target_profiles::TargetErrorCode::ManagedRuntimeUnavailable, + message, + ) + })?; + if candidate.managed_runtime_profile.as_deref() != Some(active.profile.as_str()) { + return Err(transition_error( + target_profiles::TargetErrorCode::ManagedRuntimeUnavailable, + "The selected managed target does not match the active Desktop runtime.", + )); + } + let projection = managed_runtime_projection_for(&paths, &active); + let validated = validate_managed_projection( + &paths, + &projection, + &desktop_version, + Some(&cancellation), + )?; + target_profiles::select_validated_profile(&app, &profile_id, validated)? + } else { + target_profiles::select_profile(&app, &profile_id, &desktop_version)? + }; + stop_ui_process(&app.state::()); + Ok(setup) + }) + .await + .map_err(|error| { + transition_error( + target_profiles::TargetErrorCode::ValidationRequired, + format!("Target selection stopped unexpectedly: {error}"), + ) + })? +} + +#[tauri::command] +async fn delete_target_profile( + app: AppHandle, + state: tauri::State<'_, DesktopState>, + profile_id: String, +) -> Result { + let _active = track_target_operation(&state)?; + let transition = TargetTransitionCoordinator::begin(&state, TransitionKind::Delete)?; + tauri::async_runtime::spawn_blocking(move || { + let _transition = transition; + let selected = target_profiles::current_state(&app)?.selected_profile_id; + let result = target_profiles::delete_profile(&app, &profile_id)?; + if selected.as_deref() == Some(&profile_id) { + stop_ui_process(&app.state::()); + } + Ok(result) + }) + .await + .map_err(|error| { + transition_error( + target_profiles::TargetErrorCode::ValidationRequired, + format!("Target deletion stopped unexpectedly: {error}"), + ) + })? +} + +#[tauri::command] +async fn confirm_forget_target( + app: AppHandle, + state: tauri::State<'_, DesktopState>, + display_name: String, +) -> Result { + let _active = state.active_operations.register()?; + tauri::async_runtime::spawn_blocking(move || { + app.dialog() + .message(format!( + "Forget “{display_name}” from VidXP Desktop? The installation itself will not be changed." + )) + .title("Forget saved target?") + .kind(MessageDialogKind::Warning) + .buttons(MessageDialogButtons::OkCancel) + .blocking_show() + }) + .await + .map_err(|error| format!("The confirmation dialog stopped unexpectedly: {error}")) +} + +#[tauri::command] +async fn begin_managed_setup( + app: AppHandle, + state: tauri::State<'_, DesktopState>, +) -> Result { + let _active = track_target_operation(&state)?; + let transition = state.transition.clone(); + tauri::async_runtime::spawn_blocking(move || { + let state = app.state::(); + debug_assert!(Arc::ptr_eq(&transition, &state.transition)); + TargetTransitionCoordinator::begin_managed_draft(&app, &state) + }) + .await + .map_err(|error| { + transition_error( + target_profiles::TargetErrorCode::ValidationRequired, + format!("Managed setup could not start: {error}"), + ) + })? +} + +#[tauri::command] +async fn cancel_managed_setup( + app: AppHandle, + state: tauri::State<'_, DesktopState>, + draft_id: String, +) -> Result { + let _active = track_target_operation(&state)?; + let transition = state.transition.clone(); + tauri::async_runtime::spawn_blocking(move || { + let state = app.state::(); + debug_assert!(Arc::ptr_eq(&transition, &state.transition)); + TargetTransitionCoordinator::cancel_managed_draft(&app, &state, &draft_id) + }) + .await + .map_err(|error| { + transition_error( + target_profiles::TargetErrorCode::ValidationRequired, + format!("Managed setup cancellation stopped unexpectedly: {error}"), + ) + })? +} + +#[tauri::command] +fn choose_model_directory( + app: AppHandle, + state: tauri::State<'_, DesktopState>, +) -> Result, String> { + let _active = state.active_operations.register()?; let selection = app .dialog() .file() @@ -915,22 +2206,25 @@ fn choose_model_directory(app: AppHandle) -> Result, String> { async fn install_media_runtime( app: AppHandle, state: tauri::State<'_, DesktopState>, + draft_id: String, ) -> Result { - let current = inspect_media_runtime(); + let cancellation = OperationCancellationGuard::register(&state)?; + let _transition = + TargetTransitionCoordinator::begin_apply(&state, &draft_id, TransitionKind::InstallMedia) + .map_err(|error| error.to_string())?; + let current = tauri::async_runtime::spawn_blocking(inspect_media_runtime) + .await + .map_err(|error| format!("Media runtime inspection stopped unexpectedly: {error}"))?; if current.ready { return Ok(current); } - if state - .operation_active - .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) - .is_err() - { - return Err("Another install or model-preparation operation is active.".into()); - } - let _operation_guard = OperationGuard { - active: &state.operation_active, - }; - let plan = system_install_plan().ok_or("No supported system package manager was found.")?; + let plan = system_install_plan().ok_or_else(|| { + if cfg!(target_os = "macos") { + "FFmpeg is required. Install Homebrew from https://brew.sh and run `brew install ffmpeg`, or install FFmpeg and ffprobe manually on PATH, then retry.".to_string() + } else { + "No supported system package manager was found. Install FFmpeg and ffprobe on PATH, then retry.".to_string() + } + })?; if !plan.automatic { let instruction = format!( "VidXP needs FFmpeg and ffprobe.\n\nRun this command in a terminal, then return to VidXP:\n\n{}", @@ -964,13 +2258,16 @@ async fn install_media_runtime( .shell() .command(plan.command[0].clone()) .args(&plan.command[1..]); + let command: Command = command.into(); supervised_output( - &state, command, + cancellation.token(), &format!("{} FFmpeg installation", plan.manager), ) .await?; - let status = inspect_media_runtime(); + let status = tauri::async_runtime::spawn_blocking(inspect_media_runtime) + .await + .map_err(|error| format!("Media runtime verification stopped unexpectedly: {error}"))?; if !status.ready { return Err(format!( "FFmpeg installation finished but verification failed: {}", @@ -981,35 +2278,58 @@ async fn install_media_runtime( } #[tauri::command] -fn runtime_status(app: AppHandle) -> Result { +async fn runtime_status( + app: AppHandle, + state: tauri::State<'_, DesktopState>, +) -> Result { + let _active = state.active_operations.register()?; + tauri::async_runtime::spawn_blocking(move || runtime_status_sync(&app)) + .await + .map_err(|error| format!("Managed runtime inspection stopped unexpectedly: {error}"))? +} + +fn runtime_status_sync(app: &AppHandle) -> Result { let manifest = manifest()?; - let mut paths = desktop_paths(&app)?; + let mut paths = desktop_paths(app)?; let default_model_directory = paths.models.to_string_lossy().into_owned(); - if let Err(detail) = verified_media_runtime() { + if !paths.active_runtime.exists() { return Ok(RuntimeStatus { + state: RuntimeState::NeverConfigured, ready: false, + runtime_profile: None, package_version: manifest.package_version, capabilities: Vec::new(), surfaces: Vec::new(), model_directory: default_model_directory, - detail, + detail: "No Desktop-managed runtime has been created yet.".into(), }); } - let active = match active_runtime(&paths) { + let contents = fs::read(&paths.active_runtime) + .map_err(|error| format!("Could not read the active runtime pointer: {error}"))?; + let active: ActiveRuntime = match serde_json::from_slice(&contents) { Ok(active) => active, - Err(detail) => { + Err(error) => { return Ok(RuntimeStatus { + state: RuntimeState::Broken, ready: false, + runtime_profile: None, package_version: manifest.package_version, capabilities: Vec::new(), surfaces: Vec::new(), model_directory: default_model_directory, - detail, + detail: format!("The active runtime pointer is invalid: {error}"), }); } }; paths.models = active.model_directory.clone(); let runtime = runtime_directory(&paths, &active); + let mut problems = Vec::new(); + if let Err(error) = validate_active_runtime_pointer(&active) { + problems.push(error); + } + if let Err(error) = verified_media_runtime() { + problems.push(error); + } let version = run_vidxp( &runtime, &paths, @@ -1027,16 +2347,89 @@ fn runtime_status(app: AppHandle) -> Result { )) } }); - Ok(RuntimeStatus { - ready: version.is_ok(), + if let Err(error) = version { + problems.push(error); + } + Ok(configured_runtime_status(active, problems)) +} + +fn configured_runtime_status(active: ActiveRuntime, problems: Vec) -> RuntimeStatus { + let ready = problems.is_empty(); + RuntimeStatus { + state: if ready { + RuntimeState::Ready + } else { + RuntimeState::Broken + }, + ready, + runtime_profile: Some(active.profile.clone()), package_version: active.package_version, capabilities: active.capabilities, surfaces: active.surfaces, model_directory: active.model_directory.to_string_lossy().into_owned(), - detail: version - .err() - .unwrap_or_else(|| "Local video processing is ready.".into()), + detail: if ready { + "Local video processing is ready.".into() + } else { + problems.join(" ") + }, + } +} + +#[tauri::command] +async fn model_directory_inventory( + app: AppHandle, + state: tauri::State<'_, DesktopState>, + directory: Option, +) -> Result { + let _active = state.active_operations.register()?; + tauri::async_runtime::spawn_blocking(move || { + let paths = desktop_paths(&app)?; + let selected = model_directory(&paths, directory.as_deref())?; + Ok(inventory_model_directory(&selected)) }) + .await + .map_err(|error| format!("Model inventory stopped unexpectedly: {error}"))? +} + +#[tauri::command] +async fn prepare_managed_models( + app: AppHandle, + state: tauri::State<'_, DesktopState>, + draft_id: String, +) -> Result { + let cancellation = OperationCancellationGuard::register(&state)?; + let _transition = + TargetTransitionCoordinator::begin_apply(&state, &draft_id, TransitionKind::PrepareModels) + .map_err(|error| error.to_string())?; + let preparation_app = app.clone(); + let (runtime, paths, capabilities) = tauri::async_runtime::spawn_blocking(move || { + let profile = target_profiles::selected_profile(&preparation_app) + .map_err(|error| error.to_string())?; + let mut paths = desktop_paths(&preparation_app)?; + let active = active_runtime(&paths)?; + target_profiles::authorize_managed_runtime_action(&profile, &active.profile) + .map_err(|error| error.to_string())?; + paths.models = active.model_directory.clone(); + let runtime = runtime_directory(&paths, &active); + Ok::<_, String>((runtime, paths, active.capabilities)) + }) + .await + .map_err(|error| format!("Model preparation setup stopped unexpectedly: {error}"))??; + + let manifest = manifest()?; + let arguments = capability_command_arguments(&manifest, "prepare", &capabilities); + let mut worker = state.worker_stop.register(runtime.clone(), paths.clone())?; + let preparation = run_vidxp_supervised( + &runtime, + &paths, + &arguments, + cancellation.token(), + "VidXP model preparation", + ) + .await; + worker.stop_before(Instant::now() + Duration::from_secs(5)); + preparation?; + target_profiles::current_state(&app).map_err(|error| error.to_string()) } #[tauri::command] @@ -1044,34 +2437,38 @@ async fn install_runtime( app: AppHandle, state: tauri::State<'_, DesktopState>, request: InstallRequest, -) -> Result { - if state - .operation_active - .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) - .is_err() - { - return Err("Another install or model-preparation operation is active.".into()); - } - let _operation_guard = OperationGuard { - active: &state.operation_active, - }; +) -> Result { + let cancellation = OperationCancellationGuard::register(&state)?; + let mut transition = TargetTransitionCoordinator::begin_apply( + &state, + &request.draft_id, + TransitionKind::InstallRuntime, + ) + .map_err(|error| error.to_string())?; let manifest = manifest()?; let capabilities = selected_capabilities(&manifest, &request.capabilities)?; let surfaces = selected_surfaces(&manifest, &request.surfaces)?; - let media_runtime = verified_media_runtime()?; - let mut paths = desktop_paths(&app)?; - paths.models = model_directory(&paths, request.model_directory.as_deref())?; - for directory in [ - &paths.data, - &paths.cache, - &paths.repository, - &paths.runtimes, - &paths.python, - &paths.models, - ] { - fs::create_dir_all(directory) - .map_err(|error| format!("Could not create {}: {error}", directory.display()))?; - } + let requested_model_directory = request.model_directory.clone(); + let preparation_app = app.clone(); + let (media_runtime, paths) = tauri::async_runtime::spawn_blocking(move || { + let media_runtime = verified_media_runtime()?; + let mut paths = desktop_paths(&preparation_app)?; + paths.models = model_directory(&paths, requested_model_directory.as_deref())?; + for directory in [ + &paths.data, + &paths.cache, + &paths.repository, + &paths.runtimes, + &paths.python, + &paths.models, + ] { + fs::create_dir_all(directory) + .map_err(|error| format!("Could not create {}: {error}", directory.display()))?; + } + Ok::<_, String>((media_runtime, paths)) + }) + .await + .map_err(|error| format!("Managed runtime preparation stopped unexpectedly: {error}"))??; let profile_seed = format!( "{}:{}:{}:{}:{}", @@ -1093,7 +2490,6 @@ async fn install_runtime( let install_result = async { uv_output( &app, - &state, &paths, vec![ "venv".into(), @@ -1103,25 +2499,30 @@ async fn install_runtime( "--managed-python".into(), "--no-config".into(), ], + cancellation.token(), "Managed Python setup", ) .await?; - fs::write(&constraints, normalized_runtime_constraints().as_ref()) - .map_err(|error| format!("Could not write runtime constraints: {error}"))?; + let constraints_path = constraints.clone(); + tauri::async_runtime::spawn_blocking(move || { + fs::write(&constraints_path, normalized_runtime_constraints().as_ref()) + .map_err(|error| format!("Could not write runtime constraints: {error}")) + }) + .await + .map_err(|error| format!("Runtime constraint staging stopped unexpectedly: {error}"))??; uv_output( &app, - &state, &paths, package_acquisition_arguments(&manifest, &executable(&staging, "python")), + cancellation.token(), "VidXP package acquisition", ) .await?; uv_output( &app, - &state, &paths, dependency_installation_arguments( &manifest, @@ -1131,13 +2532,12 @@ async fn install_runtime( &constraints, !cfg!(target_os = "macos"), ), + cancellation.token(), "VidXP package installation", ) .await?; run_vidxp_supervised( - &app, - &state, &staging, &paths, &[ @@ -1148,17 +2548,17 @@ async fn install_runtime( "--ffprobe".into(), media_runtime.ffprobe.to_string_lossy().into_owned(), ], + cancellation.token(), "FFmpeg configuration", ) .await?; let doctor_arguments = capability_command_arguments(&manifest, "doctor", &capabilities); run_vidxp_supervised( - &app, - &state, &staging, &paths, &doctor_arguments, + cancellation.token(), "VidXP dependency validation", ) .await?; @@ -1166,29 +2566,16 @@ async fn install_runtime( if request.prepare_models { let prepare_arguments = capability_command_arguments(&manifest, "prepare", &capabilities); - *state - .operation_worker_runtime - .lock() - .map_err(|_| "The preparation worker supervisor is unavailable.")? = - Some(staging.clone()); + let mut worker = state.worker_stop.register(staging.clone(), paths.clone())?; let preparation = run_vidxp_supervised( - &app, - &state, &staging, &paths, &prepare_arguments, + cancellation.token(), "VidXP model preparation", ) .await; - let _ = run_vidxp( - &staging, - &paths, - &["jobs".into(), "stop-worker".into()], - "VidXP preparation worker shutdown", - ); - if let Ok(mut worker_runtime) = state.operation_worker_runtime.lock() { - worker_runtime.take(); - } + worker.stop_before(Instant::now() + Duration::from_secs(5)); preparation?; } @@ -1196,11 +2583,16 @@ async fn install_runtime( } .await; if let Err(error) = install_result { - let cleanup_error = if staging.exists() { - fs::remove_dir_all(&staging).err() - } else { - None - }; + let failed_staging = staging.clone(); + let cleanup_error = tauri::async_runtime::spawn_blocking(move || { + if failed_staging.exists() { + fs::remove_dir_all(&failed_staging).err() + } else { + None + } + }) + .await + .map_err(|join| format!("{error}. Staged-runtime cleanup stopped unexpectedly: {join}"))?; return Err(match cleanup_error { Some(cleanup_error) => format!( "{error}. The previous active runtime was not changed. VidXP could not remove the failed staged runtime at {}: {cleanup_error}", @@ -1214,8 +2606,6 @@ async fn install_runtime( let profile = format!("{profile_hash}-{timestamp}"); let runtime = paths.runtimes.join(&profile); - fs::rename(&staging, &runtime) - .map_err(|error| format!("Could not finalize the validated runtime: {error}"))?; let active = ActiveRuntime { schema_version: 2, manifest_sha256: manifest_digest(), @@ -1225,40 +2615,197 @@ async fn install_runtime( surfaces: surfaces.clone(), model_directory: paths.models.clone(), }; - write_active_runtime(&paths, &active)?; - - Ok(InstallResult { - package_version: manifest.package_version, - capabilities, - surfaces, - model_directory: paths.models.to_string_lossy().into_owned(), - prepared: request.prepare_models, + let activation_app = app.clone(); + let activation_paths = paths; + let activation_manifest_version = manifest.desktop_version.clone(); + let activation = tauri::async_runtime::spawn_blocking(move || { + let previous_active_bytes = read_active_runtime_snapshot(&activation_paths)?; + let previous_targets = + target_profiles::current_state(&activation_app).map_err(|error| error.to_string())?; + if let Err(error) = fs::rename(&staging, &runtime) { + let cleanup = fs::remove_dir_all(&staging); + return Err(match cleanup { + Ok(()) => format!("Could not finalize the validated runtime: {error}"), + Err(cleanup) => format!( + "Could not finalize the validated runtime: {error}. The staging directory at {} could not be removed: {cleanup}", + staging.display() + ), + }); + } + + let projection = managed_runtime_projection_for(&activation_paths, &active); + let validated = validate_managed_projection( + &activation_paths, + &projection, + &activation_manifest_version, + Some(&cancellation.token()), + ); + let candidate_targets = match validated.and_then(|validated| { + target_profiles::prepare_managed_activation( + &activation_app, + projection, + validated, + ) + }) { + Ok(candidate) => candidate, + Err(error) => { + let cleanup = fs::remove_dir_all(&runtime); + return Err(match cleanup { + Ok(()) => format!( + "The installed runtime failed the Desktop compatibility contract and was not activated: {error}" + ), + Err(cleanup) => format!( + "The installed runtime failed the Desktop compatibility contract and was not activated: {error}. Cleanup also failed for {}: {cleanup}", + runtime.display() + ), + }); + } + }; + let mut journal = ActivationJournal { + schema_version: 2, + stage: ActivationStage::Prepared, + previous_active_bytes, + previous_targets, + candidate_active: active.clone(), + candidate_targets: candidate_targets.clone(), + }; + if let Err(error) = write_activation_journal(&activation_paths, &journal) { + let cleanup = fs::remove_dir_all(&runtime); + return Err(match cleanup { + Ok(()) => error, + Err(cleanup) => format!( + "{error}. The finalized but untracked runtime could not be removed from {}: {cleanup}", + runtime.display() + ), + }); + } + + if let Err(error) = target_profiles::replace_state(&activation_app, candidate_targets.clone()) + .map_err(|error| error.to_string()) + { + return Err(rollback_activation( + &activation_app, + &activation_paths, + &mut journal, + &runtime, + &error, + )); + } + if let Err(error) = mark_journal_stage( + &activation_paths, + &mut journal, + ActivationStage::ProfileWritten, + ) { + return Err(rollback_activation( + &activation_app, + &activation_paths, + &mut journal, + &runtime, + &error, + )); + } + if let Err(error) = write_active_runtime(&activation_paths, &active) { + return Err(rollback_activation( + &activation_app, + &activation_paths, + &mut journal, + &runtime, + &error, + )); + } + + // Both authoritative files are durable at this point. Journal marking and + // removal are retryable cleanup and must never turn a committed activation + // into a reported rollback. + if let Err(error) = mark_journal_stage( + &activation_paths, + &mut journal, + ActivationStage::Committed, + ) { + log::warn!( + "Managed activation committed, but its journal could not be marked committed: {error}" + ); + } + finish_journal_cleanup(&activation_paths, "Committed a managed activation"); + log_runtime_reconciliation(&activation_paths); + Ok::<_, String>(candidate_targets) + }) + .await + .map_err(|error| format!("Managed activation stopped unexpectedly: {error}"))??; + stop_ui_process(&state); + transition.commit_draft(); + + Ok(InstallTransitionResult { + install: InstallResult { + package_version: manifest.package_version, + capabilities, + surfaces, + model_directory: activation + .selected_profile() + .and_then(|profile| profile.model_directory.as_ref()) + .map_or_else(String::new, |path| path.to_string_lossy().into_owned()), + prepared: request.prepare_models, + }, + setup: activation, }) } fn start_ui(app: &AppHandle, state: &DesktopState) -> Result { - let mut paths = desktop_paths(&app)?; - let active = active_runtime(&paths)?; - if !active.surfaces.iter().any(|surface| surface == "browser") { + let manifest = manifest()?; + let selected = target_profiles::selected_profile(app).map_err(|error| error.to_string())?; + let mut paths = desktop_paths(app)?; + let profile = if selected.kind == target_profiles::TargetKind::Managed { + let active = active_runtime(&paths)?; + if selected.managed_runtime_profile.as_deref() != Some(active.profile.as_str()) { + return Err( + "The selected managed target no longer matches the active Desktop runtime.".into(), + ); + } + paths.models = active.model_directory.clone(); + let projection = managed_runtime_projection_for(&paths, &active); + let validation = validate_managed_projection( + &paths, + &projection, + &manifest.desktop_version, + Some(&state.shutdown), + ); + target_profiles::persist_selected_validation(app, validation) + .map_err(|error| error.to_string())? + } else { + target_profiles::validated_selected_profile_with_cancellation( + app, + &manifest.desktop_version, + Some(&state.shutdown), + ) + .map_err(|error| error.to_string())? + }; + target_profiles::authorize_lifecycle(&profile, target_profiles::LifecycleAction::Launch) + .map_err(|error| error.to_string())?; + if !profile.frontend.launchable { return Err( - "The browser interface is not installed. Reconfigure VidXP and select Browser interface." - .into(), + "The selected VidXP installation cannot launch the supported browser interface.".into(), ); } - paths.models = active.model_directory.clone(); - let runtime = runtime_directory(&paths, &active); + paths.repository = profile.repository_root.clone(); + if let Some(model_directory) = &profile.model_directory { + paths.models = model_directory.clone(); + } let mut active_process = state .ui_process .lock() .map_err(|_| "The desktop process supervisor is unavailable.".to_string())?; if let Some(ui) = active_process.as_mut() { - if ui + let running = ui .process .try_wait() .map_err(|error| format!("Could not inspect the interface process: {error}"))? - .is_none() - { - return Ok(ui.url.clone()); + .is_none(); + match ui_process_action(running, &ui.profile_id, &profile.id) { + UiProcessAction::Reuse => return Ok(ui.url.clone()), + UiProcessAction::Replace => { + ui.process.terminate_and_reap(); + } + UiProcessAction::Start => {} } *active_process = None; } @@ -1270,43 +2817,96 @@ fn start_ui(app: &AppHandle, state: &DesktopState) -> Result { .map_err(|error| format!("Could not identify the local interface port: {error}"))? .port(); drop(listener); + let nonce = browser_readiness_nonce(); + let readiness_file = paths + .private_data + .join(format!("browser-readiness-{nonce}.json")); + if let Err(error) = fs::remove_file(&readiness_file) + && error.kind() != io::ErrorKind::NotFound + { + return Err(format!( + "Could not clear the stale browser readiness marker: {error}" + )); + } + + let mut command = match profile.kind { + target_profiles::TargetKind::Managed => { + let active = active_runtime(&paths)?; + if profile.managed_runtime_profile.as_deref() != Some(active.profile.as_str()) { + return Err( + "The selected managed target no longer matches the active desktop runtime." + .into(), + ); + } + configured_command(&profile.executable, &paths) + } + target_profiles::TargetKind::ExistingLocal => Command::new(&profile.executable), + }; + configure_ui_service_command( + &mut command, + &profile.repository_root, + port, + &readiness_file, + &nonce, + ); + let mut process = background_process::spawn_service(command) + .map_err(|error| format!("Could not start the VidXP interface: {}", error.detail))?; + browser_readiness::wait_for_browser_readiness( + &mut process, + &readiness_file, + &nonce, + port, + Instant::now() + Duration::from_secs(30), + &state.shutdown, + )?; + let url = format!("http://127.0.0.1:{port}"); + *active_process = Some(ManagedUi { + process, + url: url.clone(), + profile_id: profile.id.clone(), + }); + Ok(url) +} - let mut command = configured_command(&executable(&runtime, "vidxp"), &paths); +fn stop_ui_process(state: &DesktopState) { + let Ok(mut active) = state.ui_process.lock() else { + return; + }; + if let Some(mut ui) = active.take() { + ui.process.terminate_and_reap(); + } +} + +fn browser_readiness_nonce() -> String { + let sequence = READINESS_SEQUENCE.fetch_add(1, Ordering::Relaxed); + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|duration| duration.as_nanos()) + .unwrap_or_default(); + hex::encode(Sha256::digest(format!( + "{}:{timestamp}:{sequence}", + std::process::id() + ))) +} + +fn configure_ui_service_command( + command: &mut Command, + repository_root: &Path, + port: u16, + readiness_file: &Path, + nonce: &str, +) { command + // The desktop owns the one intentional browser open after readiness. Without + // headless mode Streamlit also opens the URL, producing duplicate tabs and + // potentially visible launcher consoles on Windows. + .env("STREAMLIT_SERVER_HEADLESS", "true") + .env("VIDXP_DESKTOP_READINESS_FILE", readiness_file) + .env("VIDXP_DESKTOP_READINESS_NONCE", nonce) + .env("VIDXP_DESKTOP_UI_PORT", port.to_string()) .arg("--index-dir") - .arg(&paths.repository) - .args(["ui", "--host", "127.0.0.1", "--port", &port.to_string()]) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()); - let mut process = command - .spawn() - .map_err(|error| format!("Could not start the VidXP interface: {error}"))?; - - let address = SocketAddr::from(([127, 0, 0, 1], port)); - let deadline = Instant::now() + Duration::from_secs(30); - while Instant::now() < deadline { - if let Some(status) = process - .try_wait() - .map_err(|error| format!("Could not inspect the interface process: {error}"))? - { - return Err(format!( - "The VidXP interface exited during startup ({status})." - )); - } - if TcpStream::connect_timeout(&address, Duration::from_millis(100)).is_ok() { - let url = format!("http://127.0.0.1:{port}"); - *active_process = Some(ManagedUi { - process, - url: url.clone(), - }); - return Ok(url); - } - thread::sleep(Duration::from_millis(100)); - } - let _ = process.kill(); - let _ = process.wait(); - Err("The VidXP interface did not become ready in 30 seconds.".into()) + .arg(repository_root) + .args(["ui", "--host", "127.0.0.1", "--port", &port.to_string()]); } fn hide_main_window(app: &AppHandle) -> Result<(), String> { @@ -1327,34 +2927,70 @@ fn show_main_window(app: &AppHandle) { } fn configured_runtime(app: &AppHandle) -> bool { - desktop_paths(app) - .and_then(|paths| active_runtime(&paths)) - .is_ok() + target_profiles::current_state(app) + .ok() + .is_some_and(|state| state.selected_profile().is_some()) } fn browser_surface_configured(app: &AppHandle) -> bool { - desktop_paths(app) - .and_then(|paths| active_runtime(&paths)) - .is_ok_and(|active| active.surfaces.iter().any(|surface| surface == "browser")) + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|duration| duration.as_secs()) + .unwrap_or(u64::MAX); + target_profiles::current_state(app) + .ok() + .and_then(|state| state.selected_profile().cloned()) + .is_some_and(|profile| profile.is_ready(now) && profile.frontend.launchable) +} + +struct BrowserOpenGuard(AppHandle); + +fn claim_browser_open(active: &AtomicBool) -> bool { + active + .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) + .is_ok() } -fn open_ui_in_browser(app: &AppHandle, state: &DesktopState) -> Result<(), String> { - let url = start_ui(app, state)?; +impl Drop for BrowserOpenGuard { + fn drop(&mut self) { + self.0 + .state::() + .browser_open_active + .store(false, Ordering::Release); + } +} + +async fn open_ui_in_browser(app: AppHandle) -> Result<(), String> { + let state = app.state::(); + if !claim_browser_open(&state.browser_open_active) { + return Ok(()); + } + let _browser_guard = BrowserOpenGuard(app.clone()); + let _active = state.active_operations.register()?; + let transition = TargetTransitionCoordinator::begin(&state, TransitionKind::OpenBrowser) + .map_err(|error| error.to_string())?; + let worker_app = app.clone(); + let url = tauri::async_runtime::spawn_blocking(move || { + let _transition = transition; + let state = worker_app.state::(); + start_ui(&worker_app, &state) + }) + .await + .map_err(|error| format!("VidXP interface startup stopped unexpectedly: {error}"))??; app.opener() .open_url(&url, None::<&str>) .map_err(|error| format!("Could not open VidXP in the default browser: {error}"))?; - hide_main_window(app) + hide_main_window(&app) } -fn open_or_show(app: &AppHandle) { +fn open_browser_or_show_manager(app: &AppHandle) { if !browser_surface_configured(app) { show_main_window(app); return; } let app = app.clone(); - thread::spawn(move || { - let state = app.state::(); - if let Err(error) = open_ui_in_browser(&app, &state) { + tauri::async_runtime::spawn(async move { + if let Err(error) = open_ui_in_browser(app.clone()).await { show_main_window(&app); app.dialog() .message(error) @@ -1365,46 +3001,68 @@ fn open_or_show(app: &AppHandle) { }); } +fn perform_desktop_action(app: &AppHandle, action: DesktopAction) { + match action { + DesktopAction::Manage => show_main_window(app), + DesktopAction::OpenBrowser => open_browser_or_show_manager(app), + DesktopAction::Quit => begin_shutdown(app), + } +} + fn begin_shutdown(app: &AppHandle) { - if app - .state::() - .shutdown_started - .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) - .is_err() - { + let state = app.state::(); + if let Err(error) = state.active_operations.close() { + log::error!("Could not close operation registration during shutdown: {error}"); + } + if state.shutdown_started.swap(true, Ordering::AcqRel) { return; } + state.shutdown.cancel(); + cancel_active_operation(&state); log::info!("VidXP supervised shutdown requested"); - shutdown(app); - log::info!("VidXP supervised shutdown completed"); - std::process::exit(0); -} - -#[tauri::command] -fn launch_ui(app: AppHandle, state: tauri::State<'_, DesktopState>) -> Result<(), String> { - open_ui_in_browser(&app, &state) + stop_ui_process(&state); + let app = app.clone(); + let operations = state.active_operations.clone(); + tauri::async_runtime::spawn(async move { + let shutdown_app = app.clone(); + let result = tauri::async_runtime::spawn_blocking(move || { + let deadline = Instant::now() + Duration::from_secs(20); + if !operations.wait_until_idle(Instant::now() + Duration::from_secs(10)) { + log::error!( + "Timed out waiting for supervised operations to acknowledge cancellation; forcing final owned-process cleanup" + ); + } + shutdown(&shutdown_app, deadline); + }) + .await; + if let Err(error) = result { + log::error!("The shutdown coordinator stopped unexpectedly: {error}"); + } + log::info!("VidXP supervised shutdown completed"); + app.exit(0); + }); } #[tauri::command] -fn hide_to_tray(app: AppHandle) -> Result<(), String> { - if !configured_runtime(&app) { - return Err("Local video processing has not been configured yet.".into()); - } - hide_main_window(&app) +async fn launch_ui(app: AppHandle) -> Result<(), String> { + open_ui_in_browser(app).await } fn create_tray(app: &tauri::App) -> tauri::Result<()> { let open = MenuItem::with_id(app, "open", "Open VidXP", true, None::<&str>)?; + let manage = MenuItem::with_id(app, "manage", "Manage VidXP", true, None::<&str>)?; let quit = MenuItem::with_id(app, "quit", "Quit VidXP", true, None::<&str>)?; - let menu = Menu::with_items(app, &[&open, &quit])?; + let menu = Menu::with_items(app, &[&open, &manage, &quit])?; let mut tray = TrayIconBuilder::with_id("vidxp") .tooltip("VidXP") .menu(&menu) .show_menu_on_left_click(true) - .on_menu_event(|app, event| match event.id().as_ref() { - "open" => open_or_show(app), - "quit" => begin_shutdown(app), - _ => {} + .on_menu_event(|app, event| { + if let Some(action) = + action_for_activation(DesktopActivation::Tray(event.id().as_ref())) + { + perform_desktop_action(app, action); + } }); if let Some(icon) = app.default_window_icon() { tray = tray.icon(icon.clone()); @@ -1413,93 +3071,118 @@ fn create_tray(app: &tauri::App) -> tauri::Result<()> { Ok(()) } -fn stop_worker(runtime: &Path, paths: &DesktopPaths) { +fn stop_worker_before(runtime: &Path, paths: &DesktopPaths, deadline: Instant) { + let remaining = deadline.saturating_duration_since(Instant::now()); + if remaining.is_zero() { + log::error!("Shutdown deadline elapsed before a managed worker could be stopped"); + return; + } let mut command = configured_command(&executable(runtime, "vidxp"), paths); command .arg("--index-dir") .arg(&paths.repository) - .args(["jobs", "stop-worker"]) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()); - let Ok(mut process) = command.spawn() else { - return; - }; - match process.wait_timeout(Duration::from_secs(5)) { - Ok(Some(_)) => {} - _ => { - let _ = process.kill(); - let _ = process.wait_timeout(Duration::from_secs(1)); - } - } + .args(["jobs", "stop-worker"]); + let _ = background_process::run( + command, + background_process::BackgroundPolicy { + timeout: remaining.min(Duration::from_secs(5)), + max_output_bytes: 64 * 1024, + }, + None, + ); } -fn shutdown(app: &AppHandle) { +fn shutdown(app: &AppHandle, deadline: Instant) { log::info!("Stopping active VidXP processes"); let state = app.state::(); - if let Ok(mut active_operation) = state.operation_process.lock() { - if let Some(process) = active_operation.take() { - let _ = process.kill(); - } - } - if let Ok(mut active_process) = state.ui_process.lock() { - if let Some(mut ui) = active_process.take() { - let _ = ui.process.kill(); - match ui.process.wait_timeout(Duration::from_secs(5)) { - Ok(Some(_)) => {} - _ => { - let _ = ui.process.kill(); - let _ = ui.process.wait_timeout(Duration::from_secs(1)); - } - } - } - } + cancel_active_operation(&state); + stop_ui_process(&state); let Ok(mut paths) = desktop_paths(app) else { log::warn!("Could not resolve desktop paths during shutdown"); return; }; - if let Ok(mut operation_worker) = state.operation_worker_runtime.lock() { - if let Some(runtime) = operation_worker.take() { - stop_worker(&runtime, &paths); - } + let operation_worker = state.worker_stop.stop_active_before(deadline); + let Ok(profile) = target_profiles::selected_profile(app) else { + log::info!("No selected VidXP target needs worker shutdown"); + return; + }; + if target_profiles::authorize_lifecycle( + &profile, + target_profiles::LifecycleAction::BroadProcessStop, + ) + .is_err() + { + log::info!("Skipping broad worker shutdown for an externally owned VidXP target"); + return; } let Ok(active) = active_runtime(&paths) else { - log::info!("No active VidXP runtime needs worker shutdown"); + log::info!("No active desktop-managed VidXP runtime needs worker shutdown"); return; }; + if profile.managed_runtime_profile.as_deref() != Some(active.profile.as_str()) { + log::warn!("Skipping worker shutdown because the selected managed target is not active"); + return; + } paths.models = active.model_directory.clone(); let runtime = runtime_directory(&paths, &active); - stop_worker(&runtime, &paths); + if operation_worker + .as_ref() + .is_none_or(|stopped| !same_path(stopped, &runtime)) + { + stop_worker_before(&runtime, &paths, deadline); + } log::info!("Active VidXP worker shutdown finished"); } pub fn run() { let builder = tauri::Builder::default() .plugin(tauri_plugin_single_instance::init(|app, _, _| { - open_or_show(app); + if let Some(action) = action_for_activation(DesktopActivation::SingleInstance) { + perform_desktop_action(app, action); + } })) .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_log::Builder::new().build()) .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_shell::init()) + .plugin(tauri_plugin_store::Builder::default().build()) .manage(DesktopState::default()) .setup(|app| { migrate_legacy_shared_data(app.handle()).map_err(io::Error::other)?; + recover_interrupted_activation(app.handle(), &app.state::()) + .map_err(io::Error::other)?; + if let Ok(paths) = desktop_paths(app.handle()) { + log_runtime_reconciliation(&paths); + } + if let Err(error) = initialize_target_profiles(app.handle()) { + log::error!("Target profile initialization failed: {error}"); + } create_tray(app)?; - if !configured_runtime(app.handle()) { - show_main_window(app.handle()); + if let Some(action) = action_for_activation(DesktopActivation::Startup) { + perform_desktop_action(app.handle(), action); } Ok(()) }) .invoke_handler(tauri::generate_handler![ runtime_manifest, - media_runtime_status, + target_state, + refresh_target_state, + discover_local_targets, + choose_local_executable, + inspect_local_target, + adopt_local_target, + select_target_profile, + delete_target_profile, + confirm_forget_target, + begin_managed_setup, + cancel_managed_setup, choose_model_directory, install_media_runtime, runtime_status, + model_directory_inventory, + prepare_managed_models, install_runtime, - launch_ui, - hide_to_tray + launch_ui ]); let app = builder .build(tauri::generate_context!()) @@ -1510,25 +3193,19 @@ pub fn run() { event: WindowEvent::CloseRequested { api, .. }, .. } if label == "main" => { - if app_handle - .state::() - .shutdown_started - .load(Ordering::Acquire) - { + if app_handle.state::().shutdown.is_cancelled() { return; } api.prevent_close(); - if configured_runtime(app_handle) { - let _ = hide_main_window(app_handle); - } else { - begin_shutdown(app_handle); + match close_action(configured_runtime(app_handle)) { + DesktopCloseAction::HideToTray => { + let _ = hide_main_window(app_handle); + } + DesktopCloseAction::Quit => begin_shutdown(app_handle), } } RunEvent::ExitRequested { api, .. } - if !app_handle - .state::() - .shutdown_started - .load(Ordering::Acquire) => + if !app_handle.state::().shutdown.is_cancelled() => { api.prevent_exit(); begin_shutdown(app_handle); @@ -1540,13 +3217,29 @@ pub fn run() { #[cfg(test)] mod tests { use super::{ - base_package_specification, capability_command_arguments, - dependency_installation_arguments, desktop_paths_from_roots, display_command, manifest, + ActivationJournal, ActivationRecovery, ActivationStage, ActiveRuntime, DesktopAction, + DesktopActivation, DesktopCloseAction, DesktopState, DraftPhase, DraftRecord, + ManagedSetupDraft, TargetTransitionCoordinator, TransitionKind, UiProcessAction, + WorkerStopSupervisor, action_for_activation, activation_recovery, + base_package_specification, capability_command_arguments, claim_browser_open, + clean_environment_from, close_action, configure_ui_service_command, + configured_runtime_status, dependency_installation_arguments, desktop_paths_from_roots, + display_command, inventory_model_directory, manifest, manifest_digest, normalize_line_endings, normalized_runtime_constraints, package_acquisition_arguments, - package_index, package_specification, required_encoder_missing, selected_capabilities, - selected_surfaces, + package_specification, read_active_runtime_snapshot, reconcile_managed_runtime_storage, + required_encoder_missing, restore_active_runtime, selected_capabilities, selected_surfaces, + ui_process_action, write_activation_journal, write_active_runtime, + }; + use std::{ + ffi::OsStr, + fs, + path::{Path, PathBuf}, + process::Command, + sync::{ + Arc, + atomic::{AtomicUsize, Ordering}, + }, }; - use std::path::{Path, PathBuf}; #[test] fn desktop_runtime_is_private_while_product_data_is_shared() { @@ -1571,6 +3264,463 @@ mod tests { paths.active_runtime, PathBuf::from("private").join("active-runtime.json") ); + assert_eq!( + paths.activation_journal, + PathBuf::from("private").join("activation-journal.json") + ); + } + + #[test] + fn managed_commands_discard_hostile_inherited_environment_and_restore_owned_roots() { + let paths = + desktop_paths_from_roots(Path::new("private"), Path::new("cache"), Path::new("local")); + let environment = clean_environment_from( + &paths, + [ + ("PATH".into(), "safe-path".into()), + ("VIDXP_DATA_DIR".into(), "attacker-data".into()), + ("VIDXP_MODEL_CACHE".into(), "attacker-models".into()), + ("PYTHONPATH".into(), "attacker-python".into()), + ("VIRTUAL_ENV".into(), "attacker-venv".into()), + ("PIP_INDEX_URL".into(), "attacker-index".into()), + ("CONDA_PREFIX".into(), "attacker-conda".into()), + ("UV_INDEX".into(), "attacker-uv".into()), + ], + ) + .into_iter() + .collect::>(); + + assert_eq!( + environment.get("PATH").map(String::as_str), + Some("safe-path") + ); + assert_eq!( + environment.get("VIDXP_DATA_DIR").map(String::as_str), + Some(paths.data.to_string_lossy().as_ref()) + ); + assert_eq!( + environment.get("VIDXP_MODEL_CACHE").map(String::as_str), + Some(paths.models.to_string_lossy().as_ref()) + ); + for rejected in [ + "PYTHONPATH", + "VIRTUAL_ENV", + "PIP_INDEX_URL", + "CONDA_PREFIX", + "UV_INDEX", + ] { + assert!(!environment.contains_key(rejected)); + } + } + + #[test] + fn interrupted_activation_never_recommits_after_rollback_begins() { + assert_eq!( + activation_recovery(&ActivationStage::Prepared, false), + ActivationRecovery::RollBack + ); + assert_eq!( + activation_recovery(&ActivationStage::ProfileWritten, false), + ActivationRecovery::RollBack + ); + assert_eq!( + activation_recovery(&ActivationStage::ProfileWritten, true), + ActivationRecovery::Complete + ); + assert_eq!( + activation_recovery(&ActivationStage::Committed, false), + ActivationRecovery::Complete + ); + for stage in [ActivationStage::RollingBack, ActivationStage::RolledBack] { + assert_eq!( + activation_recovery(&stage, true), + ActivationRecovery::RollBack + ); + } + } + + #[test] + fn concurrent_target_transitions_return_a_stable_conflict() { + let state = DesktopState::default(); + let first = TargetTransitionCoordinator::begin(&state, TransitionKind::Adopt) + .expect("first transition"); + let conflict = TargetTransitionCoordinator::begin(&state, TransitionKind::Select) + .err() + .expect("conflict"); + + assert_eq!( + conflict.code, + crate::target_profiles::TargetErrorCode::OperationConflict + ); + drop(first); + assert!(TargetTransitionCoordinator::begin(&state, TransitionKind::Select).is_ok()); + } + + #[test] + fn shutdown_tracking_waits_for_probe_install_model_and_browser_operations() { + let state = DesktopState::default(); + let probe = state.active_operations.register().expect("probe"); + let install = state.active_operations.register().expect("package install"); + let models = state + .active_operations + .register() + .expect("model preparation"); + let browser = state.active_operations.register().expect("browser startup"); + assert!( + !state + .active_operations + .wait_until_idle(std::time::Instant::now() + std::time::Duration::from_millis(20)) + ); + drop((probe, install, models, browser)); + assert!( + state + .active_operations + .wait_until_idle(std::time::Instant::now() + std::time::Duration::from_secs(1)) + ); + } + + #[test] + fn concurrent_cancellation_registration_preserves_the_shutdown_owner() { + let state = DesktopState::default(); + let operation_a = super::OperationCancellationGuard::register(&state).expect("operation A"); + let token_a = operation_a.token(); + assert_eq!( + super::OperationCancellationGuard::register(&state) + .err() + .as_deref(), + Some("Another cancellable Desktop operation is already active.") + ); + assert!( + state + .operation_cancellation + .lock() + .expect("cancellation slot") + .as_ref() + .is_some_and(|token| token.same(&token_a)) + ); + state.shutdown.cancel(); + super::cancel_active_operation(&state); + assert!(state.shutdown.is_cancelled()); + assert!(token_a.is_cancelled()); + drop(operation_a); + assert!( + state + .operation_cancellation + .lock() + .expect("cancellation slot") + .is_none() + ); + assert!( + state + .active_operations + .wait_until_idle(std::time::Instant::now() + std::time::Duration::from_secs(1)) + ); + } + + fn worker_supervisor_fixture() -> ( + Arc, + Arc, + super::DesktopPaths, + ) { + let stops = Arc::new(AtomicUsize::new(0)); + let observed = stops.clone(); + let supervisor = Arc::new(WorkerStopSupervisor::with_stopper(Arc::new( + move |_runtime, _paths, _deadline| { + observed.fetch_add(1, Ordering::SeqCst); + }, + ))); + let paths = + desktop_paths_from_roots(Path::new("private"), Path::new("cache"), Path::new("local")); + (supervisor, stops, paths) + } + + #[test] + fn worker_owner_stops_once_on_normal_completion() { + let (supervisor, stops, paths) = worker_supervisor_fixture(); + let mut worker = supervisor + .register(PathBuf::from("runtime"), paths) + .expect("worker registration"); + worker.stop_before(std::time::Instant::now() + std::time::Duration::from_secs(1)); + drop(worker); + assert_eq!(stops.load(Ordering::SeqCst), 1); + } + + #[test] + fn worker_owner_stops_once_when_cancelled_or_failed() { + for _outcome in ["cancelled", "failed"] { + let (supervisor, stops, paths) = worker_supervisor_fixture(); + let worker = supervisor + .register(PathBuf::from("runtime"), paths) + .expect("worker registration"); + drop(worker); + assert_eq!(stops.load(Ordering::SeqCst), 1); + } + } + + #[test] + fn shutdown_claims_an_active_worker_and_prevents_duplicate_stop() { + let (supervisor, stops, paths) = worker_supervisor_fixture(); + let worker = supervisor + .register(PathBuf::from("runtime"), paths) + .expect("worker registration"); + assert_eq!( + supervisor + .stop_active_before(std::time::Instant::now() + std::time::Duration::from_secs(1)), + Some(PathBuf::from("runtime")) + ); + drop(worker); + assert_eq!(stops.load(Ordering::SeqCst), 1); + assert_eq!( + supervisor + .stop_active_before(std::time::Instant::now() + std::time::Duration::from_secs(1)), + Some(PathBuf::from("runtime")) + ); + assert_eq!(stops.load(Ordering::SeqCst), 1); + } + + #[test] + fn managed_draft_cancellation_is_scoped_and_rejected_while_applying() { + let state = DesktopState::default(); + state.transition.lock().expect("transition").draft = Some(DraftRecord { + draft: ManagedSetupDraft { + id: "draft-current".into(), + previous_profile_id: Some("local-1".into()), + }, + phase: DraftPhase::Draft, + }); + + let stale = TargetTransitionCoordinator::cancel_draft(&state, "draft-stale") + .expect_err("stale draft"); + assert_eq!( + stale.code, + crate::target_profiles::TargetErrorCode::DraftMismatch + ); + + let applying = TargetTransitionCoordinator::begin_apply( + &state, + "draft-current", + TransitionKind::InstallRuntime, + ) + .expect("apply"); + let conflict = TargetTransitionCoordinator::cancel_draft(&state, "draft-current") + .expect_err("applying draft"); + assert_eq!( + conflict.code, + crate::target_profiles::TargetErrorCode::DraftApplying + ); + drop(applying); + TargetTransitionCoordinator::cancel_draft(&state, "draft-current") + .expect("cancel settled draft"); + assert_eq!( + state + .transition + .lock() + .expect("transition") + .draft + .as_ref() + .expect("draft") + .phase, + DraftPhase::Cancelled + ); + let finished = TargetTransitionCoordinator::cancel_draft(&state, "draft-current") + .expect_err("finished draft"); + assert_eq!( + finished.code, + crate::target_profiles::TargetErrorCode::DraftMismatch + ); + } + + #[test] + fn previous_runtime_snapshot_accepts_current_old_malformed_and_missing_pointers() { + let root = std::env::temp_dir().join(format!( + "vidxp-active-snapshot-{}-{}", + std::process::id(), + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .expect("clock") + .as_nanos() + )); + let _ = fs::remove_dir_all(&root); + fs::create_dir_all(root.join("private")).expect("private directory"); + let paths = desktop_paths_from_roots( + &root.join("private"), + &root.join("cache"), + &root.join("local"), + ); + assert_eq!(read_active_runtime_snapshot(&paths).expect("missing"), None); + + for bytes in [ + br#"{"schema_version":2,"manifest_sha256":"current"}"#.as_slice(), + br#"{"schema_version":2,"manifest_sha256":"old"}"#.as_slice(), + br#"not-json"#.as_slice(), + ] { + fs::write(&paths.active_runtime, bytes).expect("pointer"); + assert_eq!( + read_active_runtime_snapshot(&paths).expect("snapshot"), + Some(bytes.to_vec()) + ); + restore_active_runtime(&paths, Some(bytes)).expect("restore"); + assert_eq!(fs::read(&paths.active_runtime).expect("restored"), bytes); + } + restore_active_runtime(&paths, None).expect("remove pointer"); + assert!(!paths.active_runtime.exists()); + let _ = fs::remove_dir_all(root); + } + + #[test] + fn runtime_reconciliation_preserves_authorities_and_bounds_repeated_updates() { + let root = std::env::temp_dir().join(format!( + "vidxp-runtime-reconcile-{}-{}", + std::process::id(), + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .expect("clock") + .as_nanos() + )); + let paths = desktop_paths_from_roots( + &root.join("private"), + &root.join("cache"), + &root.join("local"), + ); + fs::create_dir_all(&paths.runtimes).expect("runtimes"); + let profile = |digest: char, generation: u8| { + format!("{}-{generation}", digest.to_string().repeat(64)) + }; + let active_profile = profile('a', 3); + let candidate_profile = profile('b', 4); + let previous_profile = profile('c', 2); + let obsolete_profile = profile('d', 1); + let staging_profile = format!(".staging-{}-5-42", "e".repeat(64)); + for name in [ + &active_profile, + &candidate_profile, + &previous_profile, + &obsolete_profile, + &staging_profile, + "external-runtime", + ] { + fs::create_dir_all(paths.runtimes.join(name)).expect("runtime directory"); + fs::write(paths.runtimes.join(name).join("payload"), b"runtime").expect("payload"); + } + let runtime = |profile: String| ActiveRuntime { + schema_version: 2, + manifest_sha256: manifest_digest(), + profile, + package_version: "0.4.0-b".into(), + capabilities: vec!["scene".into()], + surfaces: vec!["browser".into()], + model_directory: paths.models.clone(), + }; + let active = runtime(active_profile.clone()); + write_active_runtime(&paths, &active).expect("active pointer"); + let journal = ActivationJournal { + schema_version: 2, + stage: ActivationStage::Prepared, + previous_active_bytes: Some( + serde_json::to_vec(&runtime(previous_profile.clone())).expect("previous"), + ), + previous_targets: crate::target_profiles::TargetState::default(), + candidate_active: runtime(candidate_profile.clone()), + candidate_targets: crate::target_profiles::TargetState::default(), + }; + write_activation_journal(&paths, &journal).expect("journal"); + + let report = reconcile_managed_runtime_storage(&paths); + assert_eq!(report.removed_directories, 2); + assert!(report.reclaimed_bytes > 0); + for retained in [ + &active_profile, + &candidate_profile, + &previous_profile, + "external-runtime", + ] { + assert!( + paths.runtimes.join(retained).exists(), + "retained {retained}" + ); + } + assert!(!paths.runtimes.join(obsolete_profile).exists()); + assert!(!paths.runtimes.join(staging_profile).exists()); + + fs::remove_file(&paths.activation_journal).expect("clear journal"); + let report = reconcile_managed_runtime_storage(&paths); + assert_eq!(report.removed_directories, 2); + assert!(paths.runtimes.join(active_profile).exists()); + assert!(paths.runtimes.join("external-runtime").exists()); + let _ = fs::remove_dir_all(root); + } + + #[test] + fn corrupt_active_pointer_preserves_unidentified_finalized_runtimes() { + let root = std::env::temp_dir().join(format!( + "vidxp-corrupt-pointer-reconcile-{}-{}", + std::process::id(), + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .expect("clock") + .as_nanos() + )); + let paths = desktop_paths_from_roots( + &root.join("private"), + &root.join("cache"), + &root.join("local"), + ); + fs::create_dir_all(&paths.runtimes).expect("runtimes"); + let finalized = format!("{}-1", "a".repeat(64)); + fs::create_dir_all(paths.runtimes.join(&finalized)).expect("finalized runtime"); + fs::write(&paths.active_runtime, b"not-json").expect("corrupt pointer"); + + let report = reconcile_managed_runtime_storage(&paths); + assert_eq!(report.removed_directories, 0); + assert!(paths.runtimes.join(finalized).exists()); + let _ = fs::remove_dir_all(root); + } + + fn status_fixture(model_directory: &str) -> ActiveRuntime { + ActiveRuntime { + schema_version: 2, + manifest_sha256: manifest_digest(), + profile: "a".repeat(64) + "-1", + package_version: "0.4.0-b".into(), + capabilities: vec!["scene".into()], + surfaces: vec!["browser".into()], + model_directory: PathBuf::from(model_directory), + } + } + + #[test] + fn missing_ffmpeg_preserves_the_managed_runtime_configuration() { + let status = configured_runtime_status( + status_fixture("custom-models"), + vec!["FFmpeg was not found.".into()], + ); + assert_eq!(status.state, super::RuntimeState::Broken); + assert_eq!(status.capabilities, ["scene"]); + assert_eq!(status.surfaces, ["browser"]); + assert_eq!(status.model_directory, "custom-models"); + assert!(status.runtime_profile.is_some()); + } + + #[test] + fn missing_encoder_and_damaged_runtime_preserve_custom_model_storage() { + for problem in [ + "FFmpeg does not provide required encoder libx264.", + "The active runtime executable is damaged.", + ] { + let status = + configured_runtime_status(status_fixture("D:\\VidXP models"), vec![problem.into()]); + assert_eq!(status.state, super::RuntimeState::Broken); + assert_eq!(status.capabilities, ["scene"]); + assert_eq!(status.surfaces, ["browser"]); + assert_eq!(status.model_directory, "D:\\VidXP models"); + } + } + + #[test] + fn repeated_browser_open_requests_are_coalesced() { + let active = std::sync::atomic::AtomicBool::new(false); + assert!(claim_browser_open(&active)); + assert!(!claim_browser_open(&active)); } #[test] @@ -1634,7 +3784,7 @@ mod tests { let manifest = manifest().expect("manifest"); let python = Path::new("managed-python"); let constraints = Path::new("runtime-constraints.txt"); - let selected_package_index = package_index(&manifest.package_version); + let selected_package_index = manifest.dependency_index.as_str(); let acquisition = package_acquisition_arguments(&manifest, python); let dependencies = dependency_installation_arguments( &manifest, @@ -1645,15 +3795,7 @@ mod tests { true, ); - let expected_package_index = if manifest.package_version.contains('-') { - "https://test.pypi.org/simple" - } else { - "https://pypi.org/simple" - }; - - assert_eq!(selected_package_index, expected_package_index); - assert_eq!(package_index("0.3.0-b.1"), "https://test.pypi.org/simple"); - assert_eq!(package_index("0.3.0"), "https://pypi.org/simple"); + assert_eq!(selected_package_index, "https://pypi.org/simple"); assert_eq!(manifest.dependency_index, "https://pypi.org/simple"); assert!(acquisition.iter().any(|item| item == "--no-deps")); assert!( @@ -1694,6 +3836,99 @@ mod tests { assert!(required_encoder_missing(encoders, "libx265")); } + #[test] + fn desktop_ui_service_is_headless_so_only_the_desktop_opens_the_browser() { + let mut command = Command::new("vidxp"); + + configure_ui_service_command( + &mut command, + Path::new("repository"), + 43123, + Path::new("readiness.json"), + "nonce", + ); + + assert!(command.get_envs().any(|(key, value)| { + key == OsStr::new("STREAMLIT_SERVER_HEADLESS") && value == Some(OsStr::new("true")) + })); + assert!(command.get_envs().any(|(key, value)| { + key == OsStr::new("VIDXP_DESKTOP_READINESS_NONCE") && value == Some(OsStr::new("nonce")) + })); + assert_eq!( + command + .get_args() + .map(|argument| argument.to_string_lossy().into_owned()) + .collect::>(), + [ + "--index-dir", + "repository", + "ui", + "--host", + "127.0.0.1", + "--port", + "43123", + ] + ); + } + + #[test] + fn startup_and_single_instance_activation_manage_without_opening_the_browser() { + assert_eq!( + action_for_activation(DesktopActivation::Startup), + Some(DesktopAction::Manage) + ); + assert_eq!( + action_for_activation(DesktopActivation::SingleInstance), + Some(DesktopAction::Manage) + ); + } + + #[test] + fn tray_manage_browser_and_quit_actions_are_unambiguous() { + assert_eq!( + action_for_activation(DesktopActivation::Tray("manage")), + Some(DesktopAction::Manage) + ); + assert_eq!( + action_for_activation(DesktopActivation::Tray("open")), + Some(DesktopAction::OpenBrowser) + ); + assert_eq!( + action_for_activation(DesktopActivation::Tray("quit")), + Some(DesktopAction::Quit) + ); + assert_eq!( + action_for_activation(DesktopActivation::Tray("other")), + None + ); + } + + #[test] + fn repeated_browser_actions_reuse_one_service_and_target_changes_replace_it() { + assert_eq!( + ui_process_action(true, "selected", "selected"), + UiProcessAction::Reuse + ); + assert_eq!( + ui_process_action(true, "previous", "selected"), + UiProcessAction::Replace + ); + assert_eq!( + ui_process_action(false, "selected", "selected"), + UiProcessAction::Start + ); + } + + #[test] + fn closing_a_configured_desktop_hides_it_and_manage_can_restore_it() { + assert_eq!(close_action(true), DesktopCloseAction::HideToTray); + assert_eq!( + action_for_activation(DesktopActivation::Tray("manage")), + Some(DesktopAction::Manage) + ); + assert_eq!(close_action(false), DesktopCloseAction::Quit); + } + #[test] fn package_manager_command_is_presented_as_copyable_text() { assert_eq!( @@ -1706,4 +3941,59 @@ mod tests { "winget install --id Gyan.FFmpeg" ); } + + #[test] + fn populated_model_inventory_reports_totals_and_known_cache_conventions() { + let root = + std::env::temp_dir().join(format!("vidxp-model-inventory-{}", std::process::id())); + let siglip = root + .join("models--google--siglip2-base-patch16-224") + .join("snapshots") + .join("75de2d55ec2d0b4efc50b3e9ad70dba96a7b2fa2"); + let opencv = root.join("opencv-zoo"); + fs::create_dir_all(&siglip).expect("siglip directory"); + fs::create_dir_all(&opencv).expect("opencv directory"); + fs::write(siglip.join("model.safetensors"), [0_u8; 7]).expect("model file"); + fs::write(opencv.join("face_detection_yunet_2026may.onnx"), [0_u8; 5]) + .expect("artifact file"); + + let inventory = inventory_model_directory(&root); + + assert!(inventory.exists); + assert!(inventory.readable); + assert_eq!(inventory.file_count, 2); + assert_eq!(inventory.total_bytes, 12); + assert_eq!( + inventory + .recognized_models + .iter() + .map(|model| model.label.as_str()) + .collect::>(), + ["google/siglip2-base-patch16-224", "yunet"] + ); + assert!(inventory.verification_required); + assert!(inventory.detail.contains("verification required")); + fs::remove_dir_all(root).expect("remove test inventory"); + } + + #[test] + fn empty_and_unreadable_model_locations_are_typed_states() { + let root = std::env::temp_dir().join(format!( + "vidxp-empty-model-inventory-{}", + std::process::id() + )); + fs::create_dir_all(&root).expect("empty directory"); + let empty = inventory_model_directory(&root); + assert!(empty.empty); + assert!(empty.readable); + assert!(!empty.verification_required); + + let file = root.join("not-a-directory"); + fs::write(&file, b"x").expect("file location"); + let unreadable = inventory_model_directory(&file); + assert!(unreadable.exists); + assert!(!unreadable.readable); + assert!(unreadable.detail.contains("not a readable directory")); + fs::remove_dir_all(root).expect("remove test inventory"); + } } diff --git a/desktop/src-tauri/src/lifecycle.rs b/desktop/src-tauri/src/lifecycle.rs new file mode 100644 index 0000000..7d7ece0 --- /dev/null +++ b/desktop/src-tauri/src/lifecycle.rs @@ -0,0 +1,209 @@ +use std::{ + sync::{Arc, Condvar, Mutex}, + time::Instant, +}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum UiProcessAction { + Reuse, + Replace, + Start, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum DesktopAction { + Manage, + OpenBrowser, + Quit, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum DesktopCloseAction { + HideToTray, + Quit, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum DesktopActivation<'a> { + Startup, + SingleInstance, + Tray(&'a str), +} + +pub(crate) fn action_for_activation(activation: DesktopActivation<'_>) -> Option { + match activation { + DesktopActivation::Startup | DesktopActivation::SingleInstance => { + Some(DesktopAction::Manage) + } + DesktopActivation::Tray("manage") => Some(DesktopAction::Manage), + DesktopActivation::Tray("open") => Some(DesktopAction::OpenBrowser), + DesktopActivation::Tray("quit") => Some(DesktopAction::Quit), + DesktopActivation::Tray(_) => None, + } +} + +pub(crate) fn close_action(configured: bool) -> DesktopCloseAction { + if configured { + DesktopCloseAction::HideToTray + } else { + DesktopCloseAction::Quit + } +} + +pub(crate) fn ui_process_action( + running: bool, + active_profile_id: &str, + requested_profile_id: &str, +) -> UiProcessAction { + if !running { + UiProcessAction::Start + } else if active_profile_id == requested_profile_id { + UiProcessAction::Reuse + } else { + UiProcessAction::Replace + } +} + +struct OperationState { + count: usize, + accepting: bool, +} + +impl Default for OperationState { + fn default() -> Self { + Self { + count: 0, + accepting: true, + } + } +} + +#[derive(Default)] +pub(crate) struct ActiveOperations { + state: Mutex, + idle: Condvar, +} + +impl ActiveOperations { + pub(crate) fn register(self: &Arc) -> Result { + let mut state = self + .state + .lock() + .map_err(|_| "The background operation tracker is unavailable.".to_string())?; + if !state.accepting { + return Err("VidXP Desktop is shutting down.".into()); + } + state.count += 1; + drop(state); + Ok(ActiveOperationGuard { + operations: self.clone(), + }) + } + + pub(crate) fn close(&self) -> Result<(), String> { + let mut state = self + .state + .lock() + .map_err(|_| "The background operation tracker is unavailable.".to_string())?; + state.accepting = false; + if state.count == 0 { + self.idle.notify_all(); + } + Ok(()) + } + + pub(crate) fn wait_until_idle(&self, deadline: Instant) -> bool { + let Ok(mut state) = self.state.lock() else { + return false; + }; + while state.count > 0 { + let now = Instant::now(); + if now >= deadline { + return false; + } + let Ok((next, timeout)) = self.idle.wait_timeout(state, deadline - now) else { + return false; + }; + state = next; + if timeout.timed_out() && state.count > 0 { + return false; + } + } + true + } +} + +pub(crate) struct ActiveOperationGuard { + operations: Arc, +} + +impl Drop for ActiveOperationGuard { + fn drop(&mut self) { + if let Ok(mut state) = self.operations.state.lock() { + state.count = state.count.saturating_sub(1); + if state.count == 0 { + self.operations.idle.notify_all(); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::{sync::Barrier, thread, time::Duration}; + + #[test] + fn registration_succeeds_before_close_and_is_rejected_afterward() { + let operations = Arc::new(ActiveOperations::default()); + let active = operations.register().expect("registration before close"); + operations.close().expect("close"); + assert_eq!( + operations.register().err().as_deref(), + Some("VidXP Desktop is shutting down.") + ); + drop(active); + assert!(operations.wait_until_idle(Instant::now() + Duration::from_secs(1))); + } + + #[test] + fn idle_observation_after_close_cannot_race_with_a_new_registration() { + let operations = Arc::new(ActiveOperations::default()); + operations.close().expect("close"); + assert!(operations.wait_until_idle(Instant::now() + Duration::from_secs(1))); + + let contender = operations.clone(); + let result = thread::spawn(move || contender.register().map(drop)) + .join() + .expect("registration thread"); + assert_eq!(result.unwrap_err(), "VidXP Desktop is shutting down."); + assert!(operations.wait_until_idle(Instant::now() + Duration::from_secs(1))); + } + + #[test] + fn close_waits_for_an_already_registered_operation() { + let operations = Arc::new(ActiveOperations::default()); + let active = operations.register().expect("registration"); + operations.close().expect("close"); + let started = Arc::new(Barrier::new(2)); + let waiter_operations = operations.clone(); + let waiter_started = started.clone(); + let waiter = thread::spawn(move || { + waiter_started.wait(); + waiter_operations.wait_until_idle(Instant::now() + Duration::from_secs(2)) + }); + started.wait(); + thread::sleep(Duration::from_millis(20)); + assert!(!waiter.is_finished()); + drop(active); + assert!(waiter.join().expect("waiter")); + } + + #[test] + fn repeated_close_is_idempotent() { + let operations = ActiveOperations::default(); + operations.close().expect("first close"); + operations.close().expect("second close"); + assert!(operations.wait_until_idle(Instant::now() + Duration::from_secs(1))); + } +} diff --git a/desktop/src-tauri/src/media_setup.rs b/desktop/src-tauri/src/media_setup.rs new file mode 100644 index 0000000..192ed68 --- /dev/null +++ b/desktop/src-tauri/src/media_setup.rs @@ -0,0 +1,88 @@ +use std::path::PathBuf; + +pub(crate) struct SystemInstallPlan { + pub(crate) manager: String, + pub(crate) command: Vec, + pub(crate) automatic: bool, +} + +pub(crate) fn system_install_plan( + mut resolve: impl FnMut(&str) -> Option, +) -> Option { + if cfg!(windows) { + resolve("winget")?; + return Some(SystemInstallPlan { + manager: "Windows Package Manager".into(), + command: vec![ + "winget".into(), + "install".into(), + "--id".into(), + "Gyan.FFmpeg".into(), + "--exact".into(), + "--source".into(), + "winget".into(), + "--accept-package-agreements".into(), + "--accept-source-agreements".into(), + ], + automatic: true, + }); + } + if cfg!(target_os = "macos") { + let brew = resolve("brew")?; + return Some(SystemInstallPlan { + manager: "Homebrew".into(), + command: vec![ + brew.to_string_lossy().into_owned(), + "install".into(), + "ffmpeg".into(), + ], + automatic: true, + }); + } + if resolve("apt-get").is_some() { + return Some(SystemInstallPlan { + manager: "APT".into(), + command: vec![ + "sudo".into(), + "apt-get".into(), + "install".into(), + "ffmpeg".into(), + ], + automatic: false, + }); + } + if resolve("dnf").is_some() { + return Some(SystemInstallPlan { + manager: "DNF".into(), + command: vec![ + "sudo".into(), + "dnf".into(), + "install".into(), + "ffmpeg".into(), + ], + automatic: false, + }); + } + None +} + +pub(crate) fn display_command(arguments: &[String]) -> String { + arguments + .iter() + .map(|argument| { + if argument.contains(char::is_whitespace) { + format!("\"{}\"", argument.replace('"', "\\\"")) + } else { + argument.clone() + } + }) + .collect::>() + .join(" ") +} + +pub(crate) fn required_encoder_missing(output: &str, encoder: &str) -> bool { + !output + .lines() + .flat_map(|line| line.split_whitespace()) + .any(|token| token == encoder) +} diff --git a/desktop/src-tauri/src/target_profiles.rs b/desktop/src-tauri/src/target_profiles.rs new file mode 100644 index 0000000..7eb11bf --- /dev/null +++ b/desktop/src-tauri/src/target_profiles.rs @@ -0,0 +1,2079 @@ +use std::{ + collections::{BTreeSet, HashSet}, + fs, + path::{Path, PathBuf}, + process::Command, + sync::Arc, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; + +use crate::background_process::{ + self, BackgroundErrorKind, BackgroundOutput, BackgroundPolicy, CancellationToken, +}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use sha2::{Digest, Sha256}; +use tauri::{AppHandle, Wry}; +use tauri_plugin_store::{Store, StoreExt}; + +const STORE_FILE: &str = "target-profiles.json"; +const STORE_SCHEMA_KEY: &str = "schema_version"; +const PROFILES_KEY: &str = "profiles"; +const SELECTED_PROFILE_KEY: &str = "selected_profile_id"; +const CURRENT_STORE_SCHEMA_VERSION: u32 = 1; +pub const CURRENT_PROFILE_SCHEMA_VERSION: u32 = 1; +const SUPPORTED_PROBE_SCHEMA_VERSION: u32 = 1; +const SUPPORTED_PROBE_PROTOCOL_VERSION: u32 = 1; +const SUPPORTED_LAUNCH_PROTOCOL_VERSION: u32 = 2; +const PRODUCT_ID: &str = "dev.grayhat.vidxp"; +const PROBE_TIMEOUT: Duration = Duration::from_secs(10); +const VALIDATION_MAX_AGE: Duration = Duration::from_secs(24 * 60 * 60); +const MAX_PROBE_STREAM_BYTES: usize = 256 * 1024; + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum TargetKind { + ExistingLocal, + Managed, +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum LifecycleOwnership { + External, + Desktop, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum LifecycleAction { + Validate, + Launch, + Install, + BroadProcessStop, +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum TargetErrorCode { + ExecutableMissing, + ExecutableInvalid, + ProbeCouldNotStart, + ProbeFailed, + ProbeTimeout, + ProbeOutputTooLarge, + MalformedProbe, + NotVidxp, + ProbeChallengeMismatch, + LauncherIdentityMismatch, + UnsupportedProbeSchema, + UnsupportedProbeProtocol, + UnsupportedLaunchProtocol, + UnsupportedLaunchContract, + InvalidDataRoot, + StoreUnavailable, + StoreCorrupt, + UnsupportedStoreSchema, + UnsupportedProfileSchema, + ProfileMalformed, + ProfileNotFound, + SelectedProfileMissing, + ValidationRequired, + ValidationStale, + LifecycleForbidden, + ManagedRuntimeUnavailable, + OperationConflict, + DraftMismatch, + DraftApplying, + ManagedProfileOwned, +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct TargetError { + pub code: TargetErrorCode, + pub message: String, +} + +impl TargetError { + fn new(code: TargetErrorCode, message: impl Into) -> Self { + Self { + code, + message: message.into(), + } + } +} + +impl std::fmt::Display for TargetError { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "{}", self.message) + } +} + +impl std::error::Error for TargetError {} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct RuntimeIdentity { + pub python_executable: PathBuf, + pub python_version: String, + pub implementation: String, + pub prefix: PathBuf, + pub base_prefix: PathBuf, +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct FrontendCapability { + pub available: bool, + pub launchable: bool, + pub optional: bool, + pub code: String, + pub message: String, + pub remediation: String, +} + +impl Default for FrontendCapability { + fn default() -> Self { + Self { + available: false, + launchable: false, + optional: true, + code: "frontend_unavailable".into(), + message: "The optional browser interface is not installed.".into(), + remediation: "Use this installation's own package-management workflow to install the VidXP frontend extra, then revalidate.".into(), + } + } +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct TargetProfile { + pub id: String, + pub display_name: String, + pub schema_version: u32, + pub kind: TargetKind, + pub lifecycle_ownership: LifecycleOwnership, + pub executable: PathBuf, + pub data_root: PathBuf, + pub repository_root: PathBuf, + pub observed_vidxp_version: String, + pub probe_schema_version: u32, + pub probe_protocol_version: u32, + pub launch_protocol_version: u32, + pub runtime: Option, + pub frontend: FrontendCapability, + pub last_successful_validation_at: Option, + pub validation_error: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub managed_runtime_profile: Option, + #[serde(default)] + pub capabilities: Vec, + #[serde(default)] + pub surfaces: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub model_directory: Option, +} + +impl TargetProfile { + pub fn is_ready(&self, now: u64) -> bool { + self.validation_error.is_none() + && self.last_successful_validation_at.is_some_and(|validated| { + now.saturating_sub(validated) <= VALIDATION_MAX_AGE.as_secs() + }) + } +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct DiscoveredTarget { + pub executable: PathBuf, +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct ValidatedTarget { + pub executable: PathBuf, + pub product_version: String, + pub probe_schema_version: u32, + pub probe_protocol_version: u32, + pub launch_protocol_version: u32, + pub runtime: RuntimeIdentity, + pub data_root: PathBuf, + pub repository_root: PathBuf, + pub model_root: PathBuf, + pub frontend: FrontendCapability, + pub validated_at: u64, +} + +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +pub struct TargetState { + pub profiles: Vec, + pub selected_profile_id: Option, + pub issues: Vec, +} + +impl TargetState { + pub fn selected_profile(&self) -> Option<&TargetProfile> { + let selected = self.selected_profile_id.as_deref()?; + self.profiles.iter().find(|profile| profile.id == selected) + } +} + +#[derive(Clone, Debug)] +pub struct ManagedRuntimeProjection { + pub runtime_profile: String, + pub executable: PathBuf, + pub data_root: PathBuf, + pub repository_root: PathBuf, + pub model_directory: PathBuf, + pub package_version: String, + pub capabilities: Vec, + pub surfaces: Vec, +} + +#[derive(Debug, Deserialize, Serialize)] +struct ProbeRuntime { + python_executable: PathBuf, + python_version: String, + implementation: String, + prefix: PathBuf, + base_prefix: PathBuf, +} + +#[derive(Debug, Deserialize, Serialize)] +struct ProbeLaunchContract { + protocol_version: u32, + surface: String, + command: String, +} + +#[derive(Debug, Default, Deserialize, Serialize)] +struct ProbeCapabilities { + #[serde(default)] + frontend: FrontendCapability, +} + +#[derive(Debug, Deserialize, Serialize)] +struct ProbeDocument { + product: String, + product_version: String, + schema_version: u32, + protocol_version: u32, + launch_contract: ProbeLaunchContract, + request_id: String, + launcher: PathBuf, + runtime: ProbeRuntime, + data_root: PathBuf, + repository_root: PathBuf, + model_root: PathBuf, + #[serde(default)] + capabilities: ProbeCapabilities, +} + +#[derive(Clone, Debug, Default)] +struct DecodedState { + profiles: Vec, + selected_profile_id: Option, + issues: Vec, + changed: bool, +} + +struct ProbeOutput { + success: bool, + stdout: Vec, + stderr: Vec, +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum InspectionState { + ReadyToUse, + UpdateRequired, + CannotStart, +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct TargetInspection { + pub state: InspectionState, + pub adoptable: bool, + pub executable: PathBuf, + pub reported_version: Option, + pub probe_compatible: bool, + pub launch_compatible: bool, + pub validated: Option, + pub message: String, + pub remediation: String, + pub technical_details: Option, +} + +fn unix_timestamp() -> Result { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|duration| duration.as_secs()) + .map_err(|error| { + TargetError::new( + TargetErrorCode::ValidationRequired, + format!("The system clock is invalid: {error}"), + ) + }) +} + +fn canonical_executable(path: &Path) -> Result { + if !path.exists() { + return Err(TargetError::new( + TargetErrorCode::ExecutableMissing, + format!( + "The selected VidXP executable no longer exists at {}.", + path.display() + ), + )); + } + if !path.is_file() { + return Err(TargetError::new( + TargetErrorCode::ExecutableInvalid, + "The selected VidXP path is not an executable file.", + )); + } + fs::canonicalize(path).map_err(|error| { + TargetError::new( + TargetErrorCode::ExecutableInvalid, + format!("The selected VidXP executable could not be resolved: {error}"), + ) + }) +} + +fn canonical_reported_launcher(reported: &Path, selected: &Path) -> Result { + if let Ok(canonical) = canonical_executable(reported) { + return (canonical == selected).then_some(canonical).ok_or_else(|| { + TargetError::new( + TargetErrorCode::LauncherIdentityMismatch, + "The probe response belongs to a different launcher than the selected executable.", + ) + }); + } + #[cfg(windows)] + if !reported.exists() && reported.extension().is_none() { + let reported_parent = reported + .parent() + .and_then(|parent| fs::canonicalize(parent).ok()); + let selected_parent = selected + .parent() + .and_then(|parent| fs::canonicalize(parent).ok()); + if reported_parent == selected_parent && reported.file_name() == selected.file_stem() { + return Ok(selected.to_path_buf()); + } + } + Err(TargetError::new( + TargetErrorCode::LauncherIdentityMismatch, + "The probe did not report a usable VidXP launcher identity.", + )) +} + +fn challenge_for(executable: &Path) -> Result { + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_err(|error| { + TargetError::new( + TargetErrorCode::ValidationRequired, + format!("The system clock is invalid: {error}"), + ) + })? + .as_nanos(); + let seed = format!("{}:{now}:{}", executable.display(), std::process::id()); + Ok(hex::encode(Sha256::digest(seed.as_bytes()))) +} + +fn collect_command_output( + executable: &Path, + arguments: &[&str], + operation: &str, + cancellation: Option<&CancellationToken>, +) -> Result { + let mut command = Command::new(executable); + command.args(arguments); + collect_prepared_command_output(command, operation, cancellation) +} + +fn collect_prepared_command_output( + command: Command, + operation: &str, + cancellation: Option<&CancellationToken>, +) -> Result { + let BackgroundOutput { + status, + stdout, + stderr, + } = background_process::run( + command, + BackgroundPolicy { + timeout: PROBE_TIMEOUT, + max_output_bytes: MAX_PROBE_STREAM_BYTES, + }, + cancellation, + ) + .map_err(|error| { + let code = match error.kind { + BackgroundErrorKind::Start => TargetErrorCode::ProbeCouldNotStart, + BackgroundErrorKind::Timeout => TargetErrorCode::ProbeTimeout, + BackgroundErrorKind::OutputTooLarge => TargetErrorCode::ProbeOutputTooLarge, + _ => TargetErrorCode::ProbeFailed, + }; + TargetError::new(code, format!("{operation} failed: {}.", error.detail)) + })?; + Ok(ProbeOutput { + success: status.success(), + stdout, + stderr, + }) +} + +pub(crate) fn validate_executable_using( + path: &Path, + desktop_version: &str, + cancellation: Option<&CancellationToken>, + command_for: impl FnOnce(&Path) -> Command, +) -> Result { + validate_executable_with(path, desktop_version, |canonical, version, request_id| { + let mut command = command_for(canonical); + command.args([ + "desktop-probe", + "--json", + "--desktop-version", + version, + "--request-id", + request_id, + ]); + collect_prepared_command_output( + command, + "The managed VidXP compatibility probe", + cancellation, + ) + }) +} + +fn collect_probe_output( + executable: &Path, + desktop_version: &str, + request_id: &str, +) -> Result { + collect_command_output( + executable, + &[ + "desktop-probe", + "--json", + "--desktop-version", + desktop_version, + "--request-id", + request_id, + ], + "The VidXP compatibility probe", + None, + ) +} + +#[cfg(test)] +fn collect_version_output(executable: &Path) -> Result { + collect_command_output(executable, &["--version"], "The VidXP version check", None) +} + +fn validate_probe_document( + canonical: &Path, + request_id: &str, + document: ProbeDocument, + now: u64, +) -> Result { + if document.product != PRODUCT_ID { + return Err(TargetError::new( + TargetErrorCode::NotVidxp, + "The selected executable did not identify itself as VidXP.", + )); + } + if document.request_id != request_id { + return Err(TargetError::new( + TargetErrorCode::ProbeChallengeMismatch, + "The selected executable did not return the desktop validation challenge.", + )); + } + if document.schema_version != SUPPORTED_PROBE_SCHEMA_VERSION { + return Err(TargetError::new( + TargetErrorCode::UnsupportedProbeSchema, + format!( + "This executable uses desktop probe schema {}; VidXP desktop supports schema {}.", + document.schema_version, SUPPORTED_PROBE_SCHEMA_VERSION + ), + )); + } + if document.protocol_version != SUPPORTED_PROBE_PROTOCOL_VERSION { + return Err(TargetError::new( + TargetErrorCode::UnsupportedProbeProtocol, + format!( + "This executable uses desktop probe protocol {}; VidXP desktop supports protocol {}.", + document.protocol_version, SUPPORTED_PROBE_PROTOCOL_VERSION + ), + )); + } + if document.launch_contract.protocol_version != SUPPORTED_LAUNCH_PROTOCOL_VERSION { + return Err(TargetError::new( + TargetErrorCode::UnsupportedLaunchProtocol, + format!( + "This executable uses desktop launch protocol {}; VidXP desktop supports protocol {}.", + document.launch_contract.protocol_version, SUPPORTED_LAUNCH_PROTOCOL_VERSION + ), + )); + } + if document.launch_contract.surface != "browser" || document.launch_contract.command != "ui" { + return Err(TargetError::new( + TargetErrorCode::UnsupportedLaunchContract, + "This executable does not provide the supported VidXP browser launch contract.", + )); + } + canonical_reported_launcher(&document.launcher, canonical)?; + for (label, path) in [ + ("data", &document.data_root), + ("repository", &document.repository_root), + ("model", &document.model_root), + ("Python executable", &document.runtime.python_executable), + ("Python prefix", &document.runtime.prefix), + ("Python base prefix", &document.runtime.base_prefix), + ] { + if !path.is_absolute() { + return Err(TargetError::new( + TargetErrorCode::InvalidDataRoot, + format!("The probe reported a non-absolute {label} path."), + )); + } + } + Ok(ValidatedTarget { + executable: canonical.to_path_buf(), + product_version: document.product_version, + probe_schema_version: document.schema_version, + probe_protocol_version: document.protocol_version, + launch_protocol_version: document.launch_contract.protocol_version, + runtime: RuntimeIdentity { + python_executable: document.runtime.python_executable, + python_version: document.runtime.python_version, + implementation: document.runtime.implementation, + prefix: document.runtime.prefix, + base_prefix: document.runtime.base_prefix, + }, + data_root: document.data_root, + repository_root: document.repository_root, + model_root: document.model_root, + frontend: document.capabilities.frontend, + validated_at: now, + }) +} + +fn validate_executable_with( + path: &Path, + desktop_version: &str, + run_probe: impl FnOnce(&Path, &str, &str) -> Result, +) -> Result { + let canonical = canonical_executable(path)?; + let request_id = challenge_for(&canonical)?; + let output = run_probe(&canonical, desktop_version, &request_id)?; + if !output.success { + return Err(TargetError::new( + TargetErrorCode::ProbeFailed, + "The selected executable rejected the VidXP compatibility probe.", + )); + } + let document: ProbeDocument = serde_json::from_slice(&output.stdout).map_err(|_| { + TargetError::new( + TargetErrorCode::MalformedProbe, + "The selected executable did not return a valid VidXP compatibility response.", + ) + })?; + validate_probe_document(&canonical, &request_id, document, unix_timestamp()?) +} + +fn inspect_executable_with( + path: &Path, + desktop_version: &str, + run_probe: impl FnOnce(&Path, &str, &str) -> Result, + run_version: impl FnOnce(&Path) -> Result, +) -> Result { + let canonical = canonical_executable(path)?; + let request_id = challenge_for(&canonical)?; + let probe_result = run_probe(&canonical, desktop_version, &request_id).and_then(|output| { + if !output.success { + let detail = String::from_utf8_lossy(&output.stderr).trim().to_owned(); + return Err(TargetError::new( + TargetErrorCode::ProbeFailed, + if detail.is_empty() { + "The selected executable rejected the VidXP compatibility probe.".into() + } else { + format!("The compatibility probe failed: {detail}") + }, + )); + } + let document: ProbeDocument = serde_json::from_slice(&output.stdout).map_err(|_| { + TargetError::new( + TargetErrorCode::MalformedProbe, + "The selected executable did not return a valid VidXP compatibility response.", + ) + })?; + validate_probe_document(&canonical, &request_id, document, unix_timestamp()?) + }); + match probe_result { + Ok(validated) => Ok(TargetInspection { + state: InspectionState::ReadyToUse, + adoptable: true, + executable: canonical, + reported_version: Some(validated.product_version.clone()), + probe_compatible: true, + launch_compatible: true, + validated: Some(validated), + message: "This installation supports the Desktop compatibility and launch contracts." + .into(), + remediation: String::new(), + technical_details: None, + }), + Err(probe_error) => { + let version = run_version(&canonical); + match version { + Ok(output) if output.success && !output.stdout.is_empty() => { + let reported = String::from_utf8_lossy(&output.stdout).trim().to_owned(); + Ok(TargetInspection { + state: InspectionState::UpdateRequired, + adoptable: false, + executable: canonical, + reported_version: Some(reported.strip_prefix("VidXP ").unwrap_or(&reported).to_owned()), + probe_compatible: false, + launch_compatible: false, + validated: None, + message: "This VidXP installation does not provide a compatible Desktop probe and launch contract.".into(), + remediation: "Update this external installation with its own package-management workflow, then check it again.".into(), + technical_details: Some(probe_error.message), + }) + } + Ok(output) => { + let detail = String::from_utf8_lossy(&output.stderr).trim().to_owned(); + Ok(TargetInspection { + state: InspectionState::CannotStart, + adoptable: false, + executable: canonical, + reported_version: None, + probe_compatible: false, + launch_compatible: false, + validated: None, + message: "This executable could not start well enough to report its version.".into(), + remediation: "Repair this external installation with its own package-management workflow, then check it again.".into(), + technical_details: Some(if detail.is_empty() { probe_error.message } else { detail }), + }) + } + Err(version_error) => Ok(TargetInspection { + state: InspectionState::CannotStart, + adoptable: false, + executable: canonical, + reported_version: None, + probe_compatible: false, + launch_compatible: false, + validated: None, + message: "This executable could not start well enough to report its version.".into(), + remediation: "Repair this external installation with its own package-management workflow, then check it again.".into(), + technical_details: Some(format!("{} {}", probe_error.message, version_error.message)), + }), + } + } + } +} + +pub fn validate_executable( + path: &Path, + desktop_version: &str, +) -> Result { + validate_executable_with(path, desktop_version, collect_probe_output) +} + +#[cfg(test)] +fn inspect_executable(path: &Path, desktop_version: &str) -> Result { + inspect_executable_with( + path, + desktop_version, + collect_probe_output, + collect_version_output, + ) +} + +pub fn inspect_executable_with_cancellation( + path: &Path, + desktop_version: &str, + cancellation: &CancellationToken, +) -> Result { + inspect_executable_with( + path, + desktop_version, + |executable, version, request_id| { + collect_command_output( + executable, + &[ + "desktop-probe", + "--json", + "--desktop-version", + version, + "--request-id", + request_id, + ], + "The VidXP compatibility probe", + Some(cancellation), + ) + }, + |executable| { + collect_command_output( + executable, + &["--version"], + "The VidXP version check", + Some(cancellation), + ) + }, + ) +} + +pub fn discover_local_targets() -> Vec { + let mut seen = HashSet::new(); + let mut discovered = which::which_all("vidxp") + .into_iter() + .flatten() + .filter_map(|candidate| canonical_executable(&candidate).ok()) + .filter(|candidate| seen.insert(candidate.clone())) + .map(|executable| DiscoveredTarget { executable }) + .collect::>(); + discovered.sort_by(|left, right| left.executable.cmp(&right.executable)); + discovered +} + +pub fn authorize_lifecycle( + profile: &TargetProfile, + action: LifecycleAction, +) -> Result<(), TargetError> { + let structurally_valid = matches!( + (&profile.kind, &profile.lifecycle_ownership), + (TargetKind::ExistingLocal, LifecycleOwnership::External) + | (TargetKind::Managed, LifecycleOwnership::Desktop) + ); + if !structurally_valid { + return Err(TargetError::new( + TargetErrorCode::ProfileMalformed, + "The target profile has an invalid lifecycle ownership declaration.", + )); + } + if profile.lifecycle_ownership == LifecycleOwnership::External + && matches!( + action, + LifecycleAction::Install | LifecycleAction::BroadProcessStop + ) + { + return Err(TargetError::new( + TargetErrorCode::LifecycleForbidden, + "This VidXP installation is externally owned and cannot be changed or broadly stopped by the desktop.", + )); + } + Ok(()) +} + +pub fn authorize_managed_runtime_action( + profile: &TargetProfile, + runtime_profile: &str, +) -> Result<(), TargetError> { + authorize_lifecycle(profile, LifecycleAction::Install)?; + if profile.kind != TargetKind::Managed + || profile.managed_runtime_profile.as_deref() != Some(runtime_profile) + { + return Err(TargetError::new( + TargetErrorCode::ValidationRequired, + "The selected managed target no longer matches the active Desktop runtime.", + )); + } + Ok(()) +} + +fn stable_local_profile_id(executable: &Path) -> String { + let digest = hex::encode(Sha256::digest(executable.to_string_lossy().as_bytes())); + format!("local-{}", &digest[..24]) +} + +fn local_profile(validated: ValidatedTarget, display_name: Option) -> TargetProfile { + let default_name = validated + .executable + .file_name() + .and_then(|name| name.to_str()) + .map_or_else( + || "Local VidXP".into(), + |name| format!("Local VidXP ({name})"), + ); + TargetProfile { + id: stable_local_profile_id(&validated.executable), + display_name: display_name + .map(|name| name.trim().to_owned()) + .filter(|name| !name.is_empty()) + .unwrap_or(default_name), + schema_version: CURRENT_PROFILE_SCHEMA_VERSION, + kind: TargetKind::ExistingLocal, + lifecycle_ownership: LifecycleOwnership::External, + executable: validated.executable, + data_root: validated.data_root, + repository_root: validated.repository_root, + observed_vidxp_version: validated.product_version, + probe_schema_version: validated.probe_schema_version, + probe_protocol_version: validated.probe_protocol_version, + launch_protocol_version: validated.launch_protocol_version, + runtime: Some(validated.runtime), + frontend: validated.frontend, + last_successful_validation_at: Some(validated.validated_at), + validation_error: None, + managed_runtime_profile: None, + capabilities: Vec::new(), + surfaces: Vec::new(), + model_directory: None, + } +} + +fn managed_profile(managed: ManagedRuntimeProjection) -> TargetProfile { + TargetProfile { + id: format!("managed-{}", managed.runtime_profile), + display_name: "Desktop-managed VidXP".into(), + schema_version: CURRENT_PROFILE_SCHEMA_VERSION, + kind: TargetKind::Managed, + lifecycle_ownership: LifecycleOwnership::Desktop, + executable: managed.executable, + data_root: managed.data_root, + repository_root: managed.repository_root, + observed_vidxp_version: managed.package_version, + probe_schema_version: 0, + probe_protocol_version: 0, + launch_protocol_version: 0, + runtime: None, + frontend: FrontendCapability { + available: managed.surfaces.iter().any(|surface| surface == "browser"), + launchable: false, + optional: true, + code: "validation_required".into(), + message: "The managed runtime must be revalidated before use.".into(), + remediation: "Complete managed runtime validation before launch.".into(), + }, + last_successful_validation_at: None, + validation_error: Some(TargetError::new( + TargetErrorCode::ValidationRequired, + "The migrated managed runtime must be revalidated before use.", + )), + managed_runtime_profile: Some(managed.runtime_profile), + capabilities: managed.capabilities, + surfaces: managed.surfaces, + model_directory: Some(managed.model_directory), + } +} + +fn reconcile_managed_profile( + existing: Option<&TargetProfile>, + managed: ManagedRuntimeProjection, +) -> TargetProfile { + let mut profile = managed_profile(managed); + if let Some(existing) = existing { + profile.display_name = existing.display_name.clone(); + } + profile +} + +fn validate_profile_structure(profile: &TargetProfile) -> Result<(), TargetError> { + if profile.schema_version != CURRENT_PROFILE_SCHEMA_VERSION { + return Err(TargetError::new( + TargetErrorCode::UnsupportedProfileSchema, + format!( + "Target profile {} uses unsupported schema version {}.", + profile.id, profile.schema_version + ), + )); + } + if profile.id.trim().is_empty() || profile.display_name.trim().is_empty() { + return Err(TargetError::new( + TargetErrorCode::ProfileMalformed, + "A stored target profile is missing its stable identity or display name.", + )); + } + authorize_lifecycle(profile, LifecycleAction::Validate)?; + if profile.kind == TargetKind::Managed && profile.managed_runtime_profile.is_none() { + return Err(TargetError::new( + TargetErrorCode::ProfileMalformed, + "A managed target profile is missing its runtime identity.", + )); + } + Ok(()) +} + +fn migrate_profile_value(mut value: Value) -> Result<(TargetProfile, bool), TargetError> { + let object = value.as_object_mut().ok_or_else(|| { + TargetError::new( + TargetErrorCode::ProfileMalformed, + "A stored target profile is not a JSON object.", + ) + })?; + let schema = object + .get("schema_version") + .and_then(Value::as_u64) + .unwrap_or(0); + let mut changed = false; + match schema { + 0 => { + object.insert( + "schema_version".into(), + Value::from(CURRENT_PROFILE_SCHEMA_VERSION), + ); + if !object.contains_key("lifecycle_ownership") { + let ownership = match object.get("kind").and_then(Value::as_str) { + Some("managed") => "desktop", + _ => "external", + }; + object.insert("lifecycle_ownership".into(), Value::from(ownership)); + } + changed = true; + } + value if value == u64::from(CURRENT_PROFILE_SCHEMA_VERSION) => {} + other => { + return Err(TargetError::new( + TargetErrorCode::UnsupportedProfileSchema, + format!("A stored target profile uses unsupported schema version {other}."), + )); + } + } + let profile: TargetProfile = serde_json::from_value(value).map_err(|_| { + TargetError::new( + TargetErrorCode::ProfileMalformed, + "A stored target profile is malformed and could not be restored.", + ) + })?; + validate_profile_structure(&profile)?; + Ok((profile, changed)) +} + +fn decode_state( + store_schema: Option, + profiles: Option, + selected: Option, +) -> Result { + let schema = store_schema.as_ref().and_then(Value::as_u64).unwrap_or(0); + if schema > u64::from(CURRENT_STORE_SCHEMA_VERSION) { + return Err(TargetError::new( + TargetErrorCode::UnsupportedStoreSchema, + format!("Target profile storage uses unsupported schema version {schema}."), + )); + } + let mut decoded = DecodedState { + changed: schema != u64::from(CURRENT_STORE_SCHEMA_VERSION), + ..DecodedState::default() + }; + let values = match profiles { + None => Vec::new(), + Some(Value::Array(values)) => values, + Some(_) => { + return Err(TargetError::new( + TargetErrorCode::StoreCorrupt, + "Stored target profiles are malformed.", + )); + } + }; + let mut ids = BTreeSet::new(); + for value in values { + let (profile, migrated) = migrate_profile_value(value)?; + if !ids.insert(profile.id.clone()) { + return Err(TargetError::new( + TargetErrorCode::StoreCorrupt, + "Stored target profiles contain duplicate identities.", + )); + } + decoded.changed |= migrated; + decoded.profiles.push(profile); + } + decoded.selected_profile_id = match selected { + None | Some(Value::Null) => None, + Some(Value::String(value)) if !value.trim().is_empty() => Some(value), + Some(_) => { + decoded.changed = true; + decoded.issues.push(TargetError::new( + TargetErrorCode::SelectedProfileMissing, + "The selected target identity was malformed and has been cleared.", + )); + None + } + }; + if decoded + .selected_profile_id + .as_ref() + .is_some_and(|selected| !ids.contains(selected)) + { + decoded.selected_profile_id = None; + decoded.changed = true; + decoded.issues.push(TargetError::new( + TargetErrorCode::SelectedProfileMissing, + "The selected target no longer exists and has been cleared.", + )); + } + Ok(decoded) +} + +type ProfileStore = Arc>; + +fn open_store(app: &AppHandle) -> Result<(ProfileStore, Option), TargetError> { + match app.store(STORE_FILE) { + Ok(store) => Ok((store, None)), + Err(error) => { + log::warn!("Recovering malformed target profile store: {error}"); + let store = + app.store_builder(STORE_FILE) + .create_new() + .build() + .map_err(|recovery_error| { + TargetError::new( + TargetErrorCode::StoreUnavailable, + format!( + "Target profile storage could not be recovered: {recovery_error}" + ), + ) + })?; + Ok(( + store, + Some(TargetError::new( + TargetErrorCode::StoreCorrupt, + "Target profile storage was corrupt and has been reset. Choose a target again.", + )), + )) + } + } +} + +fn persist_state(store: &ProfileStore, decoded: &DecodedState) -> Result<(), TargetError> { + store.set(STORE_SCHEMA_KEY, Value::from(CURRENT_STORE_SCHEMA_VERSION)); + store.set( + PROFILES_KEY, + serde_json::to_value(&decoded.profiles).map_err(|error| { + TargetError::new( + TargetErrorCode::StoreUnavailable, + format!("Target profiles could not be serialized: {error}"), + ) + })?, + ); + match &decoded.selected_profile_id { + Some(selected) => store.set(SELECTED_PROFILE_KEY, Value::from(selected.clone())), + None => { + store.delete(SELECTED_PROFILE_KEY); + } + } + store.save().map_err(|error| { + TargetError::new( + TargetErrorCode::StoreUnavailable, + format!("Target profiles could not be saved: {error}"), + ) + }) +} + +fn load_state(app: &AppHandle) -> Result<(ProfileStore, DecodedState), TargetError> { + let (store, load_issue) = open_store(app)?; + let mut decoded = match decode_state( + store.get(STORE_SCHEMA_KEY), + store.get(PROFILES_KEY), + store.get(SELECTED_PROFILE_KEY), + ) { + Ok(decoded) => decoded, + Err(error) if error.code != TargetErrorCode::UnsupportedStoreSchema => { + let mut recovered = DecodedState { + changed: true, + ..DecodedState::default() + }; + recovered.issues.push(error); + recovered + } + Err(error) => return Err(error), + }; + if let Some(issue) = load_issue { + decoded.issues.push(issue); + decoded.changed = true; + } + if decoded.changed { + persist_state(&store, &decoded)?; + decoded.changed = false; + } + Ok((store, decoded)) +} + +fn state_snapshot(decoded: DecodedState) -> TargetState { + TargetState { + profiles: decoded.profiles, + selected_profile_id: decoded.selected_profile_id, + issues: decoded.issues, + } +} + +fn upsert_profile(decoded: &mut DecodedState, profile: TargetProfile) { + if let Some(existing) = decoded + .profiles + .iter_mut() + .find(|existing| existing.id == profile.id) + { + *existing = profile; + } else { + decoded.profiles.push(profile); + } + decoded + .profiles + .sort_by(|left, right| left.id.cmp(&right.id)); + decoded.changed = true; +} + +pub fn initialize( + app: &AppHandle, + managed_runtime: Option, + _desktop_version: &str, +) -> Result { + let (store, mut decoded) = load_state(app)?; + let selected_was_managed = decoded + .selected_profile_id + .as_ref() + .is_some_and(|selected| { + decoded + .profiles + .iter() + .any(|profile| profile.id == *selected && profile.kind == TargetKind::Managed) + }); + if let Some(managed_runtime) = managed_runtime { + let profile = reconcile_managed_profile( + decoded + .profiles + .iter() + .find(|existing| existing.kind == TargetKind::Managed), + managed_runtime, + ); + let id = profile.id.clone(); + let was_empty = decoded.profiles.is_empty(); + decoded + .profiles + .retain(|existing| existing.kind != TargetKind::Managed); + upsert_profile(&mut decoded, profile); + if selected_was_managed || (was_empty && decoded.selected_profile_id.is_none()) { + decoded.selected_profile_id = Some(id); + decoded.changed = true; + } + } else { + let previous_length = decoded.profiles.len(); + decoded + .profiles + .retain(|profile| profile.kind != TargetKind::Managed); + if decoded.profiles.len() != previous_length { + decoded.changed = true; + } + if selected_was_managed { + decoded.selected_profile_id = None; + decoded.changed = true; + } + } + if decoded.changed { + persist_state(&store, &decoded)?; + } + Ok(state_snapshot(decoded)) +} + +fn apply_validation(profile: &mut TargetProfile, validated: ValidatedTarget) { + profile.executable = validated.executable; + profile.data_root = validated.data_root; + profile.repository_root = validated.repository_root; + profile.observed_vidxp_version = validated.product_version; + profile.probe_schema_version = validated.probe_schema_version; + profile.probe_protocol_version = validated.probe_protocol_version; + profile.launch_protocol_version = validated.launch_protocol_version; + profile.runtime = Some(validated.runtime); + profile.frontend = validated.frontend; + profile.last_successful_validation_at = Some(validated.validated_at); + profile.validation_error = None; +} + +pub fn current_state(app: &AppHandle) -> Result { + let (_, decoded) = load_state(app)?; + Ok(state_snapshot(decoded)) +} + +pub fn replace_state(app: &AppHandle, state: TargetState) -> Result<(), TargetError> { + let (store, _) = load_state(app)?; + let decoded = DecodedState { + profiles: state.profiles, + selected_profile_id: state.selected_profile_id, + issues: state.issues, + changed: true, + }; + persist_state(&store, &decoded) +} + +pub fn selected_profile(app: &AppHandle) -> Result { + let state = current_state(app)?; + state.selected_profile().cloned().ok_or_else(|| { + TargetError::new( + TargetErrorCode::SelectedProfileMissing, + "Choose a VidXP target before continuing.", + ) + }) +} + +pub fn validated_selected_profile_with_cancellation( + app: &AppHandle, + desktop_version: &str, + cancellation: Option<&CancellationToken>, +) -> Result { + let profile = selected_profile(app)?; + let validated = validate_executable_with( + &profile.executable, + desktop_version, + |path, version, request_id| { + collect_command_output( + path, + &[ + "desktop-probe", + "--json", + "--desktop-version", + version, + "--request-id", + request_id, + ], + "The VidXP compatibility probe", + cancellation, + ) + }, + ); + persist_selected_validation(app, validated) +} + +pub(crate) fn persist_selected_validation( + app: &AppHandle, + validated: Result, +) -> Result { + let (store, mut decoded) = load_state(app)?; + let selected = decoded.selected_profile_id.clone().ok_or_else(|| { + TargetError::new( + TargetErrorCode::SelectedProfileMissing, + "Choose a VidXP target before continuing.", + ) + })?; + let profile = decoded + .profiles + .iter_mut() + .find(|profile| profile.id == selected) + .ok_or_else(|| { + TargetError::new( + TargetErrorCode::ProfileNotFound, + "The selected VidXP target no longer exists.", + ) + })?; + match validated { + Ok(validated) => { + apply_validation(profile, validated); + let result = profile.clone(); + decoded.changed = true; + persist_state(&store, &decoded)?; + Ok(result) + } + Err(error) => { + profile.validation_error = Some(error.clone()); + decoded.changed = true; + persist_state(&store, &decoded)?; + Err(error) + } + } +} + +pub fn adopt_validated( + app: &AppHandle, + validated: ValidatedTarget, + display_name: Option, +) -> Result { + let profile = local_profile(validated, display_name); + let (store, mut decoded) = load_state(app)?; + upsert_profile(&mut decoded, profile.clone()); + decoded.selected_profile_id = Some(profile.id.clone()); + persist_state(&store, &decoded)?; + Ok(state_snapshot(decoded)) +} + +pub fn select_profile( + app: &AppHandle, + profile_id: &str, + desktop_version: &str, +) -> Result { + let profile = current_state(app)? + .profiles + .into_iter() + .find(|profile| profile.id == profile_id) + .ok_or_else(|| { + TargetError::new( + TargetErrorCode::ProfileNotFound, + "The selected VidXP target no longer exists.", + ) + })?; + let validated = validate_executable(&profile.executable, desktop_version)?; + select_validated_profile(app, profile_id, validated) +} + +pub(crate) fn select_validated_profile( + app: &AppHandle, + profile_id: &str, + validated: ValidatedTarget, +) -> Result { + let (store, mut decoded) = load_state(app)?; + let profile = decoded + .profiles + .iter_mut() + .find(|profile| profile.id == profile_id) + .ok_or_else(|| { + TargetError::new( + TargetErrorCode::ProfileNotFound, + "The selected VidXP target no longer exists.", + ) + })?; + apply_validation(profile, validated); + decoded.selected_profile_id = Some(profile_id.to_owned()); + decoded.changed = true; + persist_state(&store, &decoded)?; + Ok(state_snapshot(decoded)) +} + +pub fn delete_profile(app: &AppHandle, profile_id: &str) -> Result { + let (store, mut decoded) = load_state(app)?; + if decoded + .profiles + .iter() + .any(|profile| profile.id == profile_id && profile.kind == TargetKind::Managed) + { + return Err(TargetError::new( + TargetErrorCode::ManagedProfileOwned, + "The active Desktop-managed target cannot be forgotten. Create or select another target instead.", + )); + } + let original_length = decoded.profiles.len(); + decoded.profiles.retain(|profile| profile.id != profile_id); + if decoded.profiles.len() == original_length { + return Err(TargetError::new( + TargetErrorCode::ProfileNotFound, + "The target profile no longer exists.", + )); + } + if decoded.selected_profile_id.as_deref() == Some(profile_id) { + decoded.selected_profile_id = None; + } + decoded.changed = true; + persist_state(&store, &decoded)?; + Ok(state_snapshot(decoded)) +} + +pub fn prepare_managed_activation( + app: &AppHandle, + managed_runtime: ManagedRuntimeProjection, + validated: ValidatedTarget, +) -> Result { + let (_, mut decoded) = load_state(app)?; + prepare_managed_state(&mut decoded, managed_runtime, Ok(validated)) +} + +fn prepare_managed_state( + decoded: &mut DecodedState, + managed_runtime: ManagedRuntimeProjection, + validated: Result, +) -> Result { + let mut profile = reconcile_managed_profile( + decoded + .profiles + .iter() + .find(|existing| existing.kind == TargetKind::Managed), + managed_runtime, + ); + apply_validation(&mut profile, validated?); + decoded + .profiles + .retain(|existing| existing.kind != TargetKind::Managed); + upsert_profile(decoded, profile.clone()); + decoded.selected_profile_id = Some(profile.id.clone()); + Ok(state_snapshot(decoded.clone())) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn profile(kind: TargetKind, ownership: LifecycleOwnership) -> TargetProfile { + TargetProfile { + id: "profile-1".into(), + display_name: "Target".into(), + schema_version: CURRENT_PROFILE_SCHEMA_VERSION, + kind: kind.clone(), + lifecycle_ownership: ownership, + executable: PathBuf::from("/vidxp"), + data_root: PathBuf::from("/data"), + repository_root: PathBuf::from("/data/repositories/default"), + observed_vidxp_version: "0.4.0-b".into(), + probe_schema_version: 1, + probe_protocol_version: 1, + launch_protocol_version: 1, + runtime: None, + frontend: FrontendCapability::default(), + last_successful_validation_at: Some(100), + validation_error: None, + managed_runtime_profile: (kind == TargetKind::Managed).then(|| "runtime-1".into()), + capabilities: Vec::new(), + surfaces: Vec::new(), + model_directory: None, + } + } + + #[test] + fn tagged_profiles_round_trip_with_explicit_ownership() { + for expected in [ + profile(TargetKind::ExistingLocal, LifecycleOwnership::External), + profile(TargetKind::Managed, LifecycleOwnership::Desktop), + ] { + let json = serde_json::to_value(&expected).expect("serialize profile"); + assert_eq!( + json.get("kind").and_then(Value::as_str), + Some(match expected.kind { + TargetKind::ExistingLocal => "existing_local", + TargetKind::Managed => "managed", + }) + ); + assert_eq!( + serde_json::from_value::(json).expect("deserialize profile"), + expected + ); + } + } + + #[test] + fn schema_zero_profile_migrates_ownership() { + let mut value = serde_json::to_value(profile( + TargetKind::ExistingLocal, + LifecycleOwnership::External, + )) + .expect("serialize"); + let object = value.as_object_mut().expect("object"); + object.remove("schema_version"); + object.remove("lifecycle_ownership"); + + let (migrated, changed) = migrate_profile_value(value).expect("migration"); + + assert!(changed); + assert_eq!(migrated.schema_version, CURRENT_PROFILE_SCHEMA_VERSION); + assert_eq!(migrated.lifecycle_ownership, LifecycleOwnership::External); + } + + #[test] + fn corrupted_store_and_duplicate_profiles_are_rejected() { + assert_eq!( + decode_state(Some(Value::from(1)), Some(Value::from("bad")), None) + .expect_err("corrupt") + .code, + TargetErrorCode::StoreCorrupt + ); + let value = serde_json::to_value(profile( + TargetKind::ExistingLocal, + LifecycleOwnership::External, + )) + .expect("profile"); + assert_eq!( + decode_state( + Some(Value::from(1)), + Some(Value::Array(vec![value.clone(), value])), + None, + ) + .expect_err("duplicate") + .code, + TargetErrorCode::StoreCorrupt + ); + } + + #[test] + fn missing_or_deleted_selected_profile_is_cleared() { + let decoded = decode_state( + Some(Value::from(1)), + Some(Value::Array(Vec::new())), + Some(Value::from("deleted")), + ) + .expect("decode"); + + assert_eq!(decoded.selected_profile_id, None); + assert_eq!( + decoded.issues[0].code, + TargetErrorCode::SelectedProfileMissing + ); + assert!(decoded.changed); + } + + #[test] + fn lifecycle_guards_block_actual_external_mutation_and_broad_stop() { + let external = profile(TargetKind::ExistingLocal, LifecycleOwnership::External); + for action in [LifecycleAction::Install, LifecycleAction::BroadProcessStop] { + assert_eq!( + authorize_lifecycle(&external, action) + .expect_err("external mutation") + .code, + TargetErrorCode::LifecycleForbidden + ); + } + authorize_lifecycle(&external, LifecycleAction::Validate).expect("validation"); + authorize_lifecycle(&external, LifecycleAction::Launch).expect("launch"); + + let managed = profile(TargetKind::Managed, LifecycleOwnership::Desktop); + authorize_lifecycle(&managed, LifecycleAction::Install).expect("managed install"); + authorize_lifecycle(&managed, LifecycleAction::BroadProcessStop).expect("managed stop"); + } + + #[test] + fn external_selection_cannot_act_on_an_installed_managed_runtime() { + let external = profile(TargetKind::ExistingLocal, LifecycleOwnership::External); + let error = authorize_managed_runtime_action(&external, "runtime-1") + .expect_err("external selection must not control the managed runtime"); + assert_eq!(error.code, TargetErrorCode::LifecycleForbidden); + + let managed = profile(TargetKind::Managed, LifecycleOwnership::Desktop); + authorize_managed_runtime_action(&managed, "runtime-1") + .expect("matching managed selection"); + let mismatch = authorize_managed_runtime_action(&managed, "runtime-2") + .expect_err("a different managed runtime must not be controlled"); + assert_eq!(mismatch.code, TargetErrorCode::ValidationRequired); + } + + #[test] + fn mismatched_kind_and_ownership_is_malformed() { + let invalid = profile(TargetKind::ExistingLocal, LifecycleOwnership::Desktop); + assert_eq!( + authorize_lifecycle(&invalid, LifecycleAction::Validate) + .expect_err("mismatch") + .code, + TargetErrorCode::ProfileMalformed + ); + } + + #[test] + fn stale_or_failed_validation_is_not_ready() { + let mut target = profile(TargetKind::ExistingLocal, LifecycleOwnership::External); + assert!(target.is_ready(100 + VALIDATION_MAX_AGE.as_secs())); + assert!(!target.is_ready(101 + VALIDATION_MAX_AGE.as_secs())); + target.validation_error = Some(TargetError::new( + TargetErrorCode::UnsupportedLaunchProtocol, + "unsupported launch protocol", + )); + assert!(!target.is_ready(100)); + } + + fn document(canonical: &Path, request_id: &str) -> ProbeDocument { + let root = std::env::current_dir().expect("current directory"); + ProbeDocument { + product: PRODUCT_ID.into(), + product_version: "0.4.0-b".into(), + schema_version: 1, + protocol_version: 1, + launch_contract: ProbeLaunchContract { + protocol_version: 2, + surface: "browser".into(), + command: "ui".into(), + }, + request_id: request_id.into(), + launcher: canonical.into(), + runtime: ProbeRuntime { + python_executable: root.join("python"), + python_version: "3.14.6".into(), + implementation: "CPython".into(), + prefix: root.join("prefix"), + base_prefix: root.join("base-prefix"), + }, + data_root: root.join("data"), + repository_root: root.join("data").join("repositories").join("default"), + model_root: root.join("data").join("models"), + capabilities: ProbeCapabilities::default(), + } + } + + #[test] + fn valid_probe_accepts_missing_optional_frontend() { + let executable = std::env::current_exe().expect("current executable"); + let canonical = fs::canonicalize(executable).expect("canonical executable"); + let validated = + validate_probe_document(&canonical, "nonce", document(&canonical, "nonce"), 100) + .expect("valid probe"); + + assert!(!validated.frontend.available); + assert!(!validated.frontend.launchable); + } + + #[test] + fn validation_pipeline_reports_missing_malformed_timeout_and_failed_probes() { + let missing = std::env::temp_dir().join("vidxp-missing-probe-executable"); + assert_eq!( + validate_executable_with(&missing, "0.4.0-b", |_, _, _| { + panic!("a missing executable must not be launched") + }) + .expect_err("missing") + .code, + TargetErrorCode::ExecutableMissing + ); + + let executable = std::env::current_exe().expect("current executable"); + assert_eq!( + validate_executable_with(&executable, "0.4.0-b", |_, _, _| { + Ok(ProbeOutput { + success: true, + stdout: b"not json".to_vec(), + stderr: Vec::new(), + }) + }) + .expect_err("malformed") + .code, + TargetErrorCode::MalformedProbe + ); + assert_eq!( + validate_executable_with(&executable, "0.4.0-b", |_, _, _| { + Err(TargetError::new(TargetErrorCode::ProbeTimeout, "timed out")) + }) + .expect_err("timeout") + .code, + TargetErrorCode::ProbeTimeout + ); + assert_eq!( + validate_executable_with(&executable, "0.4.0-b", |_, _, _| { + Ok(ProbeOutput { + success: false, + stdout: Vec::new(), + stderr: Vec::new(), + }) + }) + .expect_err("failed") + .code, + TargetErrorCode::ProbeFailed + ); + } + + #[test] + fn probe_rejects_identity_and_probe_contract_mismatches() { + let executable = std::env::current_exe().expect("current executable"); + let canonical = fs::canonicalize(executable).expect("canonical executable"); + + let mut non_vidxp = document(&canonical, "nonce"); + non_vidxp.product = "other".into(); + assert_eq!( + validate_probe_document(&canonical, "nonce", non_vidxp, 100) + .expect_err("product") + .code, + TargetErrorCode::NotVidxp + ); + + let wrong_nonce = document(&canonical, "wrong"); + assert_eq!( + validate_probe_document(&canonical, "nonce", wrong_nonce, 100) + .expect_err("nonce") + .code, + TargetErrorCode::ProbeChallengeMismatch + ); + + let mut wrong_launcher = document(&canonical, "nonce"); + wrong_launcher.launcher = fs::canonicalize(file!()).expect("source file"); + assert_eq!( + validate_probe_document(&canonical, "nonce", wrong_launcher, 100) + .expect_err("launcher") + .code, + TargetErrorCode::LauncherIdentityMismatch + ); + + let mut wrong_schema = document(&canonical, "nonce"); + wrong_schema.schema_version = 2; + assert_eq!( + validate_probe_document(&canonical, "nonce", wrong_schema, 100) + .expect_err("schema") + .code, + TargetErrorCode::UnsupportedProbeSchema + ); + + let mut wrong_protocol = document(&canonical, "nonce"); + wrong_protocol.protocol_version = 2; + assert_eq!( + validate_probe_document(&canonical, "nonce", wrong_protocol, 100) + .expect_err("protocol") + .code, + TargetErrorCode::UnsupportedProbeProtocol + ); + } + + #[test] + fn compatible_probe_accepts_a_different_reported_package_version() { + let executable = std::env::current_exe().expect("current executable"); + let canonical = fs::canonicalize(executable).expect("canonical executable"); + let mut compatible = document(&canonical, "nonce"); + compatible.product_version = "0.3.0".into(); + + let validated = validate_probe_document(&canonical, "nonce", compatible, 100) + .expect("compatible contract"); + + assert_eq!(validated.product_version, "0.3.0"); + assert_eq!(validated.launch_protocol_version, 2); + } + + #[test] + fn exact_and_canonical_symlink_launchers_preserve_selected_identity() { + let executable = std::env::current_exe().expect("current executable"); + let canonical = fs::canonicalize(&executable).expect("canonical executable"); + let exact = document(&canonical, "nonce"); + assert!(validate_probe_document(&canonical, "nonce", exact, 100).is_ok()); + + let link = std::env::temp_dir().join(format!( + "vidxp-launcher-link-{}{}", + std::process::id(), + std::env::consts::EXE_SUFFIX + )); + #[cfg(windows)] + let linked = std::os::windows::fs::symlink_file(&canonical, &link); + #[cfg(unix)] + let linked = std::os::unix::fs::symlink(&canonical, &link); + if linked.is_err() { + return; + } + let linked_document = document(&link, "nonce"); + assert!(validate_probe_document(&canonical, "nonce", linked_document, 100).is_ok()); + fs::remove_file(link).expect("remove launcher symlink"); + } + + #[cfg(windows)] + #[test] + fn extensionless_windows_console_script_identity_resolves_only_selected_shim() { + let root = + std::env::temp_dir().join(format!("vidxp-launcher-identity-{}", std::process::id())); + fs::create_dir_all(&root).expect("launcher test directory"); + let selected = root.join("vidxp.exe"); + let colliding = root.join("vidxp.com"); + let similar = root.join("vidxp-helper.exe"); + fs::write(&selected, b"shim").expect("selected shim"); + fs::write(&colliding, b"different PATHEXT sibling").expect("colliding shim"); + fs::write(&similar, b"other").expect("similar shim"); + let canonical = fs::canonicalize(&selected).expect("canonical selected shim"); + + let mut extensionless = document(&canonical, "nonce"); + extensionless.launcher = root.join("vidxp"); + assert!(validate_probe_document(&canonical, "nonce", extensionless, 100).is_ok()); + + let mut unrelated = document(&canonical, "nonce"); + unrelated.launcher = similar; + assert_eq!( + validate_probe_document(&canonical, "nonce", unrelated, 100) + .expect_err("similar sibling") + .code, + TargetErrorCode::LauncherIdentityMismatch + ); + + let mut missing = document(&canonical, "nonce"); + missing.launcher = root.join("missing"); + assert_eq!( + validate_probe_document(&canonical, "nonce", missing, 100) + .expect_err("missing launcher") + .code, + TargetErrorCode::LauncherIdentityMismatch + ); + fs::remove_dir_all(root).expect("remove launcher test directory"); + } + + #[cfg(not(windows))] + #[test] + fn non_windows_launcher_identity_does_not_resolve_executable_suffixes() { + let root = + std::env::temp_dir().join(format!("vidxp-launcher-identity-{}", std::process::id())); + fs::create_dir_all(&root).expect("launcher test directory"); + let selected = root.join("vidxp.exe"); + fs::write(&selected, b"shim").expect("selected shim"); + let canonical = fs::canonicalize(&selected).expect("canonical selected shim"); + let mut extensionless = document(&canonical, "nonce"); + extensionless.launcher = root.join("vidxp"); + + assert_eq!( + validate_probe_document(&canonical, "nonce", extensionless, 100) + .expect_err("ordinary non-Windows path") + .code, + TargetErrorCode::LauncherIdentityMismatch + ); + fs::remove_dir_all(root).expect("remove launcher test directory"); + } + + #[test] + fn probe_rejects_an_incompatible_launch_protocol() { + let executable = std::env::current_exe().expect("current executable"); + let canonical = fs::canonicalize(executable).expect("canonical executable"); + let mut incompatible = document(&canonical, "nonce"); + incompatible.launch_contract.protocol_version = 1; + + assert_eq!( + validate_probe_document(&canonical, "nonce", incompatible, 100) + .expect_err("launch protocol") + .code, + TargetErrorCode::UnsupportedLaunchProtocol + ); + } + + #[test] + fn inspection_accepts_a_compatible_contract_with_a_different_package_version() { + let executable = std::env::current_exe().expect("current executable"); + let inspected = inspect_executable_with( + &executable, + "0.4.0-b", + |canonical, _, request_id| { + let mut payload = document(canonical, request_id); + payload.product_version = "0.3.0".into(); + Ok(ProbeOutput { + success: true, + stdout: serde_json::to_vec(&payload).expect("probe json"), + stderr: Vec::new(), + }) + }, + |_| panic!("a compatible probe must not fall back to package version"), + ) + .expect("inspection"); + + assert_eq!(inspected.state, InspectionState::ReadyToUse); + assert!(inspected.adoptable); + assert_eq!(inspected.reported_version.as_deref(), Some("0.3.0")); + assert!(inspected.probe_compatible); + assert!(inspected.launch_compatible); + } + + #[test] + fn version_fallback_is_diagnostic_only_and_cannot_make_a_target_adoptable() { + let executable = std::env::current_exe().expect("current executable"); + let inspected = inspect_executable_with( + &executable, + "0.4.0-b", + |_, _, _| { + Ok(ProbeOutput { + success: false, + stdout: Vec::new(), + stderr: b"No such command: desktop-probe".to_vec(), + }) + }, + |_| { + Ok(ProbeOutput { + success: true, + stdout: b"VidXP 0.4.0b0\n".to_vec(), + stderr: Vec::new(), + }) + }, + ) + .expect("inspection"); + + assert_eq!(inspected.state, InspectionState::UpdateRequired); + assert!(!inspected.adoptable); + assert_eq!(inspected.reported_version.as_deref(), Some("0.4.0b0")); + assert!(!inspected.probe_compatible); + assert!(inspected.validated.is_none()); + } + + #[test] + fn executable_that_cannot_report_a_version_is_not_adoptable() { + let executable = std::env::current_exe().expect("current executable"); + let inspected = inspect_executable_with( + &executable, + "0.4.0-b", + |_, _, _| { + Ok(ProbeOutput { + success: false, + stdout: Vec::new(), + stderr: b"missing dependency".to_vec(), + }) + }, + |_| { + Ok(ProbeOutput { + success: false, + stdout: Vec::new(), + stderr: b"ModuleNotFoundError: SQLAlchemy".to_vec(), + }) + }, + ) + .expect("inspection"); + + assert_eq!(inspected.state, InspectionState::CannotStart); + assert!(!inspected.adoptable); + assert!( + inspected + .remediation + .contains("package-management workflow") + ); + } + + #[cfg(windows)] + #[test] + fn real_windows_console_script_passes_the_desktop_inspection_path_when_requested() { + let Some(executable) = std::env::var_os("VIDXP_DESKTOP_INTEGRATION_EXECUTABLE") else { + return; + }; + let inspected = + inspect_executable(Path::new(&executable), "0.4.0-b").expect("real Desktop inspection"); + let validated = inspected.validated.expect("validated target"); + + assert_eq!(inspected.state, InspectionState::ReadyToUse); + assert!(inspected.adoptable); + assert_eq!(validated.product_version, "0.4.0b0"); + assert_eq!(validated.probe_protocol_version, 1); + assert_eq!(validated.launch_protocol_version, 2); + assert_eq!(validated.runtime.python_version, "3.14.0"); + assert!(validated.frontend.launchable); + let expected_data_root = + std::env::var_os("VIDXP_DESKTOP_INTEGRATION_DATA_ROOT").expect("integration data root"); + assert_eq!(validated.data_root, PathBuf::from(expected_data_root)); + } + + #[test] + fn managed_projection_preserves_current_runtime_identity_without_claiming_validation() { + let projected = managed_profile(ManagedRuntimeProjection { + runtime_profile: "abc-123".into(), + executable: PathBuf::from("/runtime/bin/vidxp"), + data_root: PathBuf::from("/data"), + repository_root: PathBuf::from("/data/repositories/default"), + model_directory: PathBuf::from("/models"), + package_version: "0.4.0-b".into(), + capabilities: vec!["scene".into()], + surfaces: vec!["browser".into()], + }); + + assert_eq!(projected.id, "managed-abc-123"); + assert_eq!(projected.kind, TargetKind::Managed); + assert_eq!(projected.lifecycle_ownership, LifecycleOwnership::Desktop); + assert_eq!( + projected.managed_runtime_profile.as_deref(), + Some("abc-123") + ); + assert!(projected.last_successful_validation_at.is_none()); + assert_eq!( + projected.validation_error.expect("validation error").code, + TargetErrorCode::ValidationRequired + ); + } + + #[test] + fn managed_reconciliation_refreshes_authoritative_fields_and_preserves_name() { + let mut existing = profile(TargetKind::Managed, LifecycleOwnership::Desktop); + existing.id = "managed-runtime-2".into(); + existing.display_name = "Editing workstation".into(); + existing.executable = PathBuf::from("/stale/vidxp"); + existing.model_directory = Some(PathBuf::from("/legacy/models")); + existing.capabilities = vec!["dialogue".into()]; + + let reconciled = reconcile_managed_profile( + Some(&existing), + ManagedRuntimeProjection { + runtime_profile: "runtime-2".into(), + executable: PathBuf::from("/current/vidxp"), + data_root: PathBuf::from("/current/data"), + repository_root: PathBuf::from("/current/data/repositories/default"), + model_directory: PathBuf::from("/current/models"), + package_version: "0.5.0".into(), + capabilities: vec!["scene".into()], + surfaces: vec!["browser".into()], + }, + ); + + assert_eq!(reconciled.display_name, "Editing workstation"); + assert_eq!(reconciled.executable, PathBuf::from("/current/vidxp")); + assert_eq!(reconciled.data_root, PathBuf::from("/current/data")); + assert_eq!( + reconciled.model_directory, + Some(PathBuf::from("/current/models")) + ); + assert_eq!(reconciled.capabilities, ["scene"]); + assert_eq!(reconciled.surfaces, ["browser"]); + assert_eq!(reconciled.observed_vidxp_version, "0.5.0"); + } + + fn managed_projection_for_test() -> ManagedRuntimeProjection { + ManagedRuntimeProjection { + runtime_profile: "runtime-new".into(), + executable: PathBuf::from("/runtime/bin/vidxp"), + data_root: PathBuf::from("/data"), + repository_root: PathBuf::from("/data/repositories/default"), + model_directory: PathBuf::from("/models"), + package_version: "0.5.0".into(), + capabilities: vec!["scene".into()], + surfaces: vec!["browser".into()], + } + } + + fn validated_managed_target() -> ValidatedTarget { + ValidatedTarget { + executable: PathBuf::from("/runtime/bin/vidxp"), + product_version: "0.5.0".into(), + probe_schema_version: 1, + probe_protocol_version: 1, + launch_protocol_version: 2, + runtime: RuntimeIdentity { + python_executable: PathBuf::from("/runtime/bin/python"), + python_version: "3.14.6".into(), + implementation: "CPython".into(), + prefix: PathBuf::from("/runtime"), + base_prefix: PathBuf::from("/python"), + }, + data_root: PathBuf::from("/data"), + repository_root: PathBuf::from("/data/repositories/default"), + model_root: PathBuf::from("/models"), + frontend: FrontendCapability { + available: true, + launchable: true, + optional: true, + code: "frontend_available".into(), + message: "Available".into(), + remediation: String::new(), + }, + validated_at: 200, + } + } + + #[test] + fn failed_managed_candidate_probe_cannot_replace_target_state() { + let old = profile(TargetKind::Managed, LifecycleOwnership::Desktop); + let mut decoded = DecodedState { + profiles: vec![old.clone()], + selected_profile_id: Some(old.id.clone()), + ..DecodedState::default() + }; + + let error = prepare_managed_state( + &mut decoded, + managed_projection_for_test(), + Err(TargetError::new( + TargetErrorCode::UnsupportedLaunchProtocol, + "candidate launch contract failed", + )), + ) + .expect_err("candidate must not activate"); + + assert_eq!(error.code, TargetErrorCode::UnsupportedLaunchProtocol); + assert_eq!(decoded.profiles.as_slice(), std::slice::from_ref(&old)); + assert_eq!( + decoded.selected_profile_id.as_deref(), + Some(old.id.as_str()) + ); + } + + #[test] + fn managed_activation_replaces_all_stale_managed_profiles() { + let external = profile(TargetKind::ExistingLocal, LifecycleOwnership::External); + let mut old = profile(TargetKind::Managed, LifecycleOwnership::Desktop); + old.id = "managed-old".into(); + old.display_name = "Editing workstation".into(); + let mut stale = old.clone(); + stale.id = "managed-stale".into(); + let mut decoded = DecodedState { + profiles: vec![external.clone(), old, stale], + selected_profile_id: Some("managed-old".into()), + ..DecodedState::default() + }; + + let state = prepare_managed_state( + &mut decoded, + managed_projection_for_test(), + Ok(validated_managed_target()), + ) + .expect("managed candidate"); + + let managed: Vec<_> = state + .profiles + .iter() + .filter(|profile| profile.kind == TargetKind::Managed) + .collect(); + assert_eq!(managed.len(), 1); + assert_eq!(managed[0].id, "managed-runtime-new"); + assert_eq!(managed[0].display_name, "Editing workstation"); + assert_eq!( + state.selected_profile_id.as_deref(), + Some("managed-runtime-new") + ); + assert!(state.profiles.contains(&external)); + } +} diff --git a/desktop/src-tauri/tauri.conf.json b/desktop/src-tauri/tauri.conf.json index c270063..7ec9449 100644 --- a/desktop/src-tauri/tauri.conf.json +++ b/desktop/src-tauri/tauri.conf.json @@ -1,15 +1,19 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "VidXP", - "version": "0.3.0", + "version": "0.4.0-b.1", "identifier": "dev.grayhat.vidxp", "build": { - "frontendDist": "../web" + "beforeDevCommand": "npm run dev", + "beforeBuildCommand": "npm run build", + "devUrl": "http://localhost:5173", + "frontendDist": "../dist" }, "app": { - "withGlobalTauri": true, + "withGlobalTauri": false, "security": { - "csp": "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src ipc: http://ipc.localhost" + "csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src ipc: http://ipc.localhost", + "devCsp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src ipc: http://ipc.localhost ws:" }, "windows": [ { @@ -20,13 +24,20 @@ "minWidth": 680, "minHeight": 600, "visible": false, - "resizable": true + "resizable": true, + "decorations": true, + "shadow": true, + "transparent": false } ] }, "bundle": { "active": true, "targets": "all", + "resources": [ + "../THIRD_PARTY_NOTICES.txt", + "../../LICENSE" + ], "externalBin": [ "binaries/uv" ], diff --git a/desktop/src-tauri/tauri.windows.conf.json b/desktop/src-tauri/tauri.windows.conf.json new file mode 100644 index 0000000..7693ba8 --- /dev/null +++ b/desktop/src-tauri/tauri.windows.conf.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://schema.tauri.app/config/2", + "app": { + "windows": [ + { + "label": "main", + "title": "VidXP", + "width": 920, + "height": 760, + "minWidth": 680, + "minHeight": 600, + "visible": false, + "resizable": true, + "decorations": false, + "shadow": false, + "transparent": false + } + ] + } +} diff --git a/desktop/src/App.test.tsx b/desktop/src/App.test.tsx new file mode 100644 index 0000000..fd07763 --- /dev/null +++ b/desktop/src/App.test.tsx @@ -0,0 +1,381 @@ +import { MantineProvider } from '@mantine/core'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { StrictMode } from 'react'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const mocks = vi.hoisted(() => ({ + targetSetupState: vi.fn(), recheckTargetState: vi.fn(), discoverLocalTargets: vi.fn(), + chooseLocalExecutable: vi.fn(), inspectLocalTarget: vi.fn(), activateLocalTarget: vi.fn(), + selectTargetProfile: vi.fn(), deleteTargetProfile: vi.fn(), confirmForgetTarget: vi.fn(), beginManagedSetup: vi.fn(), + cancelManagedSetup: vi.fn(), installMediaRuntime: vi.fn(), installRuntime: vi.fn(), + prepareManagedModels: vi.fn(), + runtimeManifest: vi.fn(), runtimeStatus: vi.fn(), launchUi: vi.fn(), + chooseModelDirectory: vi.fn(), modelDirectoryInventory: vi.fn(), +})); + +const windowMocks = vi.hoisted(() => ({ + close: vi.fn(), isMaximized: vi.fn(), minimize: vi.fn(), onResized: vi.fn(), toggleMaximize: vi.fn(), +})); + +vi.mock('@tauri-apps/api/window', () => ({ getCurrentWindow: () => windowMocks })); +vi.mock('./tauri', () => ({ + ...mocks, + selectedProfile: (state: any) => state.profiles.find((profile: any) => profile.id === state.selected_profile_id) ?? null, + errorMessage: (error: unknown, fallback: string) => typeof error === 'string' ? error : fallback, + displayPath: (path: string) => path, +})); + +import { App } from './App'; + +const frontend = { available: true, launchable: true, optional: true, code: 'frontend_available', message: 'Available.', remediation: '' }; +const localProfile = { + id: 'local-1', display_name: 'Studio VidXP', schema_version: 1, kind: 'existing_local', + lifecycle_ownership: 'external', executable: 'C:\\Tools\\VidXP\\vidxp.exe', + display_executable: 'C:\\Tools\\VidXP\\vidxp.exe', data_root: 'C:\\Data', display_data_root: 'C:\\Data', + repository_root: 'C:\\Data\\repositories\\default', display_repository_root: 'C:\\Data\\repositories\\default', + observed_vidxp_version: '0.4.0', probe_schema_version: 1, probe_protocol_version: 1, + launch_protocol_version: 1, runtime: null, frontend, last_successful_validation_at: 1, + last_validated_at: '2026-08-01T10:00:00Z', validation_error: null, capabilities: [], surfaces: ['browser'], +}; +const managedProfile = { + ...localProfile, id: 'managed-a', display_name: 'Managed VidXP', kind: 'managed', + lifecycle_ownership: 'desktop', managed_runtime_profile: 'runtime-a', capabilities: ['scene'], surfaces: [], + frontend: { ...frontend, available: false, launchable: false, code: 'frontend_unavailable', message: 'Browser interface is not installed.', remediation: 'Return to managed setup.' }, +}; +const emptyState = { profiles: [], selected_profile_id: null, issues: [] }; +const localState = { profiles: [localProfile], selected_profile_id: localProfile.id, issues: [] }; + +function deferred() { + let resolve!: (value: T) => void; + let reject!: (reason?: unknown) => void; + const promise = new Promise((done, fail) => { resolve = done; reject = fail; }); + return { promise, resolve, reject }; +} + +function renderApp() { + return render(); +} + +async function enterLocal(user: ReturnType) { + await screen.findByRole('heading', { name: 'Where should VidXP run?' }); + await user.click(screen.getByRole('radio', { name: /Use an existing installation/i })); + await user.click(screen.getByRole('button', { name: 'Continue' })); +} + +async function enterManaged(user: ReturnType) { + await screen.findByRole('heading', { name: 'Where should VidXP run?' }); + await user.click(screen.getByRole('radio', { name: /Set up VidXP for me/i })); + await user.click(screen.getByRole('button', { name: 'Continue' })); + await user.click(screen.getByRole('button', { name: 'Continue to setup' })); + await screen.findByRole('heading', { name: 'Set up local processing' }); +} + +describe('desktop target lifecycle', () => { + beforeEach(() => { + vi.resetAllMocks(); + windowMocks.isMaximized.mockResolvedValue(false); + windowMocks.onResized.mockResolvedValue(vi.fn()); + mocks.targetSetupState.mockResolvedValue(emptyState); + mocks.recheckTargetState.mockResolvedValue(emptyState); + mocks.discoverLocalTargets.mockResolvedValue([{ executable: 'C:\\Tools\\VidXP\\vidxp.exe', display_path: 'C:\\Tools\\VidXP\\vidxp.exe', source: 'PATH' }]); + mocks.inspectLocalTarget.mockResolvedValue({ + state: 'ready_to_use', adoptable: true, executable: 'C:\\Tools\\VidXP\\vidxp.exe', reported_version: '0.4.0', + probe_compatible: true, launch_compatible: true, message: 'Compatible contracts.', remediation: '', technical_details: null, + validation: { canonical_executable: 'C:\\Tools\\VidXP\\vidxp.exe', protocol_version: 1, launch_protocol_version: 1, python_version: '3.14', display_data_root: 'C:\\Data', can_launch_frontend: true, frontend }, + }); + mocks.beginManagedSetup.mockResolvedValue({ id: 'draft-1', previous_profile_id: null }); + mocks.cancelManagedSetup.mockResolvedValue(emptyState); + mocks.confirmForgetTarget.mockResolvedValue(true); + mocks.runtimeManifest.mockResolvedValue({ package_version: '0.4.0', capabilities: { scene: { extra: 'scene', label: 'Visual scene search' } }, surfaces: { browser: { extra: 'frontend', label: 'Browser interface', description: 'Browser UI', default: true } } }); + mocks.runtimeStatus.mockResolvedValue({ state: 'never_configured', ready: false, runtime_profile: null, package_version: '0.4.0', capabilities: [], surfaces: [], model_directory: 'C:\\Models', detail: 'No managed runtime yet.' }); + mocks.modelDirectoryInventory.mockResolvedValue({ directory: 'C:\\Models', exists: false, readable: true, total_bytes: 0, file_count: 0, recognized_models: [], empty: true, verification_required: false, truncated: false, detail: 'Empty.' }); + mocks.installMediaRuntime.mockResolvedValue({ ready: true }); + mocks.installRuntime.mockResolvedValue({ + install: { package_version: '0.4.0', capabilities: ['scene'], surfaces: ['browser'], model_directory: 'C:\\Models', prepared: true }, + setup: { profiles: [managedProfile], selected_profile_id: managedProfile.id, issues: [] }, + }); + mocks.prepareManagedModels.mockResolvedValue({ profiles: [managedProfile], selected_profile_id: managedProfile.id, issues: [] }); + mocks.launchUi.mockResolvedValue(undefined); + }); + + it('shows the target-first choice without a remote placeholder', async () => { + renderApp(); + expect(await screen.findByRole('radio', { name: /Use an existing installation/i })).toBeVisible(); + expect(screen.getByRole('radio', { name: /Set up VidXP for me/i })).toBeVisible(); + expect(screen.queryByText(/remote server/i)).not.toBeInTheDocument(); + }); + + it('shows the restored control panel immediately while one startup recheck is pending', async () => { + let resolve!: (value: typeof localState) => void; + mocks.targetSetupState.mockResolvedValue(localState); + mocks.recheckTargetState.mockReturnValue(new Promise((done) => { resolve = done; })); + renderApp(); + expect(await screen.findByRole('heading', { name: 'Studio VidXP' })).toBeVisible(); + expect(screen.getByRole('button', { name: 'Recheck target' })).toHaveAttribute('data-loading'); + expect(mocks.recheckTargetState).toHaveBeenCalledTimes(1); + resolve(localState); + await waitFor(() => expect(screen.getByRole('button', { name: 'Recheck target' })).not.toHaveAttribute('data-loading')); + }); + + it('opens the browser once and settles its loading state', async () => { + mocks.targetSetupState.mockResolvedValue(localState); + mocks.recheckTargetState.mockResolvedValue(localState); + const user = userEvent.setup(); renderApp(); + const open = await screen.findByRole('button', { name: 'Open VidXP' }); + await user.click(open); + expect(mocks.launchUi).toHaveBeenCalledTimes(1); + await waitFor(() => expect(open).not.toHaveAttribute('data-loading')); + }); + + it('uses the parent exclusive operation while browser startup is pending', async () => { + const browserManaged = { + ...managedProfile, + frontend, + surfaces: ['browser'], + }; + const setup = { profiles: [browserManaged], selected_profile_id: browserManaged.id, issues: [] }; + const opening = deferred(); + mocks.targetSetupState.mockResolvedValue(setup); + mocks.recheckTargetState.mockResolvedValue(setup); + mocks.launchUi.mockReturnValue(opening.promise); + const user = userEvent.setup(); renderApp(); + const open = await screen.findByRole('button', { name: 'Open VidXP' }); + await user.click(open); + expect(open).toHaveAttribute('data-loading'); + expect(screen.getByRole('button', { name: 'Manage targets' })).toBeDisabled(); + expect(screen.getByRole('button', { name: 'Recheck target' })).toBeDisabled(); + expect(screen.getByRole('button', { name: 'Manage setup' })).toBeDisabled(); + opening.resolve(); + await waitFor(() => expect(open).not.toHaveAttribute('data-loading')); + }); + + it('adopts the inspected candidate without an installation action', async () => { + mocks.activateLocalTarget.mockResolvedValue(localState); + const user = userEvent.setup(); renderApp(); await enterLocal(user); + await user.click(await screen.findByRole('radio', { name: /VidXP executable/i })); + await user.click(await screen.findByRole('button', { name: 'Use this installation' })); + expect(mocks.inspectLocalTarget).toHaveBeenCalledTimes(1); + expect(mocks.activateLocalTarget).toHaveBeenCalledTimes(1); + expect(mocks.installRuntime).not.toHaveBeenCalled(); + }); + + it('keeps fresh discovery fields authoritative while retaining inspection UI', async () => { + const user = userEvent.setup(); renderApp(); await enterLocal(user); + await user.click(await screen.findByRole('radio', { name: /VidXP executable/i })); + await screen.findByText('Compatible contracts.'); + mocks.discoverLocalTargets.mockResolvedValue([{ executable: 'C:\\Tools\\VidXP\\vidxp.exe', display_path: 'C:\\New\\display.exe', source: 'Fresh scan' }]); + await user.click(screen.getByRole('button', { name: 'Scan again' })); + expect(await screen.findByText('C:\\New\\display.exe')).toBeVisible(); + expect(screen.getByText('Compatible contracts.')).toBeVisible(); + expect(screen.getByText('Discovered via Fresh scan')).toBeVisible(); + }); + + it('cancels managed setup back to the still-selected target', async () => { + mocks.targetSetupState.mockResolvedValue(localState); + mocks.recheckTargetState.mockResolvedValue(localState); + mocks.beginManagedSetup.mockResolvedValue({ id: 'draft-1', previous_profile_id: localProfile.id }); + mocks.cancelManagedSetup.mockResolvedValue(localState); + const user = userEvent.setup(); renderApp(); + await user.click(await screen.findByRole('button', { name: 'Manage targets' })); + await user.click(screen.getByRole('radio', { name: /Set up VidXP for me/i })); + await user.click(screen.getByRole('button', { name: 'Continue' })); + await user.click(screen.getByRole('button', { name: 'Continue to setup' })); + await user.click(await screen.findByRole('button', { name: 'Back' })); + expect(mocks.cancelManagedSetup).toHaveBeenCalledWith('draft-1'); + expect(await screen.findByRole('heading', { name: 'Studio VidXP' })).toBeVisible(); + }); + + it('supports selecting and forgetting saved profiles', async () => { + const saved = { ...localProfile, id: 'local-2', display_name: 'Other VidXP' }; + const state = { profiles: [localProfile, saved], selected_profile_id: localProfile.id, issues: [] }; + mocks.targetSetupState.mockResolvedValue(state); mocks.recheckTargetState.mockResolvedValue(state); + mocks.selectTargetProfile.mockResolvedValue({ ...state, selected_profile_id: saved.id }); + mocks.deleteTargetProfile.mockResolvedValue({ profiles: [saved], selected_profile_id: saved.id, issues: [] }); + const user = userEvent.setup(); renderApp(); + await user.click(await screen.findByRole('button', { name: 'Manage targets' })); + await user.click(screen.getAllByRole('button', { name: 'Select' }).find((button) => !button.hasAttribute('disabled'))!); + expect(mocks.selectTargetProfile).toHaveBeenCalledWith(saved.id); + await user.click(screen.getByRole('button', { name: 'Manage targets' })); + await user.click(screen.getAllByRole('button', { name: 'Forget' })[0]); + expect(mocks.deleteTargetProfile).toHaveBeenCalled(); + }); + + it('offers recheck recovery for an invalid restored target', async () => { + const invalid = { ...localProfile, validation_error: { code: 'probe_timeout', message: 'Timed out.' } }; + const invalidState = { profiles: [invalid], selected_profile_id: invalid.id, issues: [] }; + mocks.targetSetupState.mockResolvedValue(invalidState); mocks.recheckTargetState.mockResolvedValue(invalidState); + const user = userEvent.setup(); renderApp(); + expect(await screen.findByText('Timed out.')).toBeVisible(); + await user.click(screen.getByRole('button', { name: 'Recheck target' })); + expect(mocks.recheckTargetState).toHaveBeenCalledTimes(2); + }); + + it('directs a managed target without browser surface back to managed setup', async () => { + const setup = { profiles: [managedProfile], selected_profile_id: managedProfile.id, issues: [] }; + mocks.targetSetupState.mockResolvedValue(setup); mocks.recheckTargetState.mockResolvedValue(setup); + renderApp(); + expect(await screen.findByText('Unavailable · return to managed setup to enable the browser surface')).toBeVisible(); + expect(screen.getByRole('button', { name: 'Manage setup' })).toBeEnabled(); + }); + + it('keeps ready managed settings read-only until a draft is dirty, then offers Apply and Reset', async () => { + mocks.runtimeStatus.mockResolvedValue({ state: 'ready', ready: true, runtime_profile: 'runtime-a', package_version: '0.4.0', capabilities: ['scene'], surfaces: [], model_directory: 'C:\\Models', detail: 'Ready.' }); + const user = userEvent.setup(); renderApp(); await enterManaged(user); + const apply = await screen.findByRole('button', { name: 'Apply update' }); + expect(apply).toBeDisabled(); + await user.click(screen.getByRole('checkbox', { name: /Browser interface/i })); + expect(apply).toBeEnabled(); + expect(screen.getByText(/installed runtime remains active while Desktop creates/i)).toBeVisible(); + await user.click(screen.getByRole('button', { name: 'Reset changes' })); + expect(apply).toBeDisabled(); + await waitFor(() => expect(mocks.modelDirectoryInventory).toHaveBeenCalledTimes(2)); + }); + + it('preserves a broken managed runtime draft instead of selecting every option', async () => { + mocks.runtimeManifest.mockResolvedValue({ + package_version: '0.4.0', + capabilities: { + actor: { extra: 'actor', label: 'Actor recognition' }, + scene: { extra: 'scene', label: 'Visual scene search' }, + }, + surfaces: { browser: { extra: 'frontend', label: 'Browser interface', description: 'Browser UI', default: true } }, + }); + mocks.runtimeStatus.mockResolvedValue({ + state: 'broken', ready: false, runtime_profile: 'runtime-a', package_version: '0.4.0', + capabilities: ['scene'], surfaces: [], model_directory: 'D:\\CustomModels', detail: 'FFmpeg was not found.', + }); + const user = userEvent.setup(); renderApp(); await enterManaged(user); + expect(screen.getByRole('checkbox', { name: /Visual scene search/i })).toBeChecked(); + expect(screen.getByRole('checkbox', { name: /Actor recognition/i })).not.toBeChecked(); + expect(screen.getByRole('checkbox', { name: /Browser interface/i })).not.toBeChecked(); + expect(screen.getByText('D:\\CustomModels')).toBeVisible(); + expect(screen.getByRole('button', { name: 'Repair VidXP' })).toBeEnabled(); + }); + + it('uses manifest defaults and submits a replacement for a corrupt runtime pointer', async () => { + mocks.runtimeManifest.mockResolvedValue({ + package_version: '0.4.0', + capabilities: { + actor: { extra: 'actor', label: 'Actor recognition' }, + scene: { extra: 'scene', label: 'Visual scene search' }, + }, + surfaces: { browser: { extra: 'frontend', label: 'Browser interface', description: 'Browser UI', default: true } }, + }); + mocks.runtimeStatus.mockResolvedValue({ + state: 'broken', ready: false, runtime_profile: null, package_version: '0.4.0', + capabilities: [], surfaces: [], model_directory: 'C:\\Models', detail: 'The active runtime pointer is invalid.', + }); + const user = userEvent.setup(); renderApp(); await enterManaged(user); + expect(screen.getByRole('checkbox', { name: /Actor recognition/i })).toBeChecked(); + expect(screen.getByRole('checkbox', { name: /Visual scene search/i })).toBeChecked(); + expect(screen.getByRole('checkbox', { name: /Browser interface/i })).toBeChecked(); + expect(screen.getByText(/cannot recover settings from the unreadable pointer/i)).toBeVisible(); + await user.click(screen.getByRole('button', { name: 'Configure replacement' })); + await waitFor(() => expect(mocks.installRuntime).toHaveBeenCalledWith(expect.objectContaining({ + capabilities: expect.arrayContaining(['actor', 'scene']), + surfaces: ['browser'], + draft_id: 'draft-1', + }))); + expect(screen.queryByText('Select at least one capability.')).not.toBeInTheDocument(); + }); + + it('passes the scoped draft through first-time installation and does not auto-open the browser', async () => { + const user = userEvent.setup(); renderApp(); await enterManaged(user); + await user.click(await screen.findByRole('button', { name: 'Configure VidXP' })); + await waitFor(() => expect(mocks.installRuntime).toHaveBeenCalledWith(expect.objectContaining({ draft_id: 'draft-1' }))); + expect(mocks.installMediaRuntime).toHaveBeenCalledWith('draft-1'); + expect(mocks.launchUi).not.toHaveBeenCalled(); + }); + + it('coalesces duplicate managed Continue actions', async () => { + const pending = deferred<{ id: string; previous_profile_id: null }>(); + mocks.beginManagedSetup.mockReturnValue(pending.promise); + const user = userEvent.setup(); renderApp(); + await screen.findByRole('heading', { name: 'Where should VidXP run?' }); + await user.click(screen.getByRole('radio', { name: /Set up VidXP for me/i })); + await user.click(screen.getByRole('button', { name: 'Continue' })); + const continueButton = screen.getByRole('button', { name: 'Continue to setup' }); + await user.dblClick(continueButton); + expect(mocks.beginManagedSetup).toHaveBeenCalledTimes(1); + pending.resolve({ id: 'draft-1', previous_profile_id: null }); + expect(await screen.findByRole('heading', { name: 'Set up local processing' })).toBeVisible(); + }); + + it('freezes managed controls and coalesces Apply while a replacement is running', async () => { + mocks.runtimeStatus.mockResolvedValue({ state: 'ready', ready: true, runtime_profile: 'runtime-a', package_version: '0.4.0', capabilities: ['scene'], surfaces: [], model_directory: 'C:\\Models', detail: 'Ready.' }); + const media = deferred<{ ready: boolean }>(); + mocks.installMediaRuntime.mockReturnValue(media.promise); + const user = userEvent.setup(); renderApp(); await enterManaged(user); + const browser = screen.getByRole('checkbox', { name: /Browser interface/i }); + await user.click(browser); + const apply = screen.getByRole('button', { name: 'Apply update' }); + await user.dblClick(apply); + expect(mocks.installMediaRuntime).toHaveBeenCalledTimes(1); + expect(screen.getByRole('button', { name: 'Back' })).toBeDisabled(); + expect(browser).toBeDisabled(); + expect(screen.getByRole('button', { name: 'Choose folder…' })).toBeDisabled(); + expect(screen.getByRole('button', { name: 'Reset changes' })).toBeDisabled(); + expect(screen.getByRole('button', { name: 'Prepare / verify models' })).toBeDisabled(); + expect(screen.getByRole('button', { name: 'Open VidXP' })).toBeDisabled(); + media.resolve({ ready: true }); + expect(await screen.findByRole('heading', { name: 'Managed VidXP' })).toBeVisible(); + }); + + it('prepares models for an unchanged ready runtime without making the draft dirty', async () => { + const setup = { profiles: [managedProfile], selected_profile_id: managedProfile.id, issues: [] }; + mocks.targetSetupState.mockResolvedValue(setup); + mocks.recheckTargetState.mockResolvedValue(setup); + mocks.runtimeStatus.mockResolvedValue({ state: 'ready', ready: true, runtime_profile: 'runtime-a', package_version: '0.4.0', capabilities: ['scene'], surfaces: [], model_directory: 'C:\\Models', detail: 'Ready.' }); + const user = userEvent.setup(); renderApp(); + await user.click(await screen.findByRole('button', { name: 'Manage setup' })); + await user.click(screen.getByRole('button', { name: 'Continue to setup' })); + await screen.findByRole('heading', { name: 'Set up local processing' }); + expect(screen.getByRole('button', { name: 'Apply update' })).toBeDisabled(); + await user.click(screen.getByRole('button', { name: 'Prepare / verify models' })); + expect(mocks.prepareManagedModels).toHaveBeenCalledWith('draft-1'); + }); + + it('disables managed runtime actions while an external target is selected', async () => { + const setup = { + profiles: [localProfile, managedProfile], + selected_profile_id: localProfile.id, + issues: [], + }; + mocks.targetSetupState.mockResolvedValue(setup); + mocks.recheckTargetState.mockResolvedValue(setup); + mocks.runtimeStatus.mockResolvedValue({ state: 'ready', ready: true, runtime_profile: 'runtime-a', package_version: '0.4.0', capabilities: ['scene'], surfaces: ['browser'], model_directory: 'C:\\Models', detail: 'Ready.' }); + const user = userEvent.setup(); renderApp(); + await user.click(await screen.findByRole('button', { name: 'Manage targets' })); + await enterManaged(user); + expect(screen.getByText(/another target is currently selected/i)).toBeVisible(); + expect(screen.getByRole('button', { name: 'Prepare / verify models' })).toBeDisabled(); + expect(screen.getByRole('button', { name: 'Open VidXP' })).toBeDisabled(); + expect(mocks.prepareManagedModels).not.toHaveBeenCalled(); + expect(mocks.launchUi).not.toHaveBeenCalled(); + }); + + it('uses the committed install state without a fallible status refresh', async () => { + const user = userEvent.setup(); renderApp(); await enterManaged(user); + await user.click(screen.getByRole('button', { name: 'Configure VidXP' })); + expect(await screen.findByRole('heading', { name: 'Managed VidXP' })).toBeVisible(); + expect(mocks.runtimeStatus).toHaveBeenCalledTimes(1); + expect(mocks.targetSetupState).toHaveBeenCalledTimes(1); + }); + + it('coalesces duplicate saved-profile Select actions', async () => { + const saved = { ...localProfile, id: 'local-2', display_name: 'Other VidXP' }; + const state = { profiles: [localProfile, saved], selected_profile_id: localProfile.id, issues: [] }; + const selection = deferred(); + mocks.targetSetupState.mockResolvedValue(state); + mocks.recheckTargetState.mockResolvedValue(state); + mocks.selectTargetProfile.mockReturnValue(selection.promise); + const user = userEvent.setup(); renderApp(); + await user.click(await screen.findByRole('button', { name: 'Manage targets' })); + const select = screen.getAllByRole('button', { name: 'Select' }).find((button) => !button.hasAttribute('disabled'))!; + await user.dblClick(select); + expect(mocks.selectTargetProfile).toHaveBeenCalledTimes(1); + selection.resolve({ ...state, selected_profile_id: saved.id }); + expect(await screen.findByRole('heading', { name: 'Other VidXP' })).toBeVisible(); + }); +}); diff --git a/desktop/src/App.tsx b/desktop/src/App.tsx new file mode 100644 index 0000000..c06d714 --- /dev/null +++ b/desktop/src/App.tsx @@ -0,0 +1,237 @@ +import { Alert, Badge, Button, Group, Loader, Stack, Text, ThemeIcon, Title } from '@mantine/core'; +import { IconAlertCircle, IconArrowLeft, IconDownload, IconTrash } from '@tabler/icons-react'; +import { useCallback, useEffect, useReducer, useRef } from 'react'; + +import { LocalSetup } from './components/LocalSetup'; +import { ManagedSetup } from './components/ManagedSetup'; +import { TargetChoice } from './components/TargetChoice'; +import { TargetSummary } from './components/TargetSummary'; +import { DesktopViewport } from './components/TitleBar'; +import { + beginManagedSetup, + cancelManagedSetup, + confirmForgetTarget, + deleteTargetProfile, + errorMessage, + launchUi, + recheckTargetState, + selectTargetProfile, + selectedProfile, + targetSetupState, + type ManagedSetupDraft, + type TargetKind, + type TargetSetupState, +} from './tauri'; +import { useExclusiveOperation } from './useAsyncAction'; + +type Stage = 'loading' | 'choice' | 'local' | 'managed-confirm' | 'managed' | 'summary'; +type AppOperation = 'startup-check' | 'recheck' | 'begin-managed' | 'cancel-managed' | 'select-profile' | 'forget-profile' | 'open-browser'; + +interface LifecycleState { + stage: Stage; + choice: TargetKind | null; + setup: TargetSetupState | null; + draft: ManagedSetupDraft | null; + failure: string | null; + operation: AppOperation | null; + operationProfile: string | null; +} + +type Action = + | { type: 'navigate'; stage: Stage; choice?: TargetKind | null } + | { type: 'choice'; choice: TargetKind | null } + | { type: 'loaded'; setup: TargetSetupState } + | { type: 'loadFailed'; failure: string } + | { type: 'operationStarted'; operation: AppOperation; profileId?: string } + | { type: 'operationFailed'; failure: string } + | { type: 'operationSettled'; setup?: TargetSetupState; stage?: Stage; draft?: ManagedSetupDraft | null }; + +const initialState: LifecycleState = { + stage: 'loading', choice: null, setup: null, draft: null, failure: null, + operation: null, operationProfile: null, +}; + +function reducer(state: LifecycleState, action: Action): LifecycleState { + switch (action.type) { + case 'navigate': + return { ...state, stage: action.stage, choice: action.choice === undefined ? state.choice : action.choice }; + case 'choice': + return { ...state, choice: action.choice }; + case 'loaded': + return { ...state, setup: action.setup, stage: selectedProfile(action.setup) ? 'summary' : 'choice', failure: null }; + case 'loadFailed': + return { ...state, stage: 'choice', failure: action.failure }; + case 'operationStarted': + return { ...state, operation: action.operation, operationProfile: action.profileId ?? null, failure: null }; + case 'operationFailed': + return { ...state, operation: null, operationProfile: null, failure: action.failure }; + case 'operationSettled': + return { + ...state, + setup: action.setup ?? state.setup, + stage: action.stage ?? state.stage, + draft: action.draft === undefined ? state.draft : action.draft, + operation: null, + operationProfile: null, + failure: null, + }; + } +} + +export function App() { + const [state, dispatch] = useReducer(reducer, initialState); + const operations = useExclusiveOperation(); + const startupLoad = useRef | null>(null); + + const startOperation = useCallback((operation: AppOperation, profileId?: string): number | null => { + const current = operations.begin(operation); + if (current === null) return null; + dispatch({ type: 'operationStarted', operation, profileId }); + return current; + }, [operations]); + + const settleOperation = useCallback((current: number, action: Action) => { + if (!operations.settle(current)) return; + dispatch(action); + }, [operations]); + + const recheck = useCallback(async (operation: 'startup-check' | 'recheck' = 'recheck') => { + const current = startOperation(operation); + if (current === null) return; + try { + const setup = await recheckTargetState(); + settleOperation(current, { type: 'operationSettled', setup }); + } catch (error) { + settleOperation(current, { + type: 'operationFailed', + failure: errorMessage(error, 'The active target could not be checked.'), + }); + } + }, [settleOperation, startOperation]); + + useEffect(() => { + let mounted = true; + const request = startupLoad.current ?? targetSetupState(); + startupLoad.current = request; + void request + .then((setup) => { + if (!mounted) return; + dispatch({ type: 'loaded', setup }); + if (selectedProfile(setup)) void recheck('startup-check'); + }) + .catch((error: unknown) => { + if (!mounted) return; + dispatch({ + type: 'loadFailed', + failure: errorMessage(error, 'VidXP Desktop could not load its target profiles.'), + }); + }); + return () => { + mounted = false; + }; + }, [recheck]); + + async function beginManaged() { + const current = startOperation('begin-managed'); + if (current === null) return; + try { + const draft = await beginManagedSetup(); + settleOperation(current, { type: 'operationSettled', draft, stage: 'managed' }); + } catch (error) { + settleOperation(current, { + type: 'operationFailed', + failure: errorMessage(error, 'Managed setup could not be started.'), + }); + } + } + + async function cancelManaged() { + if (!state.draft) return; + const current = startOperation('cancel-managed'); + if (current === null) return; + try { + const setup = await cancelManagedSetup(state.draft.id); + settleOperation(current, { + type: 'operationSettled', setup, draft: null, + stage: selectedProfile(setup) ? 'summary' : 'choice', + }); + } catch (error) { + settleOperation(current, { + type: 'operationFailed', + failure: errorMessage(error, 'Managed setup could not be cancelled.'), + }); + } + } + + async function selectSaved(id: string) { + const current = startOperation('select-profile', id); + if (current === null) return; + try { + const setup = await selectTargetProfile(id); + settleOperation(current, { type: 'operationSettled', setup, stage: 'summary' }); + } catch (error) { + settleOperation(current, { + type: 'operationFailed', + failure: errorMessage(error, 'The saved target could not be selected.'), + }); + } + } + + async function forgetSaved(id: string, name: string) { + if (!await confirmForgetTarget(name)) return; + const current = startOperation('forget-profile', id); + if (current === null) return; + try { + const setup = await deleteTargetProfile(id); + settleOperation(current, { type: 'operationSettled', setup }); + } catch (error) { + settleOperation(current, { + type: 'operationFailed', + failure: errorMessage(error, 'The saved target could not be forgotten.'), + }); + } + } + + async function openBrowser() { + const current = startOperation('open-browser'); + if (current === null) return; + try { + await launchUi(); + settleOperation(current, { type: 'operationSettled' }); + } catch (error) { + settleOperation(current, { + type: 'operationFailed', + failure: errorMessage(error, 'VidXP could not be opened.'), + }); + } + } + + const profile = state.setup ? selectedProfile(state.setup) : null; + const operationPending = state.operation !== null; + return ( + +