Repository: tensorzero/tensorzero (language: rust)

Issue:
Add `deny_unknown_fields` to all structs that are part of params of any request

Tutorial Docker Compose fails since `/clients/python-asyncio` does not exist
When running `docker compose up` in the `examples/email-data-extraction` the command fails due to the script attempting to copy a missing directory.

```cd 04-email-data-extraction
❯ docker compose up --always-recreate-deps email-data-extraction

[+] Running 0/0
[+] Running 0/1l-data-extraction  Building                                                                                                                                                         0.1s 
[+] Building 0.2s (7/8)                                                                                                                                                            docker:desktop-linux 
 => [email-data-extraction internal] load build definition from Dockerfile                                                                                                                         0.0s
 => => transferring dockerfile: 297B                                                                                                                                                               0.0s
 => [email-data-extraction internal] load metadata for docker.io/library/python:3.10-slim-bookworm                                                                                                 0.1s
 => [email-data-extraction internal] load .dockerignore                                                                                                                                            0.0s
 => => transferring context: 48B                                                                                                                                                                   0.0s
 => [email-data-extraction 1/4] FROM docker.io/library/python:3.10-slim-bookworm@sha256:61912260e578182d00b5e163eb4cfb13b35fb8782c98d1df9ed584cec8939097                                           0.0s
 => [email-data-extraction internal] load build context                                                                                                                                            0.0s
 => => transferring context: 2B                                                                                                                                                                    0.0s
 => CACHED [email-data-extraction 2/4] WORKDIR /app                                                                                                                                                0.0s
 => ERROR [email-data-extraction 3/4] COPY clients/python-asyncio /app/tensorzero/python-asyncio                                                                                                   0.0s
------
[+] Running 0/1extraction 3/4] COPY clients/python-asyncio /app/tensorzero/python-asyncio:
 ⠹ Service email-data-extraction  Building                                                                                                                                                         0.3s 
failed to solve: failed to compute cache key: failed to calculate checksum of ref f2e14973-1aec-4e45-b5a2-0d1fb994b61a::c1e85amn16pfznjeftsb447ad: "/clients/python-asyncio": not found```


Discussion / hints:

Fix patch:
diff --git a/.cargo/config.toml b/.cargo/config.toml
index 07e57feb4..4de730a51 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -1,4 +1,4 @@
-[build]
+[target.'cfg(not(target_arch = "wasm32"))']
 rustflags = [
     "-C",
     "target-cpu=native",
@@ -8,9 +8,9 @@ rustflags = [
 
 
 [alias]
-test-unit = "nextest run --lib --bins --profile unit"
-test-e2e = "nextest run --test e2e --features e2e_tests"
-test-all = "nextest run --features e2e_tests"
+test-unit = "nextest run -p gateway --lib --bins --profile unit"
+test-e2e = "nextest run -p gateway --test e2e --features e2e_tests"
+test-all = "nextest run -p gateway --features e2e_tests"
 
 run-e2e = "run --bin gateway --features e2e_tests -- gateway/tests/e2e/tensorzero.toml"
 watch-e2e = "watch -x run-e2e"
diff --git a/.github/workflows/general.yml b/.github/workflows/general.yml
index a8da2b3f6..93130aabe 100644
--- a/.github/workflows/general.yml
+++ b/.github/workflows/general.yml
@@ -3,10 +3,14 @@ name: General Checks
 on:
   merge_group:
   pull_request:
-    branches: ["main"]
+    branches: ["main", "dashboard"]
 
 env:
   FORCE_COLOR: 1
+  CLICKHOUSE_URL: "http://localhost:8123/tensorzero"
+  OPENAI_API_KEY: ${{secrets.OPENAI_API_KEY}}
+  FIREWORKS_API_KEY: ${{secrets.FIREWORKS_API_KEY}}
+  FIREWORKS_ACCOUNT_ID: ${{secrets.FIREWORKS_ACCOUNT_ID}}
 
 jobs:
   validate:
@@ -45,3 +49,59 @@ jobs:
           python -m pip install ruff
           ruff format --check .
           ruff check --output-format=github --extend-select I .
+
+      - name: Run mypy type checking
+        working-directory: clients
+        run: |
+          python -m pip install -r requirements.txt
+          python -m pip install mypy
+          python -m mypy python --strict
+
+      - name: Setup Node.js
+        uses: actions/setup-node@v4
+        with:
+          node-version: "22.9.0"
+
+      - name: Install wasm-pack
+        run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
+
+      - name: Build minijinja WASM bindings
+        working-directory: dashboard/app/utils/minijinja
+        run: wasm-pack build --features console_error_panic_hook
+
+      - name: Run minijinja WASM tests
+        working-directory: dashboard/app/utils/minijinja
+        run: wasm-pack test --node --features console_error_panic_hook
+
+      - name: Install npm dependencies
+        working-directory: dashboard
+        run: npm install --platform=linux
+
+      - name: Run ESLint
+        working-directory: dashboard
+        run: |
+          npx eslint . --fix --max-warnings=0 --config eslint.config.js --cache
+
+      - name: Run Prettier
+        working-directory: dashboard
+        run: |
+          npx prettier --write --list-different "**/*.{js,jsx,ts,tsx,css,scss,html,json,yaml,md}" --ignore-path "**/*.ipynb"
+
+      - name: Run TypeScript type checking
+        working-directory: dashboard
+        run: |
+          npx react-router typegen
+          npx tsc
+
+      - name: Start services for dashboard tests
+        working-directory: dashboard
+        run: |
+          echo "OPENAI_API_KEY=${{secrets.OPENAI_API_KEY}}" >> .env
+          echo "FIREWORKS_API_KEY=${{secrets.FIREWORKS_API_KEY}}" >> .env
+          echo "FIREWORKS_ACCOUNT_ID=${{secrets.FIREWORKS_ACCOUNT_ID}}" >> .env
+          echo "CLICKHOUSE_URL=http://localhost:8123/tensorzero" >> .env
+          docker compose -f fixtures/docker-compose.yml up -d
+
+      - name: Run dashboard tests
+        working-directory: dashboard
+        run: npm test
diff --git a/.github/workflows/merge-queue.yml b/.github/workflows/merge-queue.yml
index 849723cd7..b30e04b62 100644
--- a/.github/workflows/merge-queue.yml
+++ b/.github/workflows/merge-queue.yml
@@ -2,7 +2,6 @@ name: Merge Queue Checks
 
 on:
   merge_group:
-
 env:
   ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} # for E2E tests
   AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} # for E2E tests
@@ -104,7 +103,23 @@ jobs:
       - name: Terminate the gateway
         run: |
           echo "Killing gateway with pid $GATEWAY_PID"
-          kill -9 $GATEWAY_PID
+          kill $GATEWAY_PID
+
+      - name: Setup Node.js
+        uses: actions/setup-node@v4
+        with:
+          node-version: "22.9.0"
+
+      - name: Install wasm-pack
+        run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
+
+      - name: Build minijinja WASM bindings
+        working-directory: dashboard/app/utils/minijinja
+        run: wasm-pack build --features console_error_panic_hook
+
+      - name: Run minijinja WASM tests
+        working-directory: dashboard/app/utils/minijinja
+        run: wasm-pack test --node --features console_error_panic_hook
 
       - name: Build Docker container for production deployment tests
         run: docker build -t tensorzero/gateway .
@@ -122,3 +137,41 @@ jobs:
 
       - name: Run inference for production deployment tests
         run: examples/production-deployment/run_example_inference.sh
+
+      - name: Take down docker compose for production deployment tests
+        run: |
+          docker compose -f examples/production-deployment/docker-compose.yml down
+          docker compose -f gateway/tests/e2e/docker-compose.yml down
+
+      - name: Install npm dependencies
+        working-directory: dashboard
+        run: npm install --platform=linux
+
+      - name: Run ESLint
+        working-directory: dashboard
+        run: |
+          npx eslint . --fix --max-warnings=0 --config eslint.config.js --cache
+
+      - name: Run Prettier
+        working-directory: dashboard
+        run: |
+          npx prettier --write --list-different "**/*.{js,jsx,ts,tsx,css,scss,html,json,yaml,md}" --ignore-path "**/*.ipynb"
+
+      - name: Run TypeScript type checking
+        working-directory: dashboard
+        run: |
+          npx react-router typegen
+          npx tsc
+
+      - name: Start services for dashboard tests
+        working-directory: dashboard
+        run: |
+          echo "OPENAI_API_KEY=${{secrets.OPENAI_API_KEY}}" >> .env
+          echo "FIREWORKS_API_KEY=${{secrets.FIREWORKS_API_KEY}}" >> .env
+          echo "FIREWORKS_ACCOUNT_ID=${{secrets.FIREWORKS_ACCOUNT_ID}}" >> .env
+          echo "CLICKHOUSE_URL=http://localhost:8123/tensorzero" >> .env
+          docker compose -f fixtures/docker-compose.yml up -d
+
+      - name: Run dashboard tests
+        working-directory: dashboard
+        run: npm test
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 8b3904795..df940f2a8 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -2,7 +2,7 @@ name: PR Checks
 
 on:
   pull_request:
-    branches: ["main"]
+    branches: ["main", "dashboard"]
 
 jobs:
   # We don't want to run live-tests on PRs, so we use a dummy job to satisfy branch protection checks
diff --git a/.gitignore b/.gitignore
index 8ab55ae0c..a6a7728fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,4 +37,3 @@ credentials/
 
 # Node
 node_modules/
-
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 9423854f0..5ce13650e 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -51,6 +51,40 @@ repos:
         pass_filenames: false
         always_run: true
 
+      - id: prettier
+        name: prettier
+        entry: npx prettier
+        language: node
+        types_or:
+          [css, html, javascript, json, jsx, markdown, scss, ts, tsx, yaml]
+        args: ["--write", "--list-different"]
+        additional_dependencies:
+          - prettier
+          - "@prettier/plugin-xml"
+        always_run: true
+        exclude: '.*\.ipynb$'
+
+      - id: eslint
+        name: eslint
+        entry: bash -c 'cd dashboard && npx eslint'
+        language: node
+        types_or: [javascript, jsx, ts, tsx]
+        additional_dependencies:
+          - eslint
+          - "@typescript-eslint/parser"
+          - "@typescript-eslint/eslint-plugin"
+        pass_filenames: false
+        always_run: true
+
+      - id: tsc
+        name: typescript
+        entry: bash -c 'cd dashboard && tsc'
+        language: node
+        pass_filenames: false
+        additional_dependencies:
+          - typescript
+        always_run: true
+
   - repo: https://github.com/srstevenson/nb-clean
     rev: 3.2.0
     hooks:
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 000000000..c1647ac7e
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,9 @@
+{
+  "tabWidth": 2,
+  "useTabs": false,
+  "semi": true,
+  "trailingComma": "all",
+  "printWidth": 80,
+  "bracketSpacing": true,
+  "arrowParens": "always"
+}
diff --git a/Cargo.lock b/Cargo.lock
index 7ef51249f..cc29ad748 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -91,9 +91,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.93"
+version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
+checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
 
 [[package]]
 name = "async-stream"
@@ -153,7 +153,7 @@ dependencies = [
  "aws-sdk-sts",
  "aws-smithy-async",
  "aws-smithy-http",
- "aws-smithy-json",
+ "aws-smithy-json 0.60.7",
  "aws-smithy-runtime",
  "aws-smithy-runtime-api",
  "aws-smithy-types",
@@ -184,9 +184,9 @@ dependencies = [
 
 [[package]]
 name = "aws-runtime"
-version = "1.4.3"
+version = "1.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a10d5c055aa540164d9561a0e2e74ad30f0dcf7393c3a92f6733ddf9c5762468"
+checksum = "b5ac934720fbb46206292d2c75b57e67acfc56fe7dfd34fb9a02334af08409ea"
 dependencies = [
  "aws-credential-types",
  "aws-sigv4",
@@ -209,21 +209,22 @@ dependencies = [
 
 [[package]]
 name = "aws-sdk-bedrockruntime"
-version = "1.62.0"
+version = "1.64.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa1d54e1253e3739bfa6d60df813a093b916971fc423aa90fee9ca607438a177"
+checksum = "37ed488cf4e3f3acd56ead725dc01a60afcad0161b46c692aa605d63c679e7d0"
 dependencies = [
  "aws-credential-types",
  "aws-runtime",
  "aws-smithy-async",
  "aws-smithy-eventstream",
  "aws-smithy-http",
- "aws-smithy-json",
+ "aws-smithy-json 0.61.1",
  "aws-smithy-runtime",
  "aws-smithy-runtime-api",
  "aws-smithy-types",
  "aws-types",
  "bytes",
+ "fastrand",
  "http 0.2.12",
  "once_cell",
  "regex-lite",
@@ -232,15 +233,15 @@ dependencies = [
 
 [[package]]
 name = "aws-sdk-sso"
-version = "1.49.0"
+version = "1.50.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09677244a9da92172c8dc60109b4a9658597d4d298b188dd0018b6a66b410ca4"
+checksum = "05ca43a4ef210894f93096039ef1d6fa4ad3edfabb3be92b80908b9f2e4b4eab"
 dependencies = [
  "aws-credential-types",
  "aws-runtime",
  "aws-smithy-async",
  "aws-smithy-http",
- "aws-smithy-json",
+ "aws-smithy-json 0.61.1",
  "aws-smithy-runtime",
  "aws-smithy-runtime-api",
  "aws-smithy-types",
@@ -254,15 +255,15 @@ dependencies = [
 
 [[package]]
 name = "aws-sdk-ssooidc"
-version = "1.50.0"
+version = "1.51.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81fea2f3a8bb3bd10932ae7ad59cc59f65f270fc9183a7e91f501dc5efbef7ee"
+checksum = "abaf490c2e48eed0bb8e2da2fb08405647bd7f253996e0f93b981958ea0f73b0"
 dependencies = [
  "aws-credential-types",
  "aws-runtime",
  "aws-smithy-async",
  "aws-smithy-http",
- "aws-smithy-json",
+ "aws-smithy-json 0.61.1",
  "aws-smithy-runtime",
  "aws-smithy-runtime-api",
  "aws-smithy-types",
@@ -276,15 +277,15 @@ dependencies = [
 
 [[package]]
 name = "aws-sdk-sts"
-version = "1.50.0"
+version = "1.51.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ada54e5f26ac246dc79727def52f7f8ed38915cb47781e2a72213957dc3a7d5"
+checksum = "b68fde0d69c8bfdc1060ea7da21df3e39f6014da316783336deff0a9ec28f4bf"
 dependencies = [
  "aws-credential-types",
  "aws-runtime",
  "aws-smithy-async",
  "aws-smithy-http",
- "aws-smithy-json",
+ "aws-smithy-json 0.61.1",
  "aws-smithy-query",
  "aws-smithy-runtime",
  "aws-smithy-runtime-api",
@@ -299,9 +300,9 @@ dependencies = [
 
 [[package]]
 name = "aws-sigv4"
-version = "1.2.5"
+version = "1.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5619742a0d8f253be760bfbb8e8e8368c69e3587e4637af5754e488a611499b1"
+checksum = "7d3820e0c08d0737872ff3c7c1f21ebbb6693d832312d6152bf18ef50a5471c2"
 dependencies = [
  "aws-credential-types",
  "aws-smithy-http",
@@ -312,7 +313,7 @@ dependencies = [
  "hex",
  "hmac",
  "http 0.2.12",
- "http 1.1.0",
+ "http 1.2.0",
  "once_cell",
  "percent-encoding",
  "sha2",
@@ -322,9 +323,9 @@ dependencies = [
 
 [[package]]
 name = "aws-smithy-async"
-version = "1.2.1"
+version = "1.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62220bc6e97f946ddd51b5f1361f78996e704677afc518a4ff66b7a72ea1378c"
+checksum = "8aa8ff1492fd9fb99ae28e8467af0dbbb7c31512b16fabf1a0f10d7bb6ef78bb"
 dependencies = [
  "futures-util",
  "pin-project-lite",
@@ -372,6 +373,15 @@ dependencies = [
  "aws-smithy-types",
 ]
 
+[[package]]
+name = "aws-smithy-json"
+version = "0.61.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee4e69cc50921eb913c6b662f8d909131bb3e6ad6cb6090d3a39b66fc5c52095"
+dependencies = [
+ "aws-smithy-types",
+]
+
 [[package]]
 name = "aws-smithy-query"
 version = "0.60.7"
@@ -384,9 +394,9 @@ dependencies = [
 
 [[package]]
 name = "aws-smithy-runtime"
-version = "1.7.3"
+version = "1.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be28bd063fa91fd871d131fc8b68d7cd4c5fa0869bea68daca50dcb1cbd76be2"
+checksum = "431a10d0e07e09091284ef04453dae4069283aa108d209974d67e77ae1caa658"
 dependencies = [
  "aws-smithy-async",
  "aws-smithy-http",
@@ -399,7 +409,7 @@ dependencies = [
  "http-body 0.4.6",
  "http-body 1.0.1",
  "httparse",
- "hyper 0.14.31",
+ "hyper 0.14.32",
  "hyper-rustls 0.24.2",
  "once_cell",
  "pin-project-lite",
@@ -419,7 +429,7 @@ dependencies = [
  "aws-smithy-types",
  "bytes",
  "http 0.2.12",
- "http 1.1.0",
+ "http 1.2.0",
  "pin-project-lite",
  "tokio",
  "tracing",
@@ -428,16 +438,16 @@ dependencies = [
 
 [[package]]
 name = "aws-smithy-types"
-version = "1.2.9"
+version = "1.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fbd94a32b3a7d55d3806fe27d98d3ad393050439dd05eb53ece36ec5e3d3510"
+checksum = "8ecbf4d5dfb169812e2b240a4350f15ad3c6b03a54074e5712818801615f2dc5"
 dependencies = [
  "base64-simd",
  "bytes",
  "bytes-utils",
  "futures-core",
  "http 0.2.12",
- "http 1.1.0",
+ "http 1.2.0",
  "http-body 0.4.6",
  "http-body 1.0.1",
  "http-body-util",
@@ -486,10 +496,10 @@ dependencies = [
  "axum-macros",
  "bytes",
  "futures-util",
- "http 1.1.0",
+ "http 1.2.0",
  "http-body 1.0.1",
  "http-body-util",
- "hyper 1.5.1",
+ "hyper 1.5.2",
  "hyper-util",
  "itoa",
  "matchit",
@@ -502,9 +512,9 @@ dependencies = [
  "serde_json",
  "serde_path_to_error",
  "serde_urlencoded",
- "sync_wrapper 1.0.2",
+ "sync_wrapper",
  "tokio",
- "tower 0.5.1",
+ "tower 0.5.2",
  "tower-layer",
  "tower-service",
  "tracing",
@@ -519,13 +529,13 @@ dependencies = [
  "async-trait",
  "bytes",
  "futures-util",
- "http 1.1.0",
+ "http 1.2.0",
  "http-body 1.0.1",
  "http-body-util",
  "mime",
  "pin-project-lite",
  "rustversion",
- "sync_wrapper 1.0.2",
+ "sync_wrapper",
  "tower-layer",
  "tower-service",
  "tracing",
@@ -662,9 +672,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.2.2"
+version = "1.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc"
+checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf"
 dependencies = [
  "shlex",
 ]
@@ -689,9 +699,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
 
 [[package]]
 name = "clap"
-version = "4.5.21"
+version = "4.5.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
+checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -699,9 +709,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.21"
+version = "4.5.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
+checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
 dependencies = [
  "anstream",
  "anstyle",
@@ -723,9 +733,9 @@ dependencies = [
 
 [[package]]
 name = "clap_lex"
-version = "0.7.3"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
+checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
 
 [[package]]
 name = "colorchoice"
@@ -733,6 +743,16 @@ version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
 
+[[package]]
+name = "console_error_panic_hook"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
+dependencies = [
+ "cfg-if 1.0.0",
+ "wasm-bindgen",
+]
+
 [[package]]
 name = "core-foundation"
 version = "0.9.4"
@@ -778,9 +798,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.20"
+version = "0.8.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
 
 [[package]]
 name = "crypto-common"
@@ -935,9 +955,9 @@ dependencies = [
 
 [[package]]
 name = "fastrand"
-version = "2.2.0"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "fnv"
@@ -1175,7 +1195,7 @@ dependencies = [
  "fnv",
  "futures-core",
  "futures-sink",
- "http 1.1.0",
+ "http 1.2.0",
  "indexmap",
  "slab",
  "tokio",
@@ -1238,9 +1258,9 @@ dependencies = [
 
 [[package]]
 name = "http"
-version = "1.1.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
+checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
 dependencies = [
  "bytes",
  "fnv",
@@ -1265,7 +1285,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
 dependencies = [
  "bytes",
- "http 1.1.0",
+ "http 1.2.0",
 ]
 
 [[package]]
@@ -1276,7 +1296,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
 dependencies = [
  "bytes",
  "futures-util",
- "http 1.1.0",
+ "http 1.2.0",
  "http-body 1.0.1",
  "pin-project-lite",
 ]
@@ -1295,9 +1315,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
 
 [[package]]
 name = "hyper"
-version = "0.14.31"
+version = "0.14.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85"
+checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -1319,15 +1339,15 @@ dependencies = [
 
 [[package]]
 name = "hyper"
-version = "1.5.1"
+version = "1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f"
+checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0"
 dependencies = [
  "bytes",
  "futures-channel",
  "futures-util",
  "h2 0.4.7",
- "http 1.1.0",
+ "http 1.2.0",
  "http-body 1.0.1",
  "httparse",
  "httpdate",
@@ -1346,7 +1366,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
 dependencies = [
  "futures-util",
  "http 0.2.12",
- "hyper 0.14.31",
+ "hyper 0.14.32",
  "log",
  "rustls 0.21.12",
  "rustls-native-certs",
@@ -1361,13 +1381,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
 dependencies = [
  "futures-util",
- "http 1.1.0",
- "hyper 1.5.1",
+ "http 1.2.0",
+ "hyper 1.5.2",
  "hyper-util",
- "rustls 0.23.19",
+ "rustls 0.23.20",
  "rustls-pki-types",
  "tokio",
- "tokio-rustls 0.26.0",
+ "tokio-rustls 0.26.1",
  "tower-service",
  "webpki-roots",
 ]
@@ -1381,9 +1401,9 @@ dependencies = [
  "bytes",
  "futures-channel",
  "futures-util",
- "http 1.1.0",
+ "http 1.2.0",
  "http-body 1.0.1",
- "hyper 1.5.1",
+ "hyper 1.5.2",
  "pin-project-lite",
  "socket2",
  "tokio",
@@ -1584,9 +1604,9 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
 
 [[package]]
 name = "js-sys"
-version = "0.3.74"
+version = "0.3.76"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705"
+checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
 dependencies = [
  "once_cell",
  "wasm-bindgen",
@@ -1645,9 +1665,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
-version = "0.2.167"
+version = "0.2.168"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
+checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
 
 [[package]]
 name = "libmimalloc-sys"
@@ -1732,7 +1752,7 @@ checksum = "b4f0c8427b39666bf970460908b213ec09b3b350f20c0c2eabcbba51704a08e6"
 dependencies = [
  "base64 0.22.1",
  "http-body-util",
- "hyper 1.5.1",
+ "hyper 1.5.2",
  "hyper-util",
  "indexmap",
  "ipnet",
@@ -1784,6 +1804,16 @@ dependencies = [
  "unicase",
 ]
 
+[[package]]
+name = "minicov"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b"
+dependencies = [
+ "cc",
+ "walkdir",
+]
+
 [[package]]
 name = "minijinja"
 version = "2.5.0"
@@ -1795,6 +1825,19 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "minijinja-bindings"
+version = "0.1.0"
+dependencies = [
+ "console_error_panic_hook",
+ "minijinja",
+ "serde",
+ "serde-wasm-bindgen",
+ "serde_json",
+ "wasm-bindgen",
+ "wasm-bindgen-test",
+]
+
 [[package]]
 name = "minimal-lexical"
 version = "0.2.1"
@@ -1803,9 +1846,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.0"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
+checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
 dependencies = [
  "adler2",
 ]
@@ -2101,9 +2144,9 @@ dependencies = [
 
 [[package]]
 name = "quanta"
-version = "0.12.3"
+version = "0.12.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5"
+checksum = "773ce68d0bb9bc7ef20be3536ffe94e223e1f365bd374108b2659fac0c65cfe6"
 dependencies = [
  "crossbeam-utils",
  "libc",
@@ -2125,9 +2168,9 @@ dependencies = [
  "quinn-proto",
  "quinn-udp",
  "rustc-hash",
- "rustls 0.23.19",
+ "rustls 0.23.20",
  "socket2",
- "thiserror 2.0.4",
+ "thiserror 2.0.7",
  "tokio",
  "tracing",
 ]
@@ -2143,10 +2186,10 @@ dependencies = [
  "rand",
  "ring",
  "rustc-hash",
- "rustls 0.23.19",
+ "rustls 0.23.20",
  "rustls-pki-types",
  "slab",
- "thiserror 2.0.4",
+ "thiserror 2.0.7",
  "tinyvec",
  "tracing",
  "web-time",
@@ -2154,9 +2197,9 @@ dependencies = [
 
 [[package]]
 name = "quinn-udp"
-version = "0.5.7"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da"
+checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527"
 dependencies = [
  "cfg_aliases",
  "libc",
@@ -2216,9 +2259,9 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.7"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
+checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
 dependencies = [
  "bitflags 2.6.0",
 ]
@@ -2284,10 +2327,10 @@ dependencies = [
  "futures-channel",
  "futures-core",
  "futures-util",
- "http 1.1.0",
+ "http 1.2.0",
  "http-body 1.0.1",
  "http-body-util",
- "hyper 1.5.1",
+ "hyper 1.5.2",
  "hyper-rustls 0.27.3",
  "hyper-util",
  "ipnet",
@@ -2299,15 +2342,15 @@ dependencies = [
  "percent-encoding",
  "pin-project-lite",
  "quinn",
- "rustls 0.23.19",
+ "rustls 0.23.20",
  "rustls-pemfile 2.2.0",
  "rustls-pki-types",
  "serde",
  "serde_json",
  "serde_urlencoded",
- "sync_wrapper 1.0.2",
+ "sync_wrapper",
  "tokio",
- "tokio-rustls 0.26.0",
+ "tokio-rustls 0.26.1",
  "tokio-util",
  "tower-service",
  "url",
@@ -2373,15 +2416,15 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.38.41"
+version = "0.38.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6"
+checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
 dependencies = [
  "bitflags 2.6.0",
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -2398,9 +2441,9 @@ dependencies = [
 
 [[package]]
 name = "rustls"
-version = "0.23.19"
+version = "0.23.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1"
+checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b"
 dependencies = [
  "once_cell",
  "ring",
@@ -2442,9 +2485,9 @@ dependencies = [
 
 [[package]]
 name = "rustls-pki-types"
-version = "1.10.0"
+version = "1.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
+checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37"
 dependencies = [
  "web-time",
 ]
@@ -2482,6 +2525,15 @@ version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
 [[package]]
 name = "schannel"
 version = "0.1.27"
@@ -2491,6 +2543,12 @@ dependencies = [
  "windows-sys 0.59.0",
 ]
 
+[[package]]
+name = "scoped-tls"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
+
 [[package]]
 name = "scopeguard"
 version = "1.2.0"
@@ -2542,30 +2600,41 @@ dependencies = [
 
 [[package]]
 name = "self_cell"
-version = "1.0.4"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a"
+checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe"
 
 [[package]]
 name = "semver"
-version = "1.0.23"
+version = "1.0.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
 
 [[package]]
 name = "serde"
-version = "1.0.215"
+version = "1.0.216"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
+checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
 dependencies = [
  "serde_derive",
 ]
 
+[[package]]
+name = "serde-wasm-bindgen"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b"
+dependencies = [
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+]
+
 [[package]]
 name = "serde_derive"
-version = "1.0.215"
+version = "1.0.216"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
+checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2761,12 +2830,6 @@ dependencies = [
  "unicode-ident",
 ]
 
-[[package]]
-name = "sync_wrapper"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
-
 [[package]]
 name = "sync_wrapper"
 version = "1.0.2"
@@ -2811,11 +2874,11 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "2.0.4"
+version = "2.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490"
+checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767"
 dependencies = [
- "thiserror-impl 2.0.4",
+ "thiserror-impl 2.0.7",
 ]
 
 [[package]]
@@ -2831,9 +2894,9 @@ dependencies = [
 
 [[package]]
 name = "thiserror-impl"
-version = "2.0.4"
+version = "2.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061"
+checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2947,20 +3010,19 @@ dependencies = [
 
 [[package]]
 name = "tokio-rustls"
-version = "0.26.0"
+version = "0.26.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
+checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
 dependencies = [
- "rustls 0.23.19",
- "rustls-pki-types",
+ "rustls 0.23.20",
  "tokio",
 ]
 
 [[package]]
 name = "tokio-stream"
-version = "0.1.16"
+version = "0.1.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1"
+checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
 dependencies = [
  "futures-core",
  "pin-project-lite",
@@ -2969,9 +3031,9 @@ dependencies = [
 
 [[package]]
 name = "tokio-util"
-version = "0.7.12"
+version = "0.7.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
+checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
 dependencies = [
  "bytes",
  "futures-core",
@@ -3031,14 +3093,14 @@ dependencies = [
 
 [[package]]
 name = "tower"
-version = "0.5.1"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
+checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
 dependencies = [
  "futures-core",
  "futures-util",
  "pin-project-lite",
- "sync_wrapper 0.1.2",
+ "sync_wrapper",
  "tokio",
  "tower-layer",
  "tower-service",
@@ -3253,6 +3315,16 @@ version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64"
 
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
 [[package]]
 name = "want"
 version = "0.3.1"
@@ -3270,9 +3342,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.97"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c"
+checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
 dependencies = [
  "cfg-if 1.0.0",
  "once_cell",
@@ -3281,13 +3353,12 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.97"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd"
+checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
 dependencies = [
  "bumpalo",
  "log",
- "once_cell",
  "proc-macro2",
  "quote",
  "syn",
@@ -3296,9 +3367,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.47"
+version = "0.4.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d"
+checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2"
 dependencies = [
  "cfg-if 1.0.0",
  "js-sys",
@@ -3309,9 +3380,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.97"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051"
+checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -3319,9 +3390,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.97"
+version = "0.2.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d"
+checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3332,9 +3403,34 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.97"
+version = "0.2.99"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
+
+[[package]]
+name = "wasm-bindgen-test"
+version = "0.3.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49"
+checksum = "c61d44563646eb934577f2772656c7ad5e9c90fac78aa8013d776fcdaf24625d"
+dependencies = [
+ "js-sys",
+ "minicov",
+ "scoped-tls",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-bindgen-test-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-test-macro"
+version = "0.3.49"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54171416ce73aa0b9c377b51cc3cb542becee1cd678204812e8392e5b0e4a031"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
 
 [[package]]
 name = "wasm-streams"
@@ -3351,9 +3447,9 @@ dependencies = [
 
 [[package]]
 name = "web-sys"
-version = "0.3.74"
+version = "0.3.76"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c"
+checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -3394,6 +3490,15 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
+[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
 [[package]]
 name = "winapi-x86_64-pc-windows-gnu"
 version = "0.4.0"
diff --git a/Cargo.toml b/Cargo.toml
index 679175f4a..a05a965d1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,6 +2,7 @@
 members = [
     "gateway",
     "gateway/tests/mock-inference-provider",
+    "dashboard/app/utils/minijinja",
 ]
 resolver = "2"
 
@@ -26,3 +27,6 @@ inherits = "release"
 lto = "fat"
 codegen-units = 1
 incremental = false
+
+[profile.release.package.minijinja-bindings]
+opt-level = "s"
diff --git a/dashboard/.dockerignore b/dashboard/.dockerignore
new file mode 100644
index 000000000..54f78fa7b
--- /dev/null
+++ b/dashboard/.dockerignore
@@ -0,0 +1,4 @@
+.react-router
+build
+node_modules
+README.md
diff --git a/dashboard/.gitignore b/dashboard/.gitignore
new file mode 100644
index 000000000..1faab386f
--- /dev/null
+++ b/dashboard/.gitignore
@@ -0,0 +1,7 @@
+.DS_Store
+/node_modules/
+
+# React Router
+/.react-router/
+/build/
+.vite/
diff --git a/dashboard/Dockerfile b/dashboard/Dockerfile
new file mode 100644
index 000000000..163c672fd
--- /dev/null
+++ b/dashboard/Dockerfile
@@ -0,0 +1,22 @@
+FROM node:20-alpine AS development-dependencies-env
+COPY . /app
+WORKDIR /app
+RUN npm ci
+
+FROM node:20-alpine AS production-dependencies-env
+COPY ./package.json package-lock.json /app/
+WORKDIR /app
+RUN npm ci --omit=dev
+
+FROM node:20-alpine AS build-env
+COPY . /app/
+COPY --from=development-dependencies-env /app/node_modules /app/node_modules
+WORKDIR /app
+RUN npm run build
+
+FROM node:20-alpine
+COPY ./package.json package-lock.json /app/
+COPY --from=production-dependencies-env /app/node_modules /app/node_modules
+COPY --from=build-env /app/build /app/build
+WORKDIR /app
+CMD ["npm", "run", "start"]
diff --git a/dashboard/Dockerfile.bun b/dashboard/Dockerfile.bun
new file mode 100644
index 000000000..e97f76156
--- /dev/null
+++ b/dashboard/Dockerfile.bun
@@ -0,0 +1,25 @@
+FROM oven/bun:1 AS dependencies-env
+COPY . /app
+
+FROM dependencies-env AS development-dependencies-env
+COPY ./package.json bun.lockb /app/
+WORKDIR /app
+RUN bun i --frozen-lockfile
+
+FROM dependencies-env AS production-dependencies-env
+COPY ./package.json bun.lockb /app/
+WORKDIR /app
+RUN bun i --production
+
+FROM dependencies-env AS build-env
+COPY ./package.json bun.lockb /app/
+COPY --from=development-dependencies-env /app/node_modules /app/node_modules
+WORKDIR /app
+RUN bun run build
+
+FROM dependencies-env
+COPY ./package.json bun.lockb /app/
+COPY --from=production-dependencies-env /app/node_modules /app/node_modules
+COPY --from=build-env /app/build /app/build
+WORKDIR /app
+CMD ["bun", "run", "start"]
diff --git a/dashboard/Dockerfile.pnpm b/dashboard/Dockerfile.pnpm
new file mode 100644
index 000000000..dd6ceb987
--- /dev/null
+++ b/dashboard/Dockerfile.pnpm
@@ -0,0 +1,26 @@
+FROM node:20-alpine AS dependencies-env
+RUN npm i -g pnpm
+COPY . /app
+
+FROM dependencies-env AS development-dependencies-env
+COPY ./package.json pnpm-lock.yaml /app/
+WORKDIR /app
+RUN pnpm i --frozen-lockfile
+
+FROM dependencies-env AS production-dependencies-env
+COPY ./package.json pnpm-lock.yaml /app/
+WORKDIR /app
+RUN pnpm i --prod --frozen-lockfile
+
+FROM dependencies-env AS build-env
+COPY ./package.json pnpm-lock.yaml /app/
+COPY --from=development-dependencies-env /app/node_modules /app/node_modules
+WORKDIR /app
+RUN pnpm build
+
+FROM dependencies-env
+COPY ./package.json pnpm-lock.yaml /app/
+COPY --from=production-dependencies-env /app/node_modules /app/node_modules
+COPY --from=build-env /app/build /app/build
+WORKDIR /app
+CMD ["pnpm", "start"]
diff --git a/dashboard/README.md b/dashboard/README.md
new file mode 100644
index 000000000..fd92d9037
--- /dev/null
+++ b/dashboard/README.md
@@ -0,0 +1,56 @@
+# TensorZero Dashboard
+
+## Status
+
+This dashboard is currently a work in progress.
+
+Our goals for this project are to:
+
+- [ ] Allow users to run TensorZero recipes through the dashboard. To start, this will include:
+
+  - [ ] Supervised fine-tuning
+  - [ ] Dynamic in-context learning
+
+- [ ] Allow users to review inferences and episodes and provide feedback to either.
+- [ ] Provide an easy dashboard showing the relative performance of different variants for a particular function.
+- [ ] Allow users to edit the configuration through the dashboard.
+
+Currently, we are building out the dashboard incrementally.
+We have the beginning of a fine-tuning form that uses the OpenAI fine-tuning API.
+
+## Running the Dashboard
+
+### Prerequisites
+
+- Node.js (we have only tested with v22.9.0)
+- Docker Compose
+- a Rust toolchain
+
+### Setup
+
+Currently, the dashboard only runs against hardcoded fixtures in `fixtures/`.
+It depends on a running ClickHouse instance that has been initialized with the TensorZero data model.
+We include some fixture data as well in order to exercise some functionality.
+You will need Docker Compose installed to run the dependencies.
+
+It also requires a one-time build of a WebAssembly module from Rust source code that is used to ensure consistent templating of messages across the gateway and dashboard.
+
+Here are the steps in order to run or test the dashboard assuming you have the prerequisites installed and this repository checked out:
+
+1. Install npm dependencies: `npm install`
+2. Build the WebAssembly module following instructions in `app/utils/minijinja/README.md`.
+3. Create a `.env` file in the `dashboard` directory and set the following environment variables for the server:
+
+```bash
+OPENAI_API_KEY=<your-key>
+FIREWORKS_API_KEY=<your-key>
+FIREWORKS_ACCOUNT_ID=<your-account-id>
+CLICKHOUSE_URL=<your-clickhouse-url> # For testing, set to http://localhost:8123/tensorzero
+```
+
+4. Run the dependencies: `docker compose -f fixtures/docker-compose.yml up`
+
+With the dependencies running, you can run the tests with `npm run test`.
+Similarly, you can start a development server with `npm run dev`.
+
+We do not currently have a production build process or any way to change configuration.
diff --git a/dashboard/app/components/ui/accordion.tsx b/dashboard/app/components/ui/accordion.tsx
new file mode 100644
index 000000000..debc09c2d
--- /dev/null
+++ b/dashboard/app/components/ui/accordion.tsx
@@ -0,0 +1,55 @@
+import * as React from "react";
+import * as AccordionPrimitive from "@radix-ui/react-accordion";
+import { ChevronDown } from "lucide-react";
+
+import { cn } from "~/utils/common";
+
+const Accordion = AccordionPrimitive.Root;
+
+const AccordionItem = React.forwardRef<
+  React.ElementRef<typeof AccordionPrimitive.Item>,
+  React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
+>(({ className, ...props }, ref) => (
+  <AccordionPrimitive.Item
+    ref={ref}
+    className={cn("border-b", className)}
+    {...props}
+  />
+));
+AccordionItem.displayName = "AccordionItem";
+
+const AccordionTrigger = React.forwardRef<
+  React.ElementRef<typeof AccordionPrimitive.Trigger>,
+  React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
+>(({ className, children, ...props }, ref) => (
+  <AccordionPrimitive.Header className="flex">
+    <AccordionPrimitive.Trigger
+      ref={ref}
+      className={cn(
+        "flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline text-left [&[data-state=open]>svg]:rotate-180",
+        className,
+      )}
+      {...props}
+    >
+      {children}
+      <ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
+    </AccordionPrimitive.Trigger>
+  </AccordionPrimitive.Header>
+));
+AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
+
+const AccordionContent = React.forwardRef<
+  React.ElementRef<typeof AccordionPrimitive.Content>,
+  React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
+>(({ className, children, ...props }, ref) => (
+  <AccordionPrimitive.Content
+    ref={ref}
+    className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
+    {...props}
+  >
+    <div className={cn("pb-4 pt-0", className)}>{children}</div>
+  </AccordionPrimitive.Content>
+));
+AccordionContent.displayName = AccordionPrimitive.Content.displayName;
+
+export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
diff --git a/dashboard/app/components/ui/button.tsx b/dashboard/app/components/ui/button.tsx
new file mode 100644
index 000000000..d33c29dda
--- /dev/null
+++ b/dashboard/app/components/ui/button.tsx
@@ -0,0 +1,57 @@
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { cva, type VariantProps } from "class-variance-authority";
+
+import { cn } from "~/utils/common";
+
+const buttonVariants = cva(
+  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
+  {
+    variants: {
+      variant: {
+        default:
+          "bg-primary text-primary-foreground shadow hover:bg-primary/90",
+        destructive:
+          "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
+        outline:
+          "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
+        secondary:
+          "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
+        ghost: "hover:bg-accent hover:text-accent-foreground",
+        link: "text-primary underline-offset-4 hover:underline",
+      },
+      size: {
+        default: "h-9 px-4 py-2",
+        sm: "h-8 rounded-md px-3 text-xs",
+        lg: "h-10 rounded-md px-8",
+        icon: "h-9 w-9",
+      },
+    },
+    defaultVariants: {
+      variant: "default",
+      size: "default",
+    },
+  },
+);
+
+export interface ButtonProps
+  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
+    VariantProps<typeof buttonVariants> {
+  asChild?: boolean;
+}
+
+const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
+  ({ className, variant, size, asChild = false, ...props }, ref) => {
+    const Comp = asChild ? Slot : "button";
+    return (
+      <Comp
+        className={cn(buttonVariants({ variant, size, className }))}
+        ref={ref}
+        {...props}
+      />
+    );
+  },
+);
+Button.displayName = "Button";
+
+export { Button, buttonVariants };
diff --git a/dashboard/app/components/ui/dialog.tsx b/dashboard/app/components/ui/dialog.tsx
new file mode 100644
index 000000000..1ad536431
--- /dev/null
+++ b/dashboard/app/components/ui/dialog.tsx
@@ -0,0 +1,120 @@
+import * as React from "react";
+import * as DialogPrimitive from "@radix-ui/react-dialog";
+import { X } from "lucide-react";
+
+import { cn } from "~/utils/common";
+
+const Dialog = DialogPrimitive.Root;
+
+const DialogTrigger = DialogPrimitive.Trigger;
+
+const DialogPortal = DialogPrimitive.Portal;
+
+const DialogClose = DialogPrimitive.Close;
+
+const DialogOverlay = React.forwardRef<
+  React.ElementRef<typeof DialogPrimitive.Overlay>,
+  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
+>(({ className, ...props }, ref) => (
+  <DialogPrimitive.Overlay
+    ref={ref}
+    className={cn(
+      "fixed inset-0 z-50 bg-black/80  data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
+      className,
+    )}
+    {...props}
+  />
+));
+DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
+
+const DialogContent = React.forwardRef<
+  React.ElementRef<typeof DialogPrimitive.Content>,
+  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
+>(({ className, children, ...props }, ref) => (
+  <DialogPortal>
+    <DialogOverlay />
+    <DialogPrimitive.Content
+      ref={ref}
+      className={cn(
+        "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
+        className,
+      )}
+      {...props}
+    >
+      {children}
+      <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
+        <X className="h-4 w-4" />
+        <span className="sr-only">Close</span>
+      </DialogPrimitive.Close>
+    </DialogPrimitive.Content>
+  </DialogPortal>
+));
+DialogContent.displayName = DialogPrimitive.Content.displayName;
+
+const DialogHeader = ({
+  className,
+  ...props
+}: React.HTMLAttributes<HTMLDivElement>) => (
+  <div
+    className={cn(
+      "flex flex-col space-y-1.5 text-center sm:text-left",
+      className,
+    )}
+    {...props}
+  />
+);
+DialogHeader.displayName = "DialogHeader";
+
+const DialogFooter = ({
+  className,
+  ...props
+}: React.HTMLAttributes<HTMLDivElement>) => (
+  <div
+    className={cn(
+      "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
+      className,
+    )}
+    {...props}
+  />
+);
+DialogFooter.displayName = "DialogFooter";
+
+const DialogTitle = React.forwardRef<
+  React.ElementRef<typeof DialogPrimitive.Title>,
+  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
+>(({ className, ...props }, ref) => (
+  <DialogPrimitive.Title
+    ref={ref}
+    className={cn(
+      "text-lg font-semibold leading-none tracking-tight",
+      className,
+    )}
+    {...props}
+  />
+));
+DialogTitle.displayName = DialogPrimitive.Title.displayName;
+
+const DialogDescription = React.forwardRef<
+  React.ElementRef<typeof DialogPrimitive.Description>,
+  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
+>(({ className, ...props }, ref) => (
+  <DialogPrimitive.Description
+    ref={ref}
+    className={cn("text-sm text-muted-foreground", className)}
+    {...props}
+  />
+));
+DialogDescription.displayName = DialogPrimitive.Description.displayName;
+
+export {
+  Dialog,
+  DialogPortal,
+  DialogOverlay,
+  DialogTrigger,
+  DialogClose,
+  DialogContent,
+  DialogHeader,
+  DialogFooter,
+  DialogTitle,
+  DialogDescription,
+};
diff --git a/dashboard/app/components/ui/form.tsx b/dashboard/app/components/ui/form.tsx
new file mode 100644
index 000000000..72abaca7d
--- /dev/null
+++ b/dashboard/app/components/ui/form.tsx
@@ -0,0 +1,177 @@
+import * as React from "react";
+import * as LabelPrimitive from "@radix-ui/react-label";
+import { Slot } from "@radix-ui/react-slot";
+import {
+  Controller,
+  type ControllerProps,
+  type FieldPath,
+  type FieldValues,
+  FormProvider,
+  useFormContext,
+} from "react-hook-form";
+
+import { cn } from "~/utils/common";
+import { Label } from "~/components/ui/label";
+
+const Form = FormProvider;
+
+type FormFieldContextValue<
+  TFieldValues extends FieldValues = FieldValues,
+  TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
+> = {
+  name: TName;
+};
+
+const FormFieldContext = React.createContext<FormFieldContextValue>(
+  {} as FormFieldContextValue,
+);
+
+const FormField = <
+  TFieldValues extends FieldValues = FieldValues,
+  TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
+>({
+  ...props
+}: ControllerProps<TFieldValues, TName>) => {
+  return (
+    <FormFieldContext.Provider value={{ name: props.name }}>
+      <Controller {...props} />
+    </FormFieldContext.Provider>
+  );
+};
+
+const useFormField = () => {
+  const fieldContext = React.useContext(FormFieldContext);
+  const itemContext = React.useContext(FormItemContext);
+  const { getFieldState, formState } = useFormContext();
+
+  const fieldState = getFieldState(fieldContext.name, formState);
+
+  if (!fieldContext) {
+    throw new Error("useFormField should be used within <FormField>");
+  }
+
+  const { id } = itemContext;
+
+  return {
+    id,
+    name: fieldContext.name,
+    formItemId: `${id}-form-item`,
+    formDescriptionId: `${id}-form-item-description`,
+    formMessageId: `${id}-form-item-message`,
+    ...fieldState,
+  };
+};
+
+type FormItemContextValue = {
+  id: string;
+};
+
+const FormItemContext = React.createContext<FormItemContextValue>(
+  {} as FormItemContextValue,
+);
+
+const FormItem = React.forwardRef<
+  HTMLDivElement,
+  React.HTMLAttributes<HTMLDivElement>
+>(({ className, ...props }, ref) => {
+  const id = React.useId();
+
+  return (
+    <FormItemContext.Provider value={{ id }}>
+      <div ref={ref} className={cn("space-y-2", className)} {...props} />
+    </FormItemContext.Provider>
+  );
+});
+FormItem.displayName = "FormItem";
+
+const FormLabel = React.forwardRef<
+  React.ElementRef<typeof LabelPrimitive.Root>,
+  React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
+>(({ className, ...props }, ref) => {
+  const { error, formItemId } = useFormField();
+
+  return (
+    <Label
+      ref={ref}
+      className={cn(error && "text-destructive", className)}
+      htmlFor={formItemId}
+      {...props}
+    />
+  );
+});
+FormLabel.displayName = "FormLabel";
+
+const FormControl = React.forwardRef<
+  React.ElementRef<typeof Slot>,
+  React.ComponentPropsWithoutRef<typeof Slot>
+>(({ ...props }, ref) => {
+  const { error, formItemId, formDescriptionId, formMessageId } =
+    useFormField();
+
+  return (
+    <Slot
+      ref={ref}
+      id={formItemId}
+      aria-describedby={
+        !error
+          ? `${formDescriptionId}`
+          : `${formDescriptionId} ${formMessageId}`
+      }
+      aria-invalid={!!error}
+      {...props}
+    />
+  );
+});
+FormControl.displayName = "FormControl";
+
+const FormDescription = React.forwardRef<
+  HTMLParagraphElement,
+  React.HTMLAttributes<HTMLParagraphElement>
+>(({ className, ...props }, ref) => {
+  const { formDescriptionId } = useFormField();
+
+  return (
+    <p
+      ref={ref}
+      id={formDescriptionId}
+      className={cn("text-[0.8rem] text-muted-foreground", className)}
+      {...props}
+    />
+  );
+});
+FormDescription.displayName = "FormDescription";
+
+const FormMessage = React.forwardRef<
+  HTMLParagraphElement,
+  React.HTMLAttributes<HTMLParagraphElement>
+>(({ className, children, ...props }, ref) => {
+  const { error, formMessageId } = useFormField();
+  const body = error ? String(error?.message) : children;
+
+  if (!body) {
+    return null;
+  }
+
+  return (
+    <p
+      ref={ref}
+      id={formMessageId}
+      className={cn("text-[0.8rem] font-medium text-destructive", className)}
+      {...props}
+    >
+      {body}
+    </p>
+  );
+});
+FormMessage.displayName = "FormMessage";
+
+export {
+  useFormField,
+  Form,
+  FormItem,
+  FormLabel,
+  FormControl,
+  FormDescription,
+  FormMessage,
+  FormField,
+};
diff --git a/dashboard/app/components/ui/input.tsx b/dashboard/app/components/ui/input.tsx
new file mode 100644
index 000000000..03a5db136
--- /dev/null
+++ b/dashboard/app/components/ui/input.tsx
@@ -0,0 +1,22 @@
+import * as React from "react";
+
+import { cn } from "~/utils/common";
+
+const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
+  ({ className, type, ...props }, ref) => {
+    return (
+      <input
+        type={type}
+        className={cn(
+          "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
+          className,
+        )}
+        ref={ref}
+        {...props}
+      />
+    );
+  },
+);
+Input.displayName = "Input";
+
+export { Input };
diff --git a/dashboard/app/components/ui/label.tsx b/dashboard/app/components/ui/label.tsx
new file mode 100644
index 000000000..65f6195e1
--- /dev/null
+++ b/dashboard/app/components/ui/label.tsx
@@ -0,0 +1,24 @@
+import * as React from "react";
+import * as LabelPrimitive from "@radix-ui/react-label";
+import { cva, type VariantProps } from "class-variance-authority";
+
+import { cn } from "~/utils/common";
+
+const labelVariants = cva(
+  "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
+);
+
+const Label = React.forwardRef<
+  React.ElementRef<typeof LabelPrimitive.Root>,
+  React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
+    VariantProps<typeof labelVariants>
+>(({ className, ...props }, ref) => (
+  <LabelPrimitive.Root
+    ref={ref}
+    className={cn(labelVariants(), className)}
+    {...props}
+  />
+));
+Label.displayName = LabelPrimitive.Root.displayName;
+
+export { Label };
diff --git a/dashboard/app/components/ui/select.tsx b/dashboard/app/components/ui/select.tsx
new file mode 100644
index 000000000..eab9b2a24
--- /dev/null
+++ b/dashboard/app/components/ui/select.tsx
@@ -0,0 +1,157 @@
+import * as React from "react";
+import * as SelectPrimitive from "@radix-ui/react-select";
+import { Check, ChevronDown, ChevronUp } from "lucide-react";
+
+import { cn } from "~/utils/common";
+
+const Select = SelectPrimitive.Root;
+
+const SelectGroup = SelectPrimitive.Group;
+
+const SelectValue = SelectPrimitive.Value;
+
+const SelectTrigger = React.forwardRef<
+  React.ElementRef<typeof SelectPrimitive.Trigger>,
+  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
+>(({ className, children, ...props }, ref) => (
+  <SelectPrimitive.Trigger
+    ref={ref}
+    className={cn(
+      "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
+      className,
+    )}
+    {...props}
+  >
+    {children}
+    <SelectPrimitive.Icon asChild>
+      <ChevronDown className="h-4 w-4 opacity-50" />
+    </SelectPrimitive.Icon>
+  </SelectPrimitive.Trigger>
+));
+SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
+
+const SelectScrollUpButton = React.forwardRef<
+  React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
+  React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
+>(({ className, ...props }, ref) => (
+  <SelectPrimitive.ScrollUpButton
+    ref={ref}
+    className={cn(
+      "flex cursor-default items-center justify-center py-1",
+      className,
+    )}
+    {...props}
+  >
+    <ChevronUp className="h-4 w-4" />
+  </SelectPrimitive.ScrollUpButton>
+));
+SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
+
+const SelectScrollDownButton = React.forwardRef<
+  React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
+  React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
+>(({ className, ...props }, ref) => (
+  <SelectPrimitive.ScrollDownButton
+    ref={ref}
+    className={cn(
+      "flex cursor-default items-center justify-center py-1",
+      className,
+    )}
+    {...props}
+  >
+    <ChevronDown className="h-4 w-4" />
+  </SelectPrimitive.ScrollDownButton>
+));
+SelectScrollDownButton.displayName =
+  SelectPrimitive.ScrollDownButton.displayName;
+
+const SelectContent = React.forwardRef<
+  React.ElementRef<typeof SelectPrimitive.Content>,
+  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
+>(({ className, children, position = "popper", ...props }, ref) => (
+  <SelectPrimitive.Portal>
+    <SelectPrimitive.Content
+      ref={ref}
+      className={cn(
+        "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
+        position === "popper" &&
+          "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
+        className,
+      )}
+      position={position}
+      {...props}
+    >
+      <SelectScrollUpButton />
+      <SelectPrimitive.Viewport
+        className={cn(
+          "p-1",
+          position === "popper" &&
+            "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
+        )}
+      >
+        {children}
+      </SelectPrimitive.Viewport>
+      <SelectScrollDownButton />
+    </SelectPrimitive.Content>
+  </SelectPrimitive.Portal>
+));
+SelectContent.displayName = SelectPrimitive.Content.displayName;
+
+const SelectLabel = React.forwardRef<
+  React.ElementRef<typeof SelectPrimitive.Label>,
+  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
+>(({ className, ...props }, ref) => (
+  <SelectPrimitive.Label
+    ref={ref}
+    className={cn("px-2 py-1.5 text-sm font-semibold", className)}
+    {...props}
+  />
+));
+SelectLabel.displayName = SelectPrimitive.Label.displayName;
+
+const SelectItem = React.forwardRef<
+  React.ElementRef<typeof SelectPrimitive.Item>,
+  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
+>(({ className, children, ...props }, ref) => (
+  <SelectPrimitive.Item
+    ref={ref}
+    className={cn(
+      "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
+      className,
+    )}
+    {...props}
+  >
+    <span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
+      <SelectPrimitive.ItemIndicator>
+        <Check className="h-4 w-4" />
+      </SelectPrimitive.ItemIndicator>
+    </span>
+    <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
+  </SelectPrimitive.Item>
+));
+SelectItem.displayName = SelectPrimitive.Item.displayName;
+
+const SelectSeparator = React.forwardRef<
+  React.ElementRef<typeof SelectPrimitive.Separator>,
+  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
+>(({ className, ...props }, ref) => (
+  <SelectPrimitive.Separator
+    ref={ref}
+    className={cn("-mx-1 my-1 h-px bg-muted", className)}
+    {...props}
+  />
+));
+SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
+
+export {
+  Select,
+  SelectGroup,
+  SelectValue,
+  SelectTrigger,
+  SelectContent,
+  SelectLabel,
+  SelectItem,
+  SelectSeparator,
+  SelectScrollUpButton,
+  SelectScrollDownButton,
+};
diff --git a/dashboard/app/components/ui/skeleton.tsx b/dashboard/app/components/ui/skeleton.tsx
new file mode 100644
index 000000000..22ca6bc94
--- /dev/null
+++ b/dashboard/app/components/ui/skeleton.tsx
@@ -0,0 +1,15 @@
+import { cn } from "~/utils/common";
+
+function Skeleton({
+  className,
+  ...props
+}: React.HTMLAttributes<HTMLDivElement>) {
+  return (
+    <div
+      className={cn("animate-pulse rounded-md bg-primary/10", className)}
+      {...props}
+    />
+  );
+}
+
+export { Skeleton };
diff --git a/dashboard/app/components/ui/textarea.tsx b/dashboard/app/components/ui/textarea.tsx
new file mode 100644
index 000000000..bb77ddd82
--- /dev/null
+++ b/dashboard/app/components/ui/textarea.tsx
@@ -0,0 +1,22 @@
+import * as React from "react";
+
+import { cn } from "~/utils/common";
+
+const Textarea = React.forwardRef<
+  HTMLTextAreaElement,
+  React.ComponentProps<"textarea">
+>(({ className, ...props }, ref) => {
+  return (
+    <textarea
+      className={cn(
+        "flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
+        className,
+      )}
+      ref={ref}
+      {...props}
+    />
+  );
+});
+Textarea.displayName = "Textarea";
+
+export { Textarea };
diff --git a/dashboard/app/context/config.tsx b/dashboard/app/context/config.tsx
new file mode 100644
index 000000000..a9e9ef062
--- /dev/null
+++ b/dashboard/app/context/config.tsx
@@ -0,0 +1,34 @@
+/**
+ * Configuration Context Provider
+ *
+ * This module provides a React Context for managing the TensorZero configuration object.
+ * It exports a ConfigProvider component and a useConfig hook for accessing
+ * configuration values throughout the application.
+ *
+ * @module config
+ */
+
+import { createContext, useContext } from "react";
+import { Config } from "~/utils/config";
+
+const ConfigContext = createContext<Config | null>(null);
+
+export function useConfig() {
+  const config = useContext(ConfigContext);
+  if (!config) {
+    throw new Error("useConfig must be used within a ConfigProvider");
+  }
+  return config;
+}
+
+export function ConfigProvider({
+  children,
+  value,
+}: {
+  children: React.ReactNode;
+  value: Config;
+}) {
+  return (
+    <ConfigContext.Provider value={value}>{children}</ConfigContext.Provider>
+  );
+}
diff --git a/dashboard/app/root.tsx b/dashboard/app/root.tsx
new file mode 100644
index 000000000..9f7a32f5f
--- /dev/null
+++ b/dashboard/app/root.tsx
@@ -0,0 +1,89 @@
+import {
+  isRouteErrorResponse,
+  Links,
+  Meta,
+  Outlet,
+  Scripts,
+  ScrollRestoration,
+  useLoaderData,
+} from "react-router";
+
+import { ConfigProvider } from "./context/config";
+import type { Route } from "./+types/root";
+import "./tailwind.css";
+import { getConfig } from "./utils/config/index.server";
+
+export const links: Route.LinksFunction = () => [
+  { rel: "preconnect", href: "https://fonts.googleapis.com" },
+  {
+    rel: "preconnect",
+    href: "https://fonts.gstatic.com",
+    crossOrigin: "anonymous",
+  },
+  {
+    rel: "stylesheet",
+    href: "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap",
+  },
+];
+
+export async function loader() {
+  return await getConfig();
+}
+
+// Global Layout
+export function Layout({ children }: { children: React.ReactNode }) {
+  return (
+    <html lang="en">
+      <head>
+        <meta charSet="utf-8" />
+        <meta name="viewport" content="width=device-width, initial-scale=1" />
+        <Meta />
+        <Links />
+      </head>
+      <body>
+        {children}
+        <ScrollRestoration />
+        <Scripts />
+      </body>
+    </html>
+  );
+}
+
+export default function App() {
+  const config = useLoaderData<typeof loader>();
+  return (
+    <ConfigProvider value={config}>
+      <Outlet />
+    </ConfigProvider>
+  );
+}
+
+// Fallback Error Boundary
+export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
+  let message = "Oops!";
+  let details = "An unexpected error occurred.";
+  let stack: string | undefined;
+
+  if (isRouteErrorResponse(error)) {
+    message = error.status === 404 ? "404" : "Error";
+    details =
+      error.status === 404
+        ? "The requested page could not be found."
+        : error.statusText || details;
+  } else if (import.meta.env.DEV && error && error instanceof Error) {
+    details = error.message;
+    stack = error.stack;
+  }
+
+  return (
+    <main className="pt-16 p-4 container mx-auto">
+      <h1>{message}</h1>
+      <p>{details}</p>
+      {stack && (
+        <pre className="w-full p-4 overflow-x-auto">
+          <code>{stack}</code>
+        </pre>
+      )}
+    </main>
+  );
+}
diff --git a/dashboard/app/routes.ts b/dashboard/app/routes.ts
new file mode 100644
index 000000000..180f0ee4a
--- /dev/null
+++ b/dashboard/app/routes.ts
@@ -0,0 +1,12 @@
+import { type RouteConfig, route } from "@react-router/dev/routes";
+
+export default [
+  route(
+    "optimization/fine-tuning/:job_id?",
+    "routes/optimization/fine-tuning/route.tsx",
+  ),
+  route(
+    "api/curated_inferences/count",
+    "routes/api/curated_inferences/count.route.ts",
+  ),
+] satisfies RouteConfig;
diff --git a/dashboard/app/routes/api/curated_inferences/count.route.ts b/dashboard/app/routes/api/curated_inferences/count.route.ts
new file mode 100644
index 000000000..474dc09c7
--- /dev/null
+++ b/dashboard/app/routes/api/curated_inferences/count.route.ts
@@ -0,0 +1,64 @@
+import type { LoaderFunctionArgs } from "react-router";
+import {
+  countCuratedInferences,
+  countFeedbacksForMetric,
+  countInferencesForFunction,
+} from "~/utils/clickhouse";
+import { getConfig } from "~/utils/config/index.server";
+
+/// Count the number of inferences, feedbacks, and curated inferences for a given function and metric
+/// This is used to determine the number of inferences to display in the UI
+/// Call this route with optional function and metric parameters to get the counts
+/// If only a function is provided, it will count all inferences for that function
+/// If only a metric is provided, it will count all feedbacks for that metric
+/// If both a function and metric are provided, it will count all curated inferences for that function and metric
+export async function loader({
+  request,
+}: LoaderFunctionArgs): Promise<Response> {
+  // For type-safe fetching of counts, we would want this function to return a Promise<CountsData>
+  const url = new URL(request.url);
+  const functionName = url.searchParams.get("function");
+  const metricName = url.searchParams.get("metric");
+
+  let inferenceCount = null;
+  let feedbackCount = null;
+  let curatedInferenceCount = null;
+  const config = await getConfig();
+  if (functionName) {
+    inferenceCount = await countInferencesForFunction(
+      functionName,
+      config.functions[functionName],
+    );
+  }
+  if (metricName) {
+    feedbackCount = await countFeedbacksForMetric(
+      metricName,
+      config.metrics[metricName],
+    );
+  }
+  if (functionName && metricName) {
+    curatedInferenceCount = await countCuratedInferences(
+      functionName,
+      config.functions[functionName],
+      metricName,
+      config.metrics[metricName],
+    );
+  }
+  // For type-safe fetching of counts, we would want this return statement to be:
+  // return {
+  //   inferenceCount,
+  //   feedbackCount,
+  //   curatedInferenceCount,
+  // };
+  return Response.json({
+    inferenceCount,
+    feedbackCount,
+    curatedInferenceCount,
+  } as CountsData);
+}
+
+export interface CountsData {
+  inferenceCount: number | null;
+  feedbackCount: number | null;
+  curatedInferenceCount: number | null;
+}
diff --git a/dashboard/app/routes/optimization/fine-tuning/AdvancedParametersAccordion.tsx b/dashboard/app/routes/optimization/fine-tuning/AdvancedParametersAccordion.tsx
new file mode 100644
index 000000000..9915b4cf9
--- /dev/null
+++ b/dashboard/app/routes/optimization/fine-tuning/AdvancedParametersAccordion.tsx
@@ -0,0 +1,73 @@
+import type { Control } from "react-hook-form";
+import {
+  Accordion,
+  AccordionContent,
+  AccordionItem,
+  AccordionTrigger,
+} from "~/components/ui/accordion";
+import { FormField, FormItem, FormLabel } from "~/components/ui/form";
+import { Input } from "~/components/ui/input";
+import type { SFTFormValues } from "./types";
+
+type AdvancedParametersAccordionProps = {
+  control: Control<SFTFormValues>;
+};
+
+export function AdvancedParametersAccordion({
+  control,
+}: AdvancedParametersAccordionProps) {
+  return (
+    <Accordion type="single" collapsible className="w-full">
+      <AccordionItem value="advanced-parameters">
+        <AccordionTrigger className="hover:no-underline">
+          <div className="flex items-center gap-2">
+            <span>Advanced Parameters</span>
+          </div>
+        </AccordionTrigger>
+        <AccordionContent>
+          <div className="space-y-6 pt-3 px-3">
+            <FormField
+              control={control}
+              name="validationSplitPercent"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel>Validation Split (%)</FormLabel>
+                  <div className="grid gap-x-8 gap-y-2 md:grid-cols-2">
+                    <Input
+                      type="number"
+                      min={0}
+                      max={100}
+                      {...field}
+                      onChange={(e) => field.onChange(Number(e.target.value))}
+                    />
+                    <div></div>
+                  </div>
+                </FormItem>
+              )}
+            />
+
+            <FormField
+              control={control}
+              name="maxSamples"
+              render={({ field }) => (
+                <FormItem>
+                  <FormLabel>Max. Samples</FormLabel>
+                  <div className="grid gap-x-8 gap-y-2 md:grid-cols-2">
+                    <Input
+                      type="number"
+                      min={1}
+                      step={1}
+                      {...field}
+                      onChange={(e) => field.onChange(Number(e.target.value))}
+                    />
+                    <div></div>
+                  </div>
+                </FormItem>
+              )}
+            />
+          </div>
+        </AccordionContent>
+      </AccordionItem>
+    </Accordion>
+  );
+}
diff --git a/dashboard/app/routes/optimization/fine-tuning/FunctionSelector.tsx b/dashboard/app/routes/optimization/fine-tuning/FunctionSelector.tsx
new file mode 100644
index 000000000..ba0692aeb
--- /dev/null
+++ b/dashboard/app/routes/optimization/fine-tuning/FunctionSelector.tsx
@@ -0,0 +1,88 @@
+import type { Control } from "react-hook-form";
+import type { SFTFormValues } from "./types";
+import { Config } from "~/utils/config";
+import { FormField, FormItem, FormLabel } from "~/components/ui/form";
+import {
+  Select,
+  SelectContent,
+  SelectItem,
+  SelectTrigger,
+  SelectValue,
+} from "~/components/ui/select";
+import { Skeleton } from "~/components/ui/skeleton";
+
+type FunctionSelectorProps = {
+  control: Control<SFTFormValues>;
+  inferenceCount: number | null;
+  config: Config;
+  onFunctionChange: (value: string) => void;
+};
+
+export function FunctionSelector({
+  control,
+  inferenceCount,
+  config,
+  onFunctionChange,
+}: FunctionSelectorProps) {
+  return (
+    <FormField
+      control={control}
+      name="function"
+      render={({ field }) => (
+        <FormItem>
+          <FormLabel>Function</FormLabel>
+          <div className="grid gap-x-8 gap-y-2 md:grid-cols-2">
+            <Select
+              onValueChange={(value: string) => {
+                field.onChange(value);
+                onFunctionChange(value);
+              }}
+              value={field.value}
+            >
+              <SelectTrigger>
+                <SelectValue placeholder="Select a function" />
+              </SelectTrigger>
+              <SelectContent>
+                {Object.entries(config.functions).map(([name, fn]) => {
+                  return (
+                    <SelectItem key={name} value={name}>
+                      <div className="flex items-center justify-between w-full">
+                        <span>{name}</span>
+                        <span
+                          className={`ml-2 inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium
+                                    ${
+                                      fn.type === "chat"
+                                        ? "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300"
+                                        : "bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300"
+                                    }`}
+                        >
+                          {fn.type === "chat"
+                            ? "Chat"
+                            : fn.type === "json"
+                              ? "JSON"
+                              : "Unknown"}
+                        </span>
+                      </div>
+                    </SelectItem>
+                  );
+                })}
+              </SelectContent>
+            </Select>
+            <div className="text-sm text-muted-foreground">
+              Inferences:{" "}
+              {field.value ? (
+                <span className="font-medium">
+                  {inferenceCount ?? (
+                    <Skeleton className="inline-block h-4 w-16 align-middle" />
+                  )}
+                </span>
+              ) : (
+                <Skeleton className="inline-block h-4 w-16 align-middle" />
+              )}
+            </div>
+          </div>
+        </FormItem>
+      )}
+    />
+  );
+}
diff --git a/dashboard/app/routes/optimization/fine-tuning/MetricSelector.tsx b/dashboard/app/routes/optimization/fine-tuning/MetricSelector.tsx
new file mode 100644
index 000000000..edbcad070
--- /dev/null
+++ b/dashboard/app/routes/optimization/fine-tuning/MetricSelector.tsx
@@ -0,0 +1,137 @@
+import type { Control } from "react-hook-form";
+import type { SFTFormValues } from "./types";
+import { Config } from "~/utils/config";
+import { FormField, FormItem, FormLabel } from "~/components/ui/form";
+import {
+  Select,
+  SelectContent,
+  SelectItem,
+  SelectTrigger,
+  SelectValue,
+} from "~/components/ui/select";
+import { Skeleton } from "~/components/ui/skeleton";
+import { Input } from "~/components/ui/input";
+
+type MetricSelectorProps = {
+  control: Control<SFTFormValues>;
+  feedbackCount: number | null;
+  curatedInferenceCount: number | null;
+  config: Config;
+  onMetricChange: (value: string) => void;
+};
+
+export function MetricSelector({
+  control,
+  feedbackCount,
+  curatedInferenceCount,
+  config,
+  onMetricChange,
+}: MetricSelectorProps) {
+  return (
+    <FormField
+      control={control}
+      name="metric"
+      render={({ field }) => (
+        <FormItem>
+          <FormLabel>Metric</FormLabel>
+          <div className="grid gap-x-8 gap-y-2 md:grid-cols-2">
+            <Select
+              onValueChange={(value: string) => {
+                field.onChange(value);
+                onMetricChange(value);
+              }}
+              value={field.value}
+            >
+              <SelectTrigger>
+                <SelectValue placeholder="Select a metric" />
+              </SelectTrigger>
+              <SelectContent>
+                {Object.entries(config.metrics).map(([name, metric]) => (
+                  <SelectItem key={name} value={name}>
+                    <div className="flex items-center justify-between w-full">
+                      <span>{name}</span>
+                      <div className="ml-2 flex gap-1.5">
+                        <span
+                          className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium
+                            ${
+                              metric.type === "boolean"
+                                ? "bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-300"
+                                : "bg-cyan-100 text-cyan-800 dark:bg-cyan-900 dark:text-cyan-300"
+                            }`}
+                        >
+                          {metric.type}
+                        </span>
+                        <span
+                          className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium
+                            ${
+                              metric.optimize === "max"
+                                ? "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300"
+                                : "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300"
+                            }`}
+                        >
+                          {metric.optimize}
+                        </span>
+                        <span
+                          className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium
+                            ${
+                              metric.level === "episode"
+                                ? "bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-300"
+                                : "bg-rose-100 text-rose-800 dark:bg-rose-900 dark:text-rose-300"
+                            }`}
+                        >
+                          {metric.level}
+                        </span>
+                      </div>
+                    </div>
+                  </SelectItem>
+                ))}
+              </SelectContent>
+            </Select>
+
+            {field.value && config.metrics[field.value]?.type === "float" && (
+              <FormField
+                control={control}
+                name="threshold"
+                render={({ field: thresholdField }) => (
+                  <div className="p-4 bg-gray-100 rounded-lg">
+                    <FormLabel>Threshold</FormLabel>
+                    <Input
+                      type="number"
+                      step="0.01"
+                      min={0}
+                      max={1}
+                      {...thresholdField}
+                      className="bg-transparent border-none focus:ring-0"
+                      onChange={(e) =>
+                        thresholdField.onChange(Number(e.target.value))
+                      }
+                    />
+                  </div>
+                )}
+              />
+            )}
+
+            <div className="space-y-1 text-sm text-muted-foreground">
+              <div>
+                Feedbacks:{" "}
+                {field.value ? (
+                  <span className="font-medium">{feedbackCount}</span>
+                ) : (
+                  <Skeleton className="inline-block h-4 w-16 align-middle" />
+                )}
+              </div>
+              <div>
+                Curated Inferences:{" "}
+                {field.value ? (
+                  <span className="font-medium">{curatedInferenceCount}</span>
+                ) : (
+                  <Skeleton className="inline-block h-4 w-16 align-middle" />
+                )}
+              </div>
+            </div>
+          </div>
+        </FormItem>
+      )}
+    />
+  );
+}
diff --git a/dashboard/app/routes/optimization/fine-tuning/ModelSelector.tsx b/dashboard/app/routes/optimization/fine-tuning/ModelSelector.tsx
new file mode 100644
index 000000000..dd97531f7
--- /dev/null
+++ b/dashboard/app/routes/optimization/fine-tuning/ModelSelector.tsx
@@ -0,0 +1,156 @@
+import type { Control } from "react-hook-form";
+import { FormField, FormItem, FormLabel } from "~/components/ui/form";
+import {
+  Select,
+  SelectContent,
+  SelectItem,
+  SelectTrigger,
+  SelectValue,
+} from "~/components/ui/select";
+import type { SFTFormValues } from "./types";
+import type { ModelOption } from "./model_options";
+import type { ProviderConfigSchema } from "~/utils/config/models";
+import { z } from "zod";
+
+type ProviderType = z.infer<typeof ProviderConfigSchema>["type"];
+
+type ModelSelectorProps = {
+  control: Control<SFTFormValues>;
+  models: ModelOption[];
+};
+
+function formatProvider(provider: ProviderType): {
+  name: string;
+  className: string;
+} {
+  switch (provider) {
+    case "anthropic":
+      return {
+        name: "Anthropic",
+        className:
+          "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300",
+      };
+    case "aws_bedrock":
+      return {
+        name: "AWS Bedrock",
+        className:
+          "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300",
+      };
+    case "azure":
+      return {
+        name: "Azure",
+        className:
+          "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300",
+      };
+    case "dummy":
+      return {
+        name: "Dummy",
+        className:
+          "bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300",
+      };
+    case "fireworks":
+      return {
+        name: "Fireworks",
+        className:
+          "bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-300",
+      };
+    case "gcp_vertex_anthropic":
+      return {
+        name: "GCP Vertex AI (Anthropic)",
+        className: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300",
+      };
+    case "gcp_vertex_gemini":
+      return {
+        name: "GCP Vertex AI (Gemini)",
+        className: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300",
+      };
+    case "google_ai_studio_gemini":
+      return {
+        name: "Google AI Studio",
+        className: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300",
+      };
+    case "hyperbolic":
+      return {
+        name: "Hyperbolic",
+        className: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300",
+      };
+    case "mistral":
+      return {
+        name: "Mistral",
+        className:
+          "bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300",
+      };
+    case "openai":
+      return {
+        name: "OpenAI",
+        className:
+          "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300",
+      };
+    case "together":
+      return {
+        name: "Together",
+        className:
+          "bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-300",
+      };
+    case "vllm":
+      return {
+        name: "vLLM",
+        className:
+          "bg-cyan-100 text-cyan-800 dark:bg-cyan-900 dark:text-cyan-300",
+      };
+    case "xai":
+      return {
+        name: "xAI",
+        className:
+          "bg-pink-100 text-pink-800 dark:bg-pink-900 dark:text-pink-300",
+      };
+  }
+}
+
+export function ModelSelector({ control, models }: ModelSelectorProps) {
+  return (
+    <FormField
+      control={control}
+      name="model"
+      render={({ field }) => (
+        <FormItem>
+          <FormLabel>Model</FormLabel>
+          <div className="grid gap-x-8 gap-y-2 md:grid-cols-2">
+            <Select
+              onValueChange={(value: string) => {
+                const selectedModel = models.find(
+                  (model) => model.displayName === value,
+                );
+                if (selectedModel) {
+                  field.onChange(selectedModel);
+                }
+              }}
+              defaultValue={field.value?.displayName}
+            >
+              <SelectTrigger>
+                <SelectValue placeholder="Select a model" />
+              </SelectTrigger>
+              <SelectContent>
+                {models.map((model) => (
+                  <SelectItem key={model.displayName} value={model.displayName}>
+                    <div className="flex items-center justify-between w-full">
+                      <span>{model.displayName}</span>
+                      <span
+                        className={`ml-2 inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${
+                          formatProvider(model.provider).className
+                        }`}
+                      >
+                        {formatProvider(model.provider).name}
+                      </span>
+                    </div>
+                  </SelectItem>
+                ))}
+              </SelectContent>
+            </Select>
+            <div></div>
+          </div>
+        </FormItem>
+      )}
+    />
+  );
+}
diff --git a/dashboard/app/routes/optimization/fine-tuning/TemplateDetailsDialog.tsx b/dashboard/app/routes/optimization/fine-tuning/TemplateDetailsDialog.tsx
new file mode 100644
index 000000000..072d58d43
--- /dev/null
+++ b/dashboard/app/routes/optimization/fine-tuning/TemplateDetailsDialog.tsx
@@ -0,0 +1,108 @@
+import { Button } from "~/components/ui/button";
+import {
+  Dialog,
+  DialogContent,
+  DialogHeader,
+  DialogTitle,
+  DialogTrigger,
+} from "~/components/ui/dialog";
+import { Textarea } from "~/components/ui/textarea";
+import type { ChatCompletionConfig } from "~/utils/config/variant";
+
+interface TemplateDetailsDialogProps {
+  variant: string;
+  disabled: boolean;
+  chatCompletionVariants: Record<string, ChatCompletionConfig>;
+}
+
+export function TemplateDetailsDialog({
+  variant,
+  disabled,
+  chatCompletionVariants,
+}: TemplateDetailsDialogProps) {
+  return (
+    <div className="flex">
+      <Dialog>
+        <DialogTrigger asChild>
+          <Button variant="outline" disabled={disabled}>
+            Details
+          </Button>
+        </DialogTrigger>
+        <DialogContent className="sm:max-w-[625px] p-0 overflow-hidden">
+          <div className="max-h-[90vh] overflow-y-auto p-6 rounded-lg">
+            <DialogHeader>
+              <DialogTitle>Template Details</DialogTitle>
+            </DialogHeader>
+            <div className="grid gap-4 py-4">
+              <div className="space-y-4">
+                {variant && (
+                  <>
+                    <div className="space-y-2">
+                      <h4 className="font-medium leading-none">
+                        System Template
+                      </h4>
+                      {chatCompletionVariants[variant]?.system_template ? (
+                        <Textarea
+                          readOnly
+                          value={
+                            chatCompletionVariants[variant]?.system_template
+                              ?.content
+                          }
+                          className="h-[200px] resize-none"
+                        />
+                      ) : (
+                        <p className="text-sm text-muted-foreground">
+                          No system template.
+                        </p>
+                      )}
+                    </div>
+
+                    <div className="space-y-2">
+                      <h4 className="font-medium leading-none">
+                        User Template
+                      </h4>
+                      {chatCompletionVariants[variant]?.user_template ? (
+                        <Textarea
+                          readOnly
+                          value={
+                            chatCompletionVariants[variant]?.user_template
+                              ?.content
+                          }
+                          className="h-[200px] resize-none"
+                        />
+                      ) : (
+                        <p className="text-sm text-muted-foreground">
+                          No user template.
+                        </p>
+                      )}
+                    </div>
+                  </>
+                )}
+
+                <div className="space-y-2">
+                  <h4 className="font-medium leading-none">
+                    Assistant Template
+                  </h4>
+                  {chatCompletionVariants[variant]?.assistant_template ? (
+                    <Textarea
+                      readOnly
+                      value={
+                        chatCompletionVariants[variant]?.assistant_template
+                          ?.content
+                      }
+                      className="h-[200px] resize-none"
+                    />
+                  ) : (
+                    <p className="text-sm text-muted-foreground">
+                      No assistant template.
+                    </p>
+                  )}
+                </div>
+              </div>
+            </div>
+          </div>
+        </DialogContent>
+      </Dialog>
+    </div>
+  );
+}
diff --git a/dashboard/app/routes/optimization/fine-tuning/VariantSelector.tsx b/dashboard/app/routes/optimization/fine-tuning/VariantSelector.tsx
new file mode 100644
index 000000000..471df7a3e
--- /dev/null
+++ b/dashboard/app/routes/optimization/fine-tuning/VariantSelector.tsx
@@ -0,0 +1,65 @@
+import type { Control } from "react-hook-form";
+import type { SFTFormValues } from "./types";
+import { FormField, FormItem, FormLabel } from "~/components/ui/form";
+import {
+  Select,
+  SelectContent,
+  SelectItem,
+  SelectTrigger,
+  SelectValue,
+} from "~/components/ui/select";
+import type { ChatCompletionConfig } from "~/utils/config/variant";
+import { TemplateDetailsDialog } from "./TemplateDetailsDialog";
+
+type VariantSelectorProps = {
+  control: Control<SFTFormValues>;
+  chatCompletionVariants: Record<string, ChatCompletionConfig>;
+};
+
+export function VariantSelector({
+  control,
+  chatCompletionVariants,
+}: VariantSelectorProps) {
+  const hasVariants = Object.keys(chatCompletionVariants).length > 0;
+
+  return (
+    <FormField
+      control={control}
+      name="variant"
+      render={({ field }) => (
+        <FormItem>
+          <FormLabel>Prompt</FormLabel>
+          <div className="grid gap-x-8 gap-y-2 md:grid-cols-2">
+            <Select
+              onValueChange={field.onChange}
+              defaultValue={field.value}
+              disabled={!hasVariants}
+            >
+              <SelectTrigger>
+                <SelectValue
+                  placeholder={
+                    hasVariants
+                      ? "Select a variant name"
+                      : "No variants available"
+                  }
+                />
+              </SelectTrigger>
+              <SelectContent>
+                {Object.entries(chatCompletionVariants).map(([name]) => (
+                  <SelectItem key={name} value={name}>
+                    <span>{name}</span>
+                  </SelectItem>
+                ))}
+              </SelectContent>
+            </Select>
+            <TemplateDetailsDialog
+              variant={field.value}
+              disabled={!field.value}
+              chatCompletionVariants={chatCompletionVariants}
+            />
+          </div>
+        </FormItem>
+      )}
+    />
+  );
+}
diff --git a/dashboard/app/routes/optimization/fine-tuning/model_options.ts b/dashboard/app/routes/optimization/fine-tuning/model_options.ts
new file mode 100644
index 000000000..4207bea88
--- /dev/null
+++ b/dashboard/app/routes/optimization/fine-tuning/model_options.ts
@@ -0,0 +1,22 @@
+import { z } from "zod";
+
+export const ModelOptionSchema = z.object({
+  displayName: z.string().nonempty("Model name is required"),
+  name: z.string().nonempty("Model name is required"),
+  provider: z.enum(["openai", "fireworks", "mistral"]),
+});
+
+export type ModelOption = z.infer<typeof ModelOptionSchema>;
+
+export const models: ModelOption[] = [
+  {
+    displayName: "gpt-4o-mini-2024-07-18",
+    name: "gpt-4o-mini-2024-07-18",
+    provider: "openai",
+  },
+  {
+    displayName: "llama-3.1-8b-instruct",
+    name: "accounts/fireworks/models/llama-v3p1-8b-instruct",
+    provider: "fireworks",
+  },
+];
diff --git a/dashboard/app/routes/optimization/fine-tuning/route.tsx b/dashboard/app/routes/optimization/fine-tuning/route.tsx
new file mode 100644
index 000000000..62c8c6573
--- /dev/null
+++ b/dashboard/app/routes/optimization/fine-tuning/route.tsx
@@ -0,0 +1,338 @@
+import { useFetcher, type MetaFunction } from "react-router";
+import { useEffect, useState } from "react";
+import {
+  type SFTFormValues,
+  SFTFormValuesSchema,
+  SFTFormValuesResolver,
+} from "./types";
+import { v7 as uuid } from "uuid";
+import type { SFTJob } from "~/utils/fine_tuning/common";
+import { models } from "./model_options";
+import { useRevalidator } from "react-router";
+import { useForm } from "react-hook-form";
+import { redirect } from "react-router";
+import { launch_sft_job } from "~/utils/fine_tuning/client";
+import type { ChatCompletionConfig } from "~/utils/config/variant";
+import { useConfig } from "~/context/config";
+import { FunctionSelector } from "./FunctionSelector";
+import { MetricSelector } from "./MetricSelector";
+import { VariantSelector } from "./VariantSelector";
+import {
+  dump_model_config,
+  get_fine_tuned_model_config,
+} from "~/utils/config/models";
+import { ModelSelector } from "./ModelSelector";
+import { AdvancedParametersAccordion } from "./AdvancedParametersAccordion";
+import { Button } from "~/components/ui/button";
+import { Textarea } from "~/components/ui/textarea";
+import { Form } from "~/components/ui/form";
+import type { Route } from "./+types/route";
+// The following import would be needed for type-safe fetching of counts
+// import type { Route as CuratedInferencesCount } from "../../api/curated_inferences/+types/count.route";
+import type { CountsData } from "../../api/curated_inferences/count.route";
+import type { Config } from "~/utils/config";
+
+export const meta: MetaFunction = () => {
+  return [
+    { title: "TensorZero Fine-Tuning Dashboard" },
+    { name: "description", content: "Fine-Tuning Optimization Dashboard" },
+  ];
+};
+
+// Mutable store mapping job IDs to their info
+export const jobStore: { [jobId: string]: SFTJob } = {};
+
+// If there is a job_id in the URL, grab it from the job store and pull it.
+export async function loader({ params }: Route.LoaderArgs) {
+  const job_id = params.job_id;
+
+  if (!job_id) {
+    return { status: "idle" };
+  }
+
+  const storedJob = jobStore[job_id];
+  if (!storedJob) {
+    throw new Response(JSON.stringify({ error: "Job not found" }), {
+      status: 404,
+    });
+  }
+  if (storedJob.status() === "completed" || storedJob.status() === "error") {
+    return {
+      status: storedJob.status(),
+      result: storedJob.result(),
+      modelProvider: storedJob.provider(),
+    };
+  }
+
+  try {
+    // Poll for updates
+    const updatedJob = await storedJob.poll();
+    jobStore[job_id] = updatedJob;
+
+    const result = updatedJob.result();
+    const status = updatedJob.status();
+    const modelProvider = updatedJob.provider();
+
+    return {
+      status,
+      result,
+      modelProvider,
+    };
+  } catch (error) {
+    return {
+      status: "error",
+      error: error instanceof Error ? error.message : "Unknown error",
+    };
+  }
+}
+
+// The action actually launches the fine-tuning job.
+export async function action({ request }: Route.ActionArgs) {
+  const formData = await request.formData();
+  const serializedFormData = formData.get("data");
+  if (!serializedFormData || typeof serializedFormData !== "string") {
+    throw new Error("Form data must be provided");
+  }
+
+  const jsonData = JSON.parse(serializedFormData);
+  const validatedData = SFTFormValuesSchema.parse(jsonData);
+
+  const job = await launch_sft_job(validatedData);
+  jobStore[validatedData.jobId] = job;
+
+  return redirect(`/optimization/fine-tuning/${validatedData.jobId}`);
+}
+
+// Renders the fine-tuning form and status info.
+export default function FineTuning({ loaderData }: Route.ComponentProps) {
+  const config = useConfig();
+  const { status, result, modelProvider } = loaderData;
+  const revalidator = useRevalidator();
+
+  // If running, periodically poll for updates on the job
+  useEffect(() => {
+    if (status === "running") {
+      setSubmissionPhase("pending");
+      const interval = setInterval(() => {
+        revalidator.revalidate();
+      }, 10000);
+      return () => clearInterval(interval);
+    }
+  }, [status, revalidator]);
+
+  const [submissionPhase, setSubmissionPhase] = useState<
+    "idle" | "submitting" | "pending" | "complete"
+  >("idle");
+  const finalResult = result
+    ? dump_model_config(get_fine_tuned_model_config(result, modelProvider))
+    : null;
+  if (finalResult && submissionPhase !== "complete") {
+    setSubmissionPhase("complete");
+  }
+
+  return (
+    <div className="min-h-screen bg-gray-50">
+      <main className="p-4">
+        <h2 className="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight first:mt-0">
+          Fine-Tuning
+        </h2>
+        {status === "idle" && (
+          <FineTuningForm
+            config={config}
+            submissionPhase={submissionPhase}
+            setSubmissionPhase={setSubmissionPhase}
+          />
+        )}
+
+        {status !== "idle" && (
+          <div className="p-4 bg-gray-100 rounded-lg mt-4">
+            <div className="mb-2 font-medium">
+              Loader Data (Last Updated: {new Date().toLocaleTimeString()})
+            </div>
+            <Textarea
+              value={JSON.stringify(loaderData, null, 2)}
+              className="w-full h-48 resize-none bg-transparent border-none focus:ring-0"
+              readOnly
+            />
+          </div>
+        )}
+
+        {finalResult && (
+          <div className="p-4 bg-gray-100 rounded-lg mt-4">
+            <div className="mb-2 font-medium">Configuration</div>
+            <Textarea
+              value={finalResult}
+              className="w-full h-48 resize-none bg-transparent border-none focus:ring-0"
+              readOnly
+            />
+          </div>
+        )}
+      </main>
+    </div>
+  );
+}
+
+function FineTuningForm({
+  config,
+  submissionPhase,
+  setSubmissionPhase,
+}: {
+  config: Config;
+  submissionPhase: "idle" | "submitting" | "pending" | "complete";
+  setSubmissionPhase: (
+    phase: "idle" | "submitting" | "pending" | "complete",
+  ) => void;
+}) {
+  const form = useForm<SFTFormValues>({
+    defaultValues: {
+      function: "",
+      metric: "",
+      validationSplitPercent: 20,
+      maxSamples: 100000,
+      threshold: 0.5,
+      jobId: uuid(),
+    },
+    resolver: SFTFormValuesResolver,
+    mode: "onChange",
+  });
+
+  const {
+    handleSubmit,
+    formState: { errors },
+  } = form;
+
+  const fetcher = useFetcher();
+
+  const [counts, setCounts] = useState<CountsData>({
+    inferenceCount: null,
+    feedbackCount: null,
+    curatedInferenceCount: null,
+  });
+
+  const fetchCounts = async (functionName?: string, metricName?: string) => {
+    const params = new URLSearchParams();
+    if (functionName) params.set("function", functionName);
+    if (metricName) params.set("metric", metricName);
+
+    const response = await fetch(`/api/curated_inferences/count?${params}`);
+    const loaderData = (await response.json()) as CountsData;
+    setCounts(loaderData);
+    /* Type-safe way to do this (pending [this issue](https://github.com/remix-run/react-router/issues/12635))
+     const response = await fetch(`/api/curated_inferences/count?${params}`);
+    const { loaderData } =
+      (await response.json()) as CuratedInferencesCount.ComponentProps;
+    setCounts(loaderData as CountsData);
+    */
+  };
+
+  const handleFunctionChange = (value: string) => {
+    fetchCounts(value, form.getValues("metric") || undefined);
+  };
+
+  const handleMetricChange = (value: string) => {
+    fetchCounts(form.getValues("function") || undefined, value);
+  };
+
+  const getChatCompletionVariantsForFunction = (): Record<
+    string,
+    ChatCompletionConfig
+  > => {
+    const selectedFunction = form.getValues("function");
+
+    if (!selectedFunction || !config?.functions[selectedFunction]) {
+      return {};
+    }
+
+    const functionConfig = config.functions[selectedFunction];
+    return Object.fromEntries(
+      Object.entries(functionConfig.variants || {}).filter(
+        (entry): entry is [string, ChatCompletionConfig] =>
+          entry[1].type === "chat_completion",
+      ),
+    );
+  };
+
+  useEffect(() => {
+    if (counts.inferenceCount !== null) {
+      form.setValue("maxSamples", Math.min(100000, counts.inferenceCount));
+    }
+  }, [counts.inferenceCount, form]);
+
+  function getButtonText() {
+    switch (submissionPhase) {
+      case "submitting":
+        return "Submitting...";
+      case "pending":
+        return "Pending...";
+      case "complete":
+        return "Complete";
+      default:
+        return "Start Fine-tuning Job";
+    }
+  }
+
+  const onSubmit = async (data: SFTFormValues) => {
+    try {
+      const formData = {
+        ...data,
+      };
+
+      const submitData = new FormData();
+      submitData.append("data", JSON.stringify(formData));
+
+      fetcher.submit(submitData, { method: "POST" });
+      setSubmissionPhase("submitting");
+    } catch (error) {
+      console.error("Submission error:", error);
+    }
+  };
+
+  return (
+    <div className="mt-8">
+      <Form {...form}>
+        <form
+          onSubmit={(e) => {
+            handleSubmit(onSubmit)(e);
+          }}
+          className="space-y-6"
+        >
+          <div className="space-y-6">
+            <FunctionSelector
+              control={form.control}
+              inferenceCount={counts.inferenceCount}
+              config={config}
+              onFunctionChange={handleFunctionChange}
+            />
+            {errors.function && (
+              <p className="text-red-500 text-sm">{errors.function.message}</p>
+            )}
+
+            <MetricSelector
+              control={form.control}
+              feedbackCount={counts.feedbackCount}
+              curatedInferenceCount={counts.curatedInferenceCount}
+              config={config}
+              onMetricChange={handleMetricChange}
+            />
+            {errors.metric && (
+              <p className="text-red-500 text-sm">{errors.metric.message}</p>
+            )}
+
+            <VariantSelector
+              control={form.control}
+              chatCompletionVariants={getChatCompletionVariantsForFunction()}
+            />
+
+            <ModelSelector control={form.control} models={models} />
+
+            <AdvancedParametersAccordion control={form.control} />
+          </div>
+
+          <Button type="submit" disabled={submissionPhase !== "idle"}>
+            {getButtonText()}
+          </Button>
+        </form>
+      </Form>
+    </div>
+  );
+}
diff --git a/dashboard/app/routes/optimization/fine-tuning/types.ts b/dashboard/app/routes/optimization/fine-tuning/types.ts
new file mode 100644
index 000000000..1166c3d7c
--- /dev/null
+++ b/dashboard/app/routes/optimization/fine-tuning/types.ts
@@ -0,0 +1,23 @@
+import { z } from "zod";
+import { ModelOptionSchema } from "./model_options";
+import { zodResolver } from "@hookform/resolvers/zod";
+
+export const SFTFormValuesSchema = z.object({
+  function: z.string().nonempty("Function is required"),
+  metric: z.string().nonempty("Metric is required"),
+  model: ModelOptionSchema,
+  variant: z.string().nonempty(),
+  validationSplitPercent: z
+    .number()
+    .min(0, "Validation split percent must be greater than 0")
+    .max(100, "Validation split percent must be less than 100"),
+  maxSamples: z
+    .number()
+    .min(10, "Max samples must be greater than 10")
+    .optional(),
+  threshold: z.number().optional(),
+  jobId: z.string().nonempty("Job ID is required"),
+});
+
+export type SFTFormValues = z.infer<typeof SFTFormValuesSchema>;
+export const SFTFormValuesResolver = zodResolver(SFTFormValuesSchema);
diff --git a/dashboard/app/tailwind.css b/dashboard/app/tailwind.css
new file mode 100644
index 000000000..405b37a96
--- /dev/null
+++ b/dashboard/app/tailwind.css
@@ -0,0 +1,77 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+html,
+body {
+  @apply bg-white dark:bg-gray-950;
+
+  @media (prefers-color-scheme: dark) {
+    color-scheme: dark;
+  }
+}
+
+@layer base {
+  :root {
+    --background: 0 0% 100%;
+    --foreground: 222.2 84% 4.9%;
+    --card: 0 0% 100%;
+    --card-foreground: 222.2 84% 4.9%;
+    --popover: 0 0% 100%;
+    --popover-foreground: 222.2 84% 4.9%;
+    --primary: 222.2 47.4% 11.2%;
+    --primary-foreground: 210 40% 98%;
+    --secondary: 210 40% 96.1%;
+    --secondary-foreground: 222.2 47.4% 11.2%;
+    --muted: 210 40% 96.1%;
+    --muted-foreground: 215.4 16.3% 46.9%;
+    --accent: 210 40% 96.1%;
+    --accent-foreground: 222.2 47.4% 11.2%;
+    --destructive: 0 84.2% 60.2%;
+    --destructive-foreground: 210 40% 98%;
+    --border: 214.3 31.8% 91.4%;
+    --input: 214.3 31.8% 91.4%;
+    --ring: 222.2 84% 4.9%;
+    --chart-1: 12 76% 61%;
+    --chart-2: 173 58% 39%;
+    --chart-3: 197 37% 24%;
+    --chart-4: 43 74% 66%;
+    --chart-5: 27 87% 67%;
+    --radius: 0.5rem;
+  }
+  .dark {
+    --background: 222.2 84% 4.9%;
+    --foreground: 210 40% 98%;
+    --card: 222.2 84% 4.9%;
+    --card-foreground: 210 40% 98%;
+    --popover: 222.2 84% 4.9%;
+    --popover-foreground: 210 40% 98%;
+    --primary: 210 40% 98%;
+    --primary-foreground: 222.2 47.4% 11.2%;
+    --secondary: 217.2 32.6% 17.5%;
+    --secondary-foreground: 210 40% 98%;
+    --muted: 217.2 32.6% 17.5%;
+    --muted-foreground: 215 20.2% 65.1%;
+    --accent: 217.2 32.6% 17.5%;
+    --accent-foreground: 210 40% 98%;
+    --destructive: 0 62.8% 30.6%;
+    --destructive-foreground: 210 40% 98%;
+    --border: 217.2 32.6% 17.5%;
+    --input: 217.2 32.6% 17.5%;
+    --ring: 212.7 26.8% 83.9%;
+    --chart-1: 220 70% 50%;
+    --chart-2: 160 60% 45%;
+    --chart-3: 30 80% 55%;
+    --chart-4: 280 65% 60%;
+    --chart-5: 340 75% 55%;
+  }
+}
+
+@layer base {
+  * {
+    @apply border-border;
+  }
+  body {
+    @apply bg-background text-foreground;
+  }
+}
diff --git a/dashboard/app/utils/.gitignore b/dashboard/app/utils/.gitignore
new file mode 100644
index 000000000..5fff1d9c1
--- /dev/null
+++ b/dashboard/app/utils/.gitignore
@@ -0,0 +1,1 @@
+pkg
diff --git a/dashboard/app/utils/clickhouse.ts b/dashboard/app/utils/clickhouse.ts
new file mode 100644
index 000000000..c5c927ead
--- /dev/null
+++ b/dashboard/app/utils/clickhouse.ts
@@ -0,0 +1,397 @@
+import { createClient } from "@clickhouse/client";
+import { z } from "zod";
+import { type FunctionConfig } from "./config/function";
+import { type MetricConfig } from "./config/metric";
+
+export const clickhouseClient = createClient({
+  url: process.env.CLICKHOUSE_URL,
+});
+
+export async function checkClickhouseConnection(): Promise<boolean> {
+  try {
+    const result = await clickhouseClient.ping();
+    return result.success;
+  } catch {
+    return false;
+  }
+}
+
+export const roleSchema = z.enum(["user", "assistant"]);
+export type Role = z.infer<typeof roleSchema>;
+
+export const textInputMessageContentSchema = z.object({
+  type: z.literal("text"),
+  value: z.any(), // Value type from Rust maps to any in TS
+});
+export type textInputMessageContent = z.infer<
+  typeof textInputMessageContentSchema
+>;
+
+export const toolCallSchema = z
+  .object({
+    name: z.string(),
+    arguments: z.string(),
+    id: z.string(),
+  })
+  .strict();
+export type toolCall = z.infer<typeof toolCallSchema>;
+
+export const toolCallInputMessageContentSchema = z
+  .object({
+    type: z.literal("tool_call"),
+    ...toolCallSchema.shape,
+  })
+  .strict();
+export type toolCallInputMessageContent = z.infer<
+  typeof toolCallInputMessageContentSchema
+>;
+
+export const toolResultSchema = z
+  .object({
+    name: z.string(),
+    result: z.string(),
+    id: z.string(),
+  })
+  .strict();
+
+export const toolResultInputMessageContentSchema = z
+  .object({
+    type: z.literal("tool_result"),
+    ...toolResultSchema.shape,
+  })
+  .strict();
+export type toolResultInputMessageContent = z.infer<
+  typeof toolResultInputMessageContentSchema
+>;
+
+export const inputMessageContentSchema = z.discriminatedUnion("type", [
+  textInputMessageContentSchema,
+  toolCallInputMessageContentSchema,
+  toolResultInputMessageContentSchema,
+]);
+export type InputMessageContent = z.infer<typeof inputMessageContentSchema>;
+
+export const inputMessageSchema = z
+  .object({
+    role: roleSchema,
+    content: z.array(inputMessageContentSchema),
+  })
+  .strict();
+export type InputMessage = z.infer<typeof inputMessageSchema>;
+
+export const inputSchema = z
+  .object({
+    system: z.any().optional(), // Value type from Rust maps to any in TS
+    messages: z.array(inputMessageSchema).default([]),
+  })
+  .strict();
+export type Input = z.infer<typeof inputSchema>;
+
+export const jsonInferenceOutputSchema = z.object({
+  raw: z.string(),
+  parsed: z.any().optional(),
+});
+
+export type JsonInferenceOutput = z.infer<typeof jsonInferenceOutputSchema>;
+
+export const toolCallOutputSchema = z
+  .object({
+    type: z.literal("tool_call"),
+    arguments: z.any().optional(), // Value type from Rust maps to any in TS
+    id: z.string(),
+    name: z.string().optional(),
+    raw_arguments: z.string(),
+    raw_name: z.string(),
+  })
+  .strict();
+
+export type ToolCallOutput = z.infer<typeof toolCallOutputSchema>;
+export const textSchema = z
+  .object({
+    type: z.literal("text"),
+    text: z.string(),
+  })
+  .strict();
+
+export type Text = z.infer<typeof textSchema>;
+
+export const contentBlockOutputSchema = z.discriminatedUnion("type", [
+  textSchema,
+  toolCallOutputSchema,
+]);
+
+export type ContentBlockOutput = z.infer<typeof contentBlockOutputSchema>;
+
+export const inferenceRowSchema = z
+  .object({
+    variant_name: z.string(),
+    input: z.string(),
+    output: z.string(),
+    episode_id: z.string(),
+  })
+  .strict();
+export type InferenceRow = z.infer<typeof inferenceRowSchema>;
+
+export const parsedChatInferenceRowSchema = inferenceRowSchema
+  .omit({
+    input: true,
+    output: true,
+  })
+  .extend({
+    input: inputSchema,
+    output: z.array(contentBlockOutputSchema),
+  })
+  .strict();
+export type ParsedChatInferenceRow = z.infer<
+  typeof parsedChatInferenceRowSchema
+>;
+
+export const parsedJsonInferenceRowSchema = inferenceRowSchema
+  .omit({
+    input: true,
+    output: true,
+  })
+  .extend({
+    input: inputSchema,
+    output: jsonInferenceOutputSchema,
+  })
+  .strict();
+export type ParsedJsonInferenceRow = z.infer<
+  typeof parsedJsonInferenceRowSchema
+>;
+
+export type ParsedInferenceRow =
+  | ParsedChatInferenceRow
+  | ParsedJsonInferenceRow;
+
+export function parseInferenceRows(
+  rows: InferenceRow[],
+  tableName: string,
+): ParsedChatInferenceRow[] | ParsedJsonInferenceRow[] {
+  if (tableName === "ChatInference") {
+    return rows.map((row) => ({
+      ...row,
+      input: inputSchema.parse(JSON.parse(row.input)),
+      output: z.array(contentBlockOutputSchema).parse(JSON.parse(row.output)),
+    })) as ParsedChatInferenceRow[];
+  } else {
+    return rows.map((row) => ({
+      ...row,
+      input: inputSchema.parse(JSON.parse(row.input)),
+      output: jsonInferenceOutputSchema.parse(JSON.parse(row.output)),
+    })) as ParsedJsonInferenceRow[];
+  }
+}
+
+export const InferenceTableName = {
+  CHAT: "ChatInference",
+  JSON: "JsonInference",
+} as const;
+export type InferenceTableName =
+  (typeof InferenceTableName)[keyof typeof InferenceTableName];
+
+export const InferenceJoinKey = {
+  ID: "id",
+  EPISODE_ID: "episode_id",
+} as const;
+export type InferenceJoinKey =
+  (typeof InferenceJoinKey)[keyof typeof InferenceJoinKey];
+
+function getInferenceTableName(
+  function_config: FunctionConfig,
+): InferenceTableName {
+  switch (function_config.type) {
+    case "chat":
+      return InferenceTableName.CHAT;
+    case "json":
+      return InferenceTableName.JSON;
+  }
+}
+
+function getMetricTableName(metric_config: MetricConfig): string {
+  switch (metric_config.type) {
+    case "boolean":
+      return "BooleanMetricFeedback";
+    case "float":
+      return "FloatMetricFeedback";
+    case "comment":
+      return "CommentFeedback";
+    case "demonstration":
+      return "DemonstrationFeedback";
+  }
+}
+
+function getInferenceJoinKey(metric_config: MetricConfig): InferenceJoinKey {
+  switch (metric_config.level) {
+    case "inference":
+      return InferenceJoinKey.ID;
+    case "episode":
+      return InferenceJoinKey.EPISODE_ID;
+  }
+}
+
+export async function countInferencesForFunction(
+  function_name: string,
+  function_config: FunctionConfig,
+): Promise<number> {
+  const inference_table_name = getInferenceTableName(function_config);
+  const query = `SELECT COUNT() AS count FROM ${inference_table_name} WHERE function_name = {function_name:String}`;
+  const resultSet = await clickhouseClient.query({
+    query,
+    format: "JSONEachRow",
+    query_params: { function_name },
+  });
+  const rows = await resultSet.json<{ count: string }>();
+  return Number(rows[0].count);
+}
+
+export async function countFeedbacksForMetric(
+  metric_name: string,
+  metric_config: MetricConfig,
+): Promise<number> {
+  const metric_table_name = getMetricTableName(metric_config);
+  const query = `SELECT COUNT() AS count FROM ${metric_table_name} WHERE metric_name = {metric_name:String}`;
+  const resultSet = await clickhouseClient.query({
+    query,
+    format: "JSONEachRow",
+    query_params: { metric_name },
+  });
+  const rows = await resultSet.json<{ count: string }>();
+  return Number(rows[0].count);
+}
+
+export async function getCuratedInferences(
+  function_name: string,
+  function_config: FunctionConfig,
+  metric_name: string,
+  metric_config: MetricConfig,
+  max_samples?: number,
+) {
+  const inference_table_name = getInferenceTableName(function_config);
+  const inference_join_key = getInferenceJoinKey(metric_config);
+
+  switch (metric_config.type) {
+    case "boolean":
+      return queryGoodBooleanMetricData(
+        function_name,
+        metric_name,
+        inference_table_name,
+        inference_join_key,
+        metric_config.optimize === "max",
+        max_samples,
+      );
+    default:
+      throw new Error(`Unsupported metric type: ${metric_config.type}`);
+  }
+}
+
+export async function countCuratedInferences(
+  function_name: string,
+  function_config: FunctionConfig,
+  metric_name: string,
+  metric_config: MetricConfig,
+) {
+  const inference_table_name = getInferenceTableName(function_config);
+  const inference_join_key = getInferenceJoinKey(metric_config);
+
+  switch (metric_config.type) {
+    case "boolean":
+      return countGoodBooleanMetricData(
+        function_name,
+        metric_name,
+        inference_table_name,
+        inference_join_key,
+        metric_config.optimize === "max",
+      );
+    default:
+      throw new Error(`Unsupported metric type: ${metric_config.type}`);
+  }
+}
+
+export async function queryGoodBooleanMetricData(
+  function_name: string,
+  metric_name: string,
+  inference_table_name: InferenceTableName,
+  inference_join_key: InferenceJoinKey,
+  maximize: boolean,
+  max_samples: number | undefined,
+): Promise<ParsedInferenceRow[]> {
+  const comparison_operator = maximize ? "= 1" : "= 0"; // Changed from "IS TRUE"/"IS FALSE"
+  const limitClause = max_samples ? `LIMIT ${max_samples}` : "";
+
+  const query = `
+    SELECT
+      i.variant_name,
+      i.input,
+      i.output,
+      i.episode_id
+    FROM
+      ${inference_table_name} i
+    JOIN
+      (SELECT
+        target_id,
+        value,
+        ROW_NUMBER() OVER (PARTITION BY target_id ORDER BY timestamp DESC) as rn
+      FROM
+        BooleanMetricFeedback
+      WHERE
+        metric_name = {metric_name:String}
+        AND value ${comparison_operator}
+      ) f ON i.${inference_join_key} = f.target_id and f.rn = 1
+    WHERE
+      i.function_name = {function_name:String}
+    ${limitClause}
+  `;
+
+  const resultSet = await clickhouseClient.query({
+    query,
+    format: "JSONEachRow",
+    query_params: {
+      metric_name,
+      function_name,
+    },
+  });
+  const rows = await resultSet.json<InferenceRow>();
+  return parseInferenceRows(rows, inference_table_name);
+}
+
+export async function countGoodBooleanMetricData(
+  function_name: string,
+  metric_name: string,
+  inference_table_name: InferenceTableName,
+  inference_join_key: InferenceJoinKey,
+  maximize: boolean,
+): Promise<number> {
+  const comparison_operator = maximize ? "= 1" : "= 0"; // Changed from "IS TRUE"/"IS FALSE"
+
+  const query = `
+    SELECT
+      COUNT(*) as count
+    FROM
+      ${inference_table_name} i
+    JOIN
+      (SELECT
+        target_id,
+        value,
+        ROW_NUMBER() OVER (PARTITION BY target_id ORDER BY timestamp DESC) as rn
+      FROM
+        BooleanMetricFeedback
+      WHERE
+        metric_name = {metric_name:String}
+        AND value ${comparison_operator}
+      ) f ON i.${inference_join_key} = f.target_id and f.rn = 1
+    WHERE
+      i.function_name = {function_name:String}
+  `;
+
+  const resultSet = await clickhouseClient.query({
+    query,
+    format: "JSONEachRow",
+    query_params: {
+      metric_name,
+      function_name,
+    },
+  });
+  const rows = await resultSet.json<{ count: number }>();
+  return rows[0].count;
+}
diff --git a/dashboard/app/utils/common.ts b/dashboard/app/utils/common.ts
new file mode 100644
index 000000000..a5ef19350
--- /dev/null
+++ b/dashboard/app/utils/common.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+export function cn(...inputs: ClassValue[]) {
+  return twMerge(clsx(inputs));
+}
diff --git a/dashboard/app/utils/config/function.server.ts b/dashboard/app/utils/config/function.server.ts
new file mode 100644
index 000000000..30a5923d7
--- /dev/null
+++ b/dashboard/app/utils/config/function.server.ts
@@ -0,0 +1,53 @@
+import { z } from "zod";
+import type { FunctionConfig } from "./function";
+import { RawVariantConfigSchema } from "./variant.server";
+import type { VariantConfig } from "./variant";
+
+// Common schema for both Chat and Json variants
+const rawBaseConfigSchema = z.object({
+  variants: z.record(z.string(), RawVariantConfigSchema),
+  system_schema: z.string().optional(),
+  user_schema: z.string().optional(),
+  assistant_schema: z.string().optional(),
+});
+
+// Schema for FunctionConfigChat
+export const RawFunctionConfigChatSchema = rawBaseConfigSchema.extend({
+  type: z.literal("chat"),
+  tools: z.array(z.string()).default([]),
+  tool_choice: z.enum(["none", "auto", "any"]).default("none"), // Assuming these are the ToolChoice variants
+  parallel_tool_calls: z.boolean().default(false),
+});
+
+// Schema for FunctionConfigJson
+export const RawFunctionConfigJsonSchema = rawBaseConfigSchema.extend({
+  type: z.literal("json"),
+  output_schema: z.string().optional(),
+});
+
+// Combined FunctionConfig schema
+export const RawFunctionConfigSchema = z
+  .discriminatedUnion("type", [
+    RawFunctionConfigChatSchema,
+    RawFunctionConfigJsonSchema,
+  ])
+  .transform((raw) => {
+    const config = { ...raw };
+    return {
+      ...config,
+      load: async function (config_path: string): Promise<FunctionConfig> {
+        const loadedVariants: Record<string, VariantConfig> = {};
+        for (const [key, variant] of Object.entries(config.variants)) {
+          loadedVariants[key] = await variant.load(config_path);
+        }
+        return {
+          ...config,
+          variants: loadedVariants,
+        };
+      },
+    };
+  });
+
+export type RawFunctionConfigChat = z.infer<typeof RawFunctionConfigChatSchema>;
+export type RawFunctionConfigJson = z.infer<typeof RawFunctionConfigJsonSchema>;
+export type RawFunctionConfig = z.infer<typeof RawFunctionConfigSchema>;
diff --git a/dashboard/app/utils/config/function.ts b/dashboard/app/utils/config/function.ts
new file mode 100644
index 000000000..8803f51e5
--- /dev/null
+++ b/dashboard/app/utils/config/function.ts
@@ -0,0 +1,34 @@
+import { z } from "zod";
+import { VariantConfigSchema } from "./variant";
+
+// Common schema for both Chat and Json variants
+const baseConfigSchema = z.object({
+  variants: z.record(z.string(), VariantConfigSchema),
+  system_schema: z.string().optional(),
+  user_schema: z.string().optional(),
+  assistant_schema: z.string().optional(),
+});
+
+// Schema for FunctionConfigChat
+export const FunctionConfigChatSchema = baseConfigSchema.extend({
+  type: z.literal("chat"),
+  tools: z.array(z.string()).default([]),
+  tool_choice: z.enum(["none", "auto", "any"]).default("none"), // Assuming these are the ToolChoice variants
+  parallel_tool_calls: z.boolean().default(false),
+});
+
+// Schema for FunctionConfigJson
+export const FunctionConfigJsonSchema = baseConfigSchema.extend({
+  type: z.literal("json"),
+  output_schema: z.string().optional(),
+});
+
+// Combined FunctionConfig schema
+export const FunctionConfigSchema = z.discriminatedUnion("type", [
+  FunctionConfigChatSchema,
+  FunctionConfigJsonSchema,
+]);
+
+export type FunctionConfigChat = z.infer<typeof FunctionConfigChatSchema>;
+export type FunctionConfigJson = z.infer<typeof FunctionConfigJsonSchema>;
+export type FunctionConfig = z.infer<typeof FunctionConfigSchema>;
diff --git a/dashboard/app/utils/config/index.server.ts b/dashboard/app/utils/config/index.server.ts
new file mode 100644
index 000000000..0e402af2f
--- /dev/null
+++ b/dashboard/app/utils/config/index.server.ts
@@ -0,0 +1,66 @@
+import { parse } from "smol-toml";
+import { promises as fs } from "fs";
+import { Config, GatewayConfig } from ".";
+import { MetricConfigSchema } from "./metric";
+import { RawFunctionConfigSchema } from "./function.server";
+import { z } from "zod";
+import { EmbeddingModelConfigSchema, ModelConfigSchema } from "./models";
+import { ToolConfigSchema } from "./tool";
+import type { FunctionConfig } from "./function";
+
+const CONFIG_PATH =
+  process.env.CONFIG_PATH || "fixtures/config/tensorzero.toml";
+
+export async function loadConfig(config_path: string): Promise<Config> {
+  const tomlContent = await fs.readFile(config_path, "utf-8");
+  const parsedConfig = parse(tomlContent);
+  const validatedConfig = RawConfig.parse(parsedConfig);
+
+  const loadedConfig = await validatedConfig.load(config_path);
+
+  return loadedConfig;
+}
+
+// Create singleton
+let configPromise: ReturnType<typeof loadConfig>;
+
+export function getConfig() {
+  if (!configPromise) {
+    configPromise = loadConfig(CONFIG_PATH);
+  }
+  return configPromise;
+}
+
+export const RawConfig = z
+  .object({
+    gateway: GatewayConfig.optional().default({}),
+    models: z.record(z.string(), ModelConfigSchema),
+    embedding_models: z
+      .record(z.string(), EmbeddingModelConfigSchema)
+      .optional()
+      .default({}),
+    functions: z.record(z.string(), RawFunctionConfigSchema),
+    metrics: z.record(z.string(), MetricConfigSchema),
+    tools: z.record(z.string(), ToolConfigSchema).optional().default({}),
+  })
+  .transform((raw) => {
+    const config = { ...raw };
+    return {
+      ...config,
+      load: async function (config_path: string): Promise<Config> {
+        const loadedFunctions: Record<string, FunctionConfig> = {};
+        for (const [key, func] of Object.entries(config.functions)) {
+          loadedFunctions[key] = await func.load(config_path);
+        }
+        return {
+          gateway: config.gateway,
+          models: config.models,
+          embedding_models: config.embedding_models,
+          functions: loadedFunctions,
+          metrics: config.metrics,
+          tools: config.tools,
+        };
+      },
+    };
+  });
+export type RawConfig = z.infer<typeof RawConfig>;
diff --git a/dashboard/app/utils/config/index.ts b/dashboard/app/utils/config/index.ts
new file mode 100644
index 000000000..b481b8b18
--- /dev/null
+++ b/dashboard/app/utils/config/index.ts
@@ -0,0 +1,24 @@
+import { z } from "zod";
+import { ModelConfigSchema, EmbeddingModelConfigSchema } from "./models";
+import { FunctionConfigSchema } from "./function";
+import { MetricConfigSchema } from "./metric";
+import { ToolConfigSchema } from "./tool";
+
+export const GatewayConfig = z.object({
+  bind_address: z.string().optional(), // Socket address as string
+  disable_observability: z.boolean().default(false),
+});
+export type GatewayConfig = z.infer<typeof GatewayConfig>;
+
+export const Config = z.object({
+  gateway: GatewayConfig.optional().default({}),
+  models: z.record(z.string(), ModelConfigSchema),
+  embedding_models: z
+    .record(z.string(), EmbeddingModelConfigSchema)
+    .optional()
+    .default({}),
+  functions: z.record(z.string(), FunctionConfigSchema),
+  metrics: z.record(z.string(), MetricConfigSchema),
+  tools: z.record(z.string(), ToolConfigSchema).optional().default({}),
+});
+export type Config = z.infer<typeof Config>;
diff --git a/dashboard/app/utils/config/metric.ts b/dashboard/app/utils/config/metric.ts
new file mode 100644
index 000000000..a95a6ab5d
--- /dev/null
+++ b/dashboard/app/utils/config/metric.ts
@@ -0,0 +1,22 @@
+import { z } from "zod";
+
+export const MetricConfigTypeSchema = z.enum([
+  "boolean",
+  "float",
+  "comment",
+  "demonstration",
+]);
+export type MetricConfigType = z.infer<typeof MetricConfigTypeSchema>;
+
+export const MetricConfigOptimizeSchema = z.enum(["min", "max"]);
+export type MetricConfigOptimize = z.infer<typeof MetricConfigOptimizeSchema>;
+
+export const MetricConfigLevelSchema = z.enum(["inference", "episode"]);
+export type MetricConfigLevel = z.infer<typeof MetricConfigLevelSchema>;
+
+export const MetricConfigSchema = z.object({
+  type: MetricConfigTypeSchema,
+  optimize: MetricConfigOptimizeSchema,
+  level: MetricConfigLevelSchema,
+});
+export type MetricConfig = z.infer<typeof MetricConfigSchema>;
diff --git a/dashboard/app/utils/config/models.ts b/dashboard/app/utils/config/models.ts
new file mode 100644
index 000000000..4fb9e28dc
--- /dev/null
+++ b/dashboard/app/utils/config/models.ts
@@ -0,0 +1,219 @@
+import { z } from "zod";
+import { stringify } from "smol-toml";
+
+// Base provider configs
+export const AnthropicProviderConfigSchema = z.object({
+  type: z.literal("anthropic"),
+  model_name: z.string(),
+});
+export type AnthropicProviderConfig = z.infer<
+  typeof AnthropicProviderConfigSchema
+>;
+
+export const AWSBedrockProviderConfigSchema = z.object({
+  type: z.literal("aws_bedrock"),
+  model_id: z.string(),
+  region: z.string().optional(),
+});
+export type AWSBedrockProviderConfig = z.infer<
+  typeof AWSBedrockProviderConfigSchema
+>;
+
+export const AzureProviderConfigSchema = z.object({
+  type: z.literal("azure"),
+  deployment_id: z.string(),
+  endpoint: z.string().url(),
+});
+export type AzureProviderConfig = z.infer<typeof AzureProviderConfigSchema>;
+
+export const DummyProviderConfigSchema = z.object({
+  type: z.literal("dummy"),
+  model_name: z.string(),
+});
+export type DummyProviderConfig = z.infer<typeof DummyProviderConfigSchema>;
+
+export const FireworksProviderConfigSchema = z.object({
+  type: z.literal("fireworks"),
+  model_name: z.string(),
+});
+export type FireworksProviderConfig = z.infer<
+  typeof FireworksProviderConfigSchema
+>;
+
+export const GCPVertexAnthropicProviderConfigSchema = z.object({
+  type: z.literal("gcp_vertex_anthropic"),
+  model_id: z.string(),
+  location: z.string(),
+  project_id: z.string(),
+});
+export type GCPVertexAnthropicProviderConfig = z.infer<
+  typeof GCPVertexAnthropicProviderConfigSchema
+>;
+
+export const GCPVertexGeminiProviderConfigSchema = z.object({
+  type: z.literal("gcp_vertex_gemini"),
+  model_id: z.string(),
+  location: z.string(),
+  project_id: z.string(),
+});
+export type GCPVertexGeminiProviderConfig = z.infer<
+  typeof GCPVertexGeminiProviderConfigSchema
+>;
+
+export const GoogleAIStudioGeminiProviderConfigSchema = z.object({
+  type: z.literal("google_ai_studio_gemini"),
+  model_name: z.string(),
+});
+export type GoogleAIStudioGeminiProviderConfig = z.infer<
+  typeof GoogleAIStudioGeminiProviderConfigSchema
+>;
+
+export const HyperbolicProviderConfigSchema = z.object({
+  type: z.literal("hyperbolic"),
+  model_name: z.string(),
+});
+export type HyperbolicProviderConfig = z.infer<
+  typeof HyperbolicProviderConfigSchema
+>;
+
+export const MistralProviderConfigSchema = z.object({
+  type: z.literal("mistral"),
+  model_name: z.string(),
+});
+export type MistralProviderConfig = z.infer<typeof MistralProviderConfigSchema>;
+
+export const OpenAIProviderConfigSchema = z.object({
+  type: z.literal("openai"),
+  model_name: z.string(),
+  api_base: z.string().url().optional(),
+});
+export type OpenAIProviderConfig = z.infer<typeof OpenAIProviderConfigSchema>;
+
+export const TogetherProviderConfigSchema = z.object({
+  type: z.literal("together"),
+  model_name: z.string(),
+});
+export type TogetherProviderConfig = z.infer<
+  typeof TogetherProviderConfigSchema
+>;
+
+export const VLLMProviderConfigSchema = z.object({
+  type: z.literal("vllm"),
+  model_name: z.string(),
+  api_base: z.string().url(),
+});
+export type VLLMProviderConfig = z.infer<typeof VLLMProviderConfigSchema>;
+
+export const XAIProviderConfigSchema = z.object({
+  type: z.literal("xai"),
+  model_name: z.string(),
+});
+export type XAIProviderConfig = z.infer<typeof XAIProviderConfigSchema>;
+
+// Union of all provider configs
+export const ProviderConfigSchema = z.discriminatedUnion("type", [
+  AnthropicProviderConfigSchema,
+  AWSBedrockProviderConfigSchema,
+  AzureProviderConfigSchema,
+  DummyProviderConfigSchema,
+  FireworksProviderConfigSchema,
+  GCPVertexAnthropicProviderConfigSchema,
+  GCPVertexGeminiProviderConfigSchema,
+  GoogleAIStudioGeminiProviderConfigSchema,
+  HyperbolicProviderConfigSchema,
+  MistralProviderConfigSchema,
+  OpenAIProviderConfigSchema,
+  TogetherProviderConfigSchema,
+  VLLMProviderConfigSchema,
+  XAIProviderConfigSchema,
+]);
+
+export type ProviderConfig = z.infer<typeof ProviderConfigSchema>;
+export type ProviderType = ProviderConfig["type"];
+
+export function createProviderConfig(
+  type: ProviderType,
+  model_name: string,
+): ProviderConfig {
+  switch (type) {
+    case "anthropic":
+    case "dummy":
+    case "fireworks":
+    case "mistral":
+    case "together":
+    case "google_ai_studio_gemini":
+    case "openai":
+      return { type, model_name };
+    case "aws_bedrock":
+      return { type, model_id: model_name };
+    default:
+      throw new Error(`Provider ${type} requires additional configuration`);
+  }
+}
+
+// Model config schema
+export const ModelConfigSchema = z.object({
+  // Array of provider names for routing/fallback order
+  routing: z.array(z.string()),
+  // Map of provider name to provider config
+  providers: z.record(z.string(), ProviderConfigSchema),
+});
+
+export type ModelConfig = z.infer<typeof ModelConfigSchema>;
+
+// Embedding provider config schema
+export const EmbeddingProviderConfigSchema = z.discriminatedUnion("type", [
+  OpenAIProviderConfigSchema,
+]);
+
+export type EmbeddingProviderConfig = z.infer<
+  typeof EmbeddingProviderConfigSchema
+>;
+
+// Embedding model config schema
+export const EmbeddingModelConfigSchema = z.object({
+  // Array of provider names for routing/fallback order
+  routing: z.array(z.string()),
+  // Map of provider name to provider config
+  providers: z.record(z.string(), EmbeddingProviderConfigSchema),
+});
+
+export type EmbeddingModelConfig = z.infer<typeof EmbeddingModelConfigSchema>;
+
+// Helper functions for model config
+export type FullyQualifiedModelConfig = {
+  models: {
+    [key: string]: ModelConfig;
+  };
+};
+
+export function get_fine_tuned_model_config(
+  model_name: string,
+  model_provider_type: ProviderType,
+) {
+  const providerConfig: ProviderConfig = createProviderConfig(
+    model_provider_type,
+    model_name,
+  );
+  const modelConfig: ModelConfig = {
+    routing: [model_name],
+    providers: {
+      [model_name]: providerConfig,
+    },
+  };
+  const fullyQualifiedModelConfig: FullyQualifiedModelConfig = {
+    models: {
+      [model_name]: modelConfig,
+    },
+  };
+  return fullyQualifiedModelConfig;
+}
+
+export function dump_model_config(modelConfig: FullyQualifiedModelConfig) {
+  const rawSerializedModelConfig = stringify(modelConfig);
+  const lines = rawSerializedModelConfig.split("\n");
+  const linesWithoutFirst = lines.slice(1);
+  linesWithoutFirst.splice(3, 1);
+  const trimmedSerializedModelConfig = linesWithoutFirst.join("\n");
+  return trimmedSerializedModelConfig;
+}
diff --git a/dashboard/app/utils/config/tool.ts b/dashboard/app/utils/config/tool.ts
new file mode 100644
index 000000000..b4efbfc4e
--- /dev/null
+++ b/dashboard/app/utils/config/tool.ts
@@ -0,0 +1,17 @@
+import { z } from "zod";
+
+export const ToolChoiceSchema = z.enum(["none", "auto", "required"]).or(
+  z.object({
+    specific: z.string(),
+  }),
+);
+
+export type ToolChoice = z.infer<typeof ToolChoiceSchema>;
+
+export const ToolConfigSchema = z.object({
+  description: z.string(),
+  parameters: z.string(),
+  strict: z.boolean().default(false),
+});
+
+export type ToolConfig = z.infer<typeof ToolConfigSchema>;
diff --git a/dashboard/app/utils/config/types.ts b/dashboard/app/utils/config/types.ts
new file mode 100644
index 000000000..1f42770f1
--- /dev/null
+++ b/dashboard/app/utils/config/types.ts
@@ -0,0 +1,25 @@
+import { z } from "zod";
+import type { JSONSchema7 } from "json-schema";
+import Ajv from "ajv";
+
+const ajv = new Ajv({ allErrors: true });
+
+export const jsonSchema7Validator = z.custom<JSONSchema7>((val) => {
+  try {
+    if (typeof val !== "object" || val === null) {
+      return false;
+    }
+    return ajv.validateSchema(val);
+  } catch {
+    return false;
+  }
+}, "Must be a valid JSON Schema Draft 7 schema");
+
+export const jsonModeSchema = z.enum(["off", "on", "strict", "implicit_tool"]);
+export type JsonMode = z.infer<typeof jsonModeSchema>;
+
+export const RetryConfigSchema = z.object({
+  num_retries: z.number().int().nonnegative().default(0),
+  max_delay_s: z.number().nonnegative().default(10),
+});
+export type RetryConfig = z.infer<typeof RetryConfigSchema>;
diff --git a/dashboard/app/utils/config/variant.server.ts b/dashboard/app/utils/config/variant.server.ts
new file mode 100644
index 000000000..552dc8854
--- /dev/null
+++ b/dashboard/app/utils/config/variant.server.ts
@@ -0,0 +1,129 @@
+import { z } from "zod";
+import { promises as fs } from "fs";
+import path from "path";
+import {
+  BaseChatCompletionConfigSchema,
+  BestOfNSamplingConfigSchema,
+  DiclConfigSchema,
+  MixtureOfNConfigSchema,
+  type ChatCompletionConfig,
+  type VariantConfig,
+} from "./variant";
+import { stringify } from "smol-toml";
+
+export const RawChatCompletionConfigSchema =
+  BaseChatCompletionConfigSchema.extend({
+    type: z.literal("chat_completion"),
+  }).partial({ retries: true, weight: true });
+
+export type RawChatCompletionConfig = z.infer<
+  typeof RawChatCompletionConfigSchema
+>;
+
+// Raw variant config using basic string templates
+export const RawVariantConfigSchema = z
+  .discriminatedUnion("type", [
+    RawChatCompletionConfigSchema,
+    BestOfNSamplingConfigSchema,
+    DiclConfigSchema,
+    MixtureOfNConfigSchema,
+  ])
+  .transform((raw) => ({
+    ...raw,
+    load: async function (config_path: string): Promise<VariantConfig> {
+      return await convertRawVariantConfig(raw, config_path);
+    },
+  }));
+
+export type RawVariantConfig = z.infer<typeof RawVariantConfigSchema>;
+
+export function create_dump_variant_config(
+  oldVariant: ChatCompletionConfig,
+  model_name: string,
+  function_name: string,
+) {
+  // Convert back to ChatCompletionConfig
+  const variantConfig: RawChatCompletionConfig = {
+    ...oldVariant,
+    weight: 0,
+    model: model_name,
+    system_template:
+      typeof oldVariant.system_template === "string"
+        ? oldVariant.system_template
+        : oldVariant.system_template?.path,
+    user_template:
+      typeof oldVariant.user_template === "string"
+        ? oldVariant.user_template
+        : oldVariant.user_template?.path,
+    assistant_template:
+      typeof oldVariant.assistant_template === "string"
+        ? oldVariant.assistant_template
+        : oldVariant.assistant_template?.path,
+  };
+
+  const fullNewVariantConfig = {
+    functions: {
+      [function_name]: {
+        variants: {
+          [model_name]: variantConfig,
+        },
+      },
+    },
+  };
+
+  return stringify(fullNewVariantConfig);
+}
+async function loadTemplateContent(
+  templatePath: string,
+  configPath: string,
+): Promise<string> {
+  // Dynamic import to prevent bundling fs module
+  return await fs.readFile(
+    path.join(path.dirname(configPath), templatePath),
+    "utf-8",
+  );
+}
+
+export async function convertRawVariantConfig(
+  variantConfig: Omit<RawVariantConfig, "load">,
+  configPath: string,
+): Promise<VariantConfig> {
+  if (variantConfig.type === "chat_completion") {
+    const rawChatCompletionConfig = variantConfig as RawChatCompletionConfig;
+    const templatedVariant: ChatCompletionConfig = {
+      ...rawChatCompletionConfig,
+      type: "chat_completion",
+      system_template: rawChatCompletionConfig.system_template
+        ? {
+            path: rawChatCompletionConfig.system_template,
+            content: await loadTemplateContent(
+              rawChatCompletionConfig.system_template,
+              configPath,
+            ),
+          }
+        : undefined,
+      user_template: rawChatCompletionConfig.user_template
+        ? {
+            path: rawChatCompletionConfig.user_template,
+            content: await loadTemplateContent(
+              rawChatCompletionConfig.user_template,
+              configPath,
+            ),
+          }
+        : undefined,
+      assistant_template: rawChatCompletionConfig.assistant_template
+        ? {
+            path: rawChatCompletionConfig.assistant_template,
+            content: await loadTemplateContent(
+              rawChatCompletionConfig.assistant_template,
+              configPath,
+            ),
+          }
+        : undefined,
+    };
+    return templatedVariant;
+  }
+
+  // Other variant types don't need conversion
+  return variantConfig as VariantConfig;
+}
diff --git a/dashboard/app/utils/config/variant.ts b/dashboard/app/utils/config/variant.ts
new file mode 100644
index 000000000..b24258882
--- /dev/null
+++ b/dashboard/app/utils/config/variant.ts
@@ -0,0 +1,133 @@
+import { z } from "zod";
+import { jsonModeSchema, RetryConfigSchema } from "./types";
+import { create_env } from "../minijinja/pkg/minijinja_bindings";
+
+// Runtime-only type for internal use
+export interface TemplateWithContent {
+  path: string;
+  content?: string;
+}
+
+export const BaseChatCompletionConfigSchema = z.object({
+  weight: z.number().default(0),
+  model: z.string(),
+  system_template: z.string().optional(),
+  user_template: z.string().optional(),
+  assistant_template: z.string().optional(),
+  temperature: z.number().optional(),
+  top_p: z.number().optional(),
+  max_tokens: z.number().int().optional(),
+  presence_penalty: z.number().optional(),
+  frequency_penalty: z.number().optional(),
+  seed: z.number().int().optional(),
+  json_mode: jsonModeSchema.default("on"),
+  retries: RetryConfigSchema.default({ num_retries: 0, max_delay_s: 10 }),
+});
+
+export const EvaluatorConfigSchema = z.object({
+  ...BaseChatCompletionConfigSchema.shape,
+});
+
+export type EvaluatorConfig = z.infer<typeof EvaluatorConfigSchema>;
+
+export const BestOfNSamplingConfigSchema = z.object({
+  type: z.literal("experimental_best_of_n_sampling"),
+  weight: z.number().default(0),
+  timeout_s: z.number().default(300),
+  candidates: z.array(z.string()),
+  evaluator: EvaluatorConfigSchema,
+});
+
+export type BestOfNSamplingConfig = z.infer<typeof BestOfNSamplingConfigSchema>;
+
+export const DiclConfigSchema = z.object({
+  type: z.literal("experimental_dynamic_in_context_learning"),
+  weight: z.number().default(0),
+  embedding_model: z.string(),
+  k: z.number().int(), // k as in k-nearest neighbors
+  model: z.string(),
+  system_instructions: z.string().optional(), // should be the path here not the actual system instructions
+  temperature: z.number().optional(),
+  top_p: z.number().optional(),
+  presence_penalty: z.number().optional(),
+  frequency_penalty: z.number().optional(),
+  max_tokens: z.number().int().optional(),
+  seed: z.number().int().optional(),
+  json_mode: jsonModeSchema.default("on"),
+  retries: RetryConfigSchema.optional().default({
+    num_retries: 0,
+    max_delay_s: 10,
+  }),
+});
+
+export type DiclConfig = z.infer<typeof DiclConfigSchema>;
+
+export const FuserConfigSchema = z.object({
+  ...BaseChatCompletionConfigSchema.shape,
+});
+
+export type FuserConfig = z.infer<typeof FuserConfigSchema>;
+
+export const MixtureOfNConfigSchema = z.object({
+  type: z.literal("experimental_mixture_of_n"),
+  weight: z.number().default(0),
+  timeout_s: z.number().default(300),
+  candidates: z.array(z.string()),
+  fuser: FuserConfigSchema,
+});
+
+export type MixtureOfNConfig = z.infer<typeof MixtureOfNConfigSchema>;
+
+// Extend the inferred type to include template content
+export const ChatCompletionConfigSchema = BaseChatCompletionConfigSchema.extend(
+  {
+    type: z.literal("chat_completion"),
+    system_template: z.custom<TemplateWithContent>().optional(),
+    user_template: z.custom<TemplateWithContent>().optional(),
+    assistant_template: z.custom<TemplateWithContent>().optional(),
+  },
+).partial({ retries: true, weight: true });
+
+export type ChatCompletionConfig = z.infer<typeof ChatCompletionConfigSchema>;
+
+// Variant config using template content
+export const VariantConfigSchema = z.discriminatedUnion("type", [
+  ChatCompletionConfigSchema,
+  BestOfNSamplingConfigSchema,
+  DiclConfigSchema,
+  MixtureOfNConfigSchema,
+]);
+
+export type VariantConfig = z.infer<typeof VariantConfigSchema>;
+
+export async function get_template_env(variant: ChatCompletionConfig) {
+  const env: {
+    system?: string;
+    user?: string;
+    assistant?: string;
+  } = {};
+
+  if ("system_template" in variant && variant.system_template) {
+    env.system =
+      typeof variant.system_template === "string"
+        ? variant.system_template
+        : (variant.system_template.content ?? variant.system_template.path);
+  }
+
+  if ("user_template" in variant && variant.user_template) {
+    env.user =
+      typeof variant.user_template === "string"
+        ? variant.user_template
+        : (variant.user_template.content ?? variant.user_template.path);
+  }
+
+  if ("assistant_template" in variant && variant.assistant_template) {
+    env.assistant =
+      typeof variant.assistant_template === "string"
+        ? variant.assistant_template
+        : (variant.assistant_template.content ??
+          variant.assistant_template.path);
+  }
+
+  return await create_env(env);
+}
diff --git a/dashboard/app/utils/fine_tuning/client.ts b/dashboard/app/utils/fine_tuning/client.ts
new file mode 100644
index 000000000..8ff57efdf
--- /dev/null
+++ b/dashboard/app/utils/fine_tuning/client.ts
@@ -0,0 +1,15 @@
+import type { SFTFormValues } from "~/routes/optimization/fine-tuning/types";
+import { OpenAISFTJob } from "./openai";
+import { FireworksSFTJob } from "./fireworks";
+import type { SFTJob } from "./common";
+
+export function launch_sft_job(data: SFTFormValues): Promise<SFTJob> {
+  switch (data.model.provider) {
+    case "openai":
+      return OpenAISFTJob.fromFormData(data);
+    case "fireworks":
+      return FireworksSFTJob.from_form_data(data);
+    default:
+      throw new Error("Invalid provider");
+  }
+}
diff --git a/dashboard/app/utils/fine_tuning/common.ts b/dashboard/app/utils/fine_tuning/common.ts
new file mode 100644
index 000000000..822b920a4
--- /dev/null
+++ b/dashboard/app/utils/fine_tuning/common.ts
@@ -0,0 +1,40 @@
+import type { SFTFormValues } from "~/routes/optimization/fine-tuning/types";
+import type { ParsedInferenceRow } from "../clickhouse";
+import type { ProviderType } from "../config/models";
+
+export function splitValidationData(
+  inferences: ParsedInferenceRow[],
+  validationSplitPercent: number,
+) {
+  const validationSplit = validationSplitPercent / 100;
+  const splitIndex =
+    validationSplit > 0
+      ? Math.floor(inferences.length * (1 - validationSplit))
+      : inferences.length;
+
+  const trainInferences = inferences.slice(0, splitIndex);
+  const valInferences =
+    validationSplitPercent > 0 ? inferences.slice(splitIndex) : [];
+
+  return {
+    trainInferences,
+    valInferences,
+  };
+}
+
+export type SFTJobStatus = "running" | "completed" | "error";
+
+// Abstract base class
+export abstract class SFTJob {
+  protected constructor() {}
+
+  /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
+  static fromFormData(data: SFTFormValues): Promise<SFTJob> {
+    throw new Error("Child class must implement fromFormData");
+  }
+
+  abstract result(): string | undefined;
+  abstract status(): SFTJobStatus;
+  abstract poll(): Promise<SFTJob>;
+  abstract provider(): ProviderType;
+}
diff --git a/dashboard/app/utils/fine_tuning/fireworks.ts b/dashboard/app/utils/fine_tuning/fireworks.ts
new file mode 100644
index 000000000..ead771d38
--- /dev/null
+++ b/dashboard/app/utils/fine_tuning/fireworks.ts
@@ -0,0 +1,562 @@
+/**
+ * This module handles fine-tuning and deployment of models using the Fireworks AI API.
+ *
+ * The high-level flow is:
+ * 1. User submits fine-tuning job configuration via the UI form (SFTFormValues)
+ * 2. FireworksSFTJob class is instantiated with the form data
+ * 3. Curated training data is retrieved from ClickHouse based on:
+ *    - Selected function
+ *    - Selected metric
+ *    - Max samples limit
+ * 4. Training data is formatted according to Fireworks API requirements
+ * 5. Fine-tuning job is launched via Fireworks API endpoints (we get a job ID here)
+ * 6. Job status is polled periodically to track progress
+ * 7. Once complete, the fine-tuned model ID is stored
+ * 8. The fine-tuned model is then deployed-- this also needs to be polled
+ * 9. Once this is completed we have a path we can use for inference
+ *
+ * The FireworksSFTJob class extends the base SFTJob class to provide
+ * Fireworks-specific implementation of job creation, status polling,
+ * result handling, and deployment management.
+ */
+
+import type { SFTFormValues } from "~/routes/optimization/fine-tuning/types";
+import type { JsExposedEnv } from "../minijinja/pkg/minijinja_bindings";
+import { v7 } from "uuid";
+import type {
+  ContentBlockOutput,
+  JsonInferenceOutput,
+  ParsedInferenceRow,
+} from "../clickhouse";
+import { getCuratedInferences } from "../clickhouse";
+import { render_message } from "./rendering";
+import { getConfig } from "../config/index.server";
+import { get_template_env, type ChatCompletionConfig } from "../config/variant";
+import { z } from "zod";
+import { SFTJob, type SFTJobStatus } from "./common";
+import type { ProviderType } from "../config/models";
+export const FIREWORKS_API_URL = "https://api.fireworks.ai";
+export const FIREWORKS_API_KEY = process.env.FIREWORKS_API_KEY || throwError();
+export const FIREWORKS_ACCOUNT_ID =
+  process.env.FIREWORKS_ACCOUNT_ID || throwError();
+
+// This is apparently the traditional way to coerce both to strings.
+function throwError(): never {
+  throw new Error("FIREWORKS_API_KEY and FIREWORKS_ACCOUNT_ID must be set");
+}
+
+interface FireworksSFTJobParams {
+  jobPath: string;
+  status: string;
+  jobId: string;
+  modelId?: string;
+  modelPath?: string;
+}
+
+export class FireworksSFTJob extends SFTJob {
+  public jobPath: string;
+  public jobStatus: string;
+  public jobId: string;
+  public modelId?: string;
+  public modelPath?: string;
+
+  constructor(params: FireworksSFTJobParams) {
+    super();
+    this.jobPath = params.jobPath;
+    this.jobStatus = params.status;
+    this.jobId = params.jobId;
+    this.modelId = params.modelId;
+    this.modelPath = params.modelPath;
+  }
+
+  static async from_form_data(data: SFTFormValues): Promise<FireworksSFTJob> {
+    const config = await getConfig();
+    const currentVariant = config.functions[data.function].variants[
+      data.variant
+    ] as ChatCompletionConfig;
+    if (currentVariant.type != "chat_completion") {
+      throw new Error(
+        "Supervised fine-tuning is only supported for chat completion variants",
+      );
+    }
+    const curatedInferences = await getCuratedInferences(
+      data.function,
+      config.functions[data.function],
+      data.metric,
+      config.metrics[data.metric],
+      data.maxSamples,
+    );
+    if (!curatedInferences || curatedInferences.length === 0) {
+      throw new Error("No curated inferences found");
+    }
+    const templateEnv = await get_template_env(currentVariant);
+    const jobPath = await start_sft_fireworks(
+      data.model.name,
+      curatedInferences,
+      data.validationSplitPercent,
+      templateEnv,
+    );
+    return new FireworksSFTJob({
+      jobPath: jobPath,
+      status: "RUNNING",
+      jobId: data.jobId,
+      modelId: undefined,
+      modelPath: undefined,
+    });
+  }
+
+  provider(): ProviderType {
+    return "fireworks";
+  }
+
+  status(): SFTJobStatus {
+    if (this.jobStatus === "FAILED") return "error";
+    return this.jobStatus === "DEPLOYED" ? "completed" : "running";
+  }
+
+  result(): string | undefined {
+    return this.modelPath;
+  }
+
+  async poll(): Promise<FireworksSFTJob> {
+    if (!this.modelId) {
+      // If we don't have a model ID, training is still running so we need to poll for it
+      const status = await get_fine_tuning_job_status(this.jobPath);
+      if (status === "COMPLETED") {
+        const modelId = await get_model_id(this.jobPath);
+        if (!modelId) {
+          throw new Error("Model ID not found after job completed");
+        }
+        await deploy_model(FIREWORKS_ACCOUNT_ID, modelId);
+        return new FireworksSFTJob({
+          jobPath: this.jobPath,
+          status: "DEPLOYING",
+          jobId: this.jobId,
+          modelId: modelId,
+          modelPath: undefined,
+        });
+      } else {
+        return new FireworksSFTJob({
+          jobPath: this.jobPath,
+          status: "TRAINING",
+          jobId: this.jobId,
+          modelId: undefined,
+          modelPath: undefined,
+        });
+      }
+    } else {
+      // If we do have a model ID, we need to poll for the deployment
+      const status = await poll_model_deployment(
+        FIREWORKS_ACCOUNT_ID,
+        this.modelId,
+      );
+      if (status === "DEPLOYED") {
+        const modelPath = `accounts/${FIREWORKS_ACCOUNT_ID}/models/${this.modelId}`;
+        return new FireworksSFTJob({
+          jobPath: this.jobPath,
+          status: "DEPLOYED",
+          jobId: this.jobId,
+          modelId: this.modelId,
+          modelPath: modelPath,
+        });
+      } else {
+        return new FireworksSFTJob({
+          jobPath: this.jobPath,
+          status: "DEPLOYING",
+          jobId: this.jobId,
+          modelId: this.modelId,
+          modelPath: undefined,
+        });
+      }
+    }
+  }
+}
+
+const FineTuningJobStatusSchema = z.enum([
+  "STATE_UNSPECIFIED",
+  "CREATING",
+  "PENDING",
+  "RUNNING",
+  "COMPLETED",
+  "FAILED",
+  "DELETING",
+]);
+
+type FineTuningJobStatus = z.infer<typeof FineTuningJobStatusSchema>;
+
+const FineTuningJobResponseSchema = z.object({
+  state: FineTuningJobStatusSchema,
+  modelId: z.string().optional(),
+  // Add more fields as needed
+});
+
+type FineTuningJobResponse = z.infer<typeof FineTuningJobResponseSchema>;
+
+// Docs: https://docs.fireworks.ai/api-reference/get-fine-tuning-job
+async function get_fine_tuning_job_details(
+  job_path: string,
+): Promise<FineTuningJobResponse> {
+  const url = new URL(`v1/${job_path}`, FIREWORKS_API_URL).toString();
+  const options = {
+    method: "GET",
+    headers: {
+      Authorization: `Bearer ${FIREWORKS_API_KEY}`,
+    },
+  };
+
+  try {
+    const info = await fetch(url, options);
+    if (!info.ok) {
+      throw new Error(
+        `Failed to get fine tuning job details: ${info.status} ${info.statusText}`,
+      );
+    }
+    const response = await info.json();
+    // Validate the response with Zod
+    const validated = FineTuningJobResponseSchema.parse(response);
+    return validated;
+  } catch (error) {
+    if (error instanceof z.ZodError) {
+      throw new Error(`Invalid API response format: ${error.message}`);
+    }
+    throw new Error(
+      `Error getting fine tuning job details: ${
+        error instanceof Error ? error.message : "Unknown error"
+      }`,
+    );
+  }
+}
+
+async function get_fine_tuning_job_status(
+  job_path: string,
+): Promise<FineTuningJobStatus> {
+  const response = await get_fine_tuning_job_details(job_path);
+  return response.state;
+}
+
+// This is the model ID that we can use to deploy the model
+// Note: this should only be called after the job is completed
+async function get_model_id(job_path: string): Promise<string | undefined> {
+  const response = await get_fine_tuning_job_details(job_path);
+  return response.modelId;
+}
+
+// Docs: https://docs.fireworks.ai/api-reference/create-deployment
+// Once a model has been fine-tuned, we should deploy it
+// This is a separate step from the fine-tuning job
+// NOTE: If unused, the model will be un-deployed after 7 days
+async function deploy_model_request(accountId: string, modelId: string) {
+  const url = new URL(
+    `v1/accounts/${accountId}/deployedModels`,
+    FIREWORKS_API_URL,
+  ).toString();
+
+  const model_path = `accounts/${accountId}/models/${modelId}`;
+  const body = {
+    model: model_path,
+    displayName: model_path,
+    default: true,
+    serverless: true,
+    public: false,
+  };
+
+  const options = {
+    method: "POST",
+    headers: {
+      Authorization: `Bearer ${FIREWORKS_API_KEY}`,
+      "Content-Type": "application/json",
+    },
+    body: JSON.stringify(body),
+  };
+
+  const response = await fetch(url, options).then((r) => r.json());
+
+  return response;
+}
+
+async function deploy_model(
+  accountId: string,
+  modelId: string,
+): Promise<string> {
+  const response = await deploy_model_request(accountId, modelId);
+  return response.name;
+}
+
+// Returns the status of the deployment
+// TODO: this should be a better API call honestly
+// We just can't find the right endpoint
+async function poll_model_deployment(
+  accountId: string,
+  modelId: string,
+): Promise<string> {
+  const response = await deploy_model_request(accountId, modelId);
+  const message = response.message;
+  if (!message) {
+    throw new Error("Failed to get deployment status message");
+  }
+  const status = message.split(":").pop()?.trim();
+  if (!status) {
+    throw new Error("Failed to parse deployment status from message");
+  }
+  return status;
+}
+
+export async function start_sft_fireworks(
+  modelName: string,
+  inferences: ParsedInferenceRow[],
+  validationSplitPercent: number,
+  templateEnv: JsExposedEnv,
+): Promise<string> {
+  const fireworksExamples = inferences.map((inference) =>
+    tensorzero_inference_to_fireworks_messages(inference, templateEnv),
+  );
+
+  const datasetId = await create_dataset_record(
+    FIREWORKS_ACCOUNT_ID,
+    fireworksExamples.length,
+  );
+  await upload_dataset(FIREWORKS_ACCOUNT_ID, datasetId, fireworksExamples);
+
+  // We poll here since this usually does not take long
+  while (!(await dataset_is_ready(FIREWORKS_ACCOUNT_ID, datasetId))) {
+    await new Promise((resolve) => setTimeout(resolve, 1000));
+  }
+
+  const job_path = await create_fine_tuning_job(
+    FIREWORKS_ACCOUNT_ID,
+    datasetId,
+    modelName,
+    validationSplitPercent,
+  );
+
+  return job_path;
+}
+
+type FireworksMessage = {
+  role: "system" | "user" | "assistant";
+  content: string;
+};
+
+type FireworksExample = {
+  messages: FireworksMessage[];
+};
+
+export function tensorzero_inference_to_fireworks_messages(
+  sample: ParsedInferenceRow,
+  env: JsExposedEnv,
+): FireworksExample {
+  const messages: FireworksMessage[] = [];
+
+  // Handle system message
+  const system = sample.input.system;
+  if (env.has_template("system")) {
+    const rendered_system = env.render("system", system);
+    messages.push({
+      role: "system",
+      content: rendered_system,
+    });
+  } else if (system) {
+    if (typeof system !== "string") {
+      throw new Error(
+        "System message must be a string when not using templates",
+      );
+    }
+    messages.push({
+      role: "system",
+      content: system,
+    });
+  }
+
+  // Handle input messages
+  for (const message of sample.input.messages) {
+    for (const content of message.content) {
+      if (content.type === "text") {
+        messages.push({
+          role: message.role,
+          content: render_message(env, message.role, content),
+        });
+      } else {
+        throw new Error(
+          "Only text messages are supported for Fireworks fine-tuning",
+        );
+      }
+    }
+  }
+
+  // Handle output
+  const isChatInference = Array.isArray(sample.output);
+  if (isChatInference) {
+    const output = sample.output as ContentBlockOutput[];
+    if (output.length !== 1) {
+      throw new Error("Chat inference must have exactly one message");
+    }
+    if (output[0].type !== "text") {
+      throw new Error("Chat inference must have a text message as output");
+    }
+    messages.push({ role: "assistant", content: output[0].text });
+  } else if ("raw" in sample.output) {
+    const output = sample.output as JsonInferenceOutput;
+    messages.push({ role: "assistant", content: output.raw });
+  } else {
+    throw new Error("Invalid inference type");
+  }
+
+  return { messages };
+}
+
+// Creates a dataset record in Fireworks.
+// This is a placeholder for the dataset that gets uploaded in a subsequest call.
+// Essentially all this does is make an ID in Fireworks that we reuse.
+// We'll use a UUIDv7
+async function create_dataset_record(accountId: string, exampleCount: number) {
+  const datasetId = v7();
+  const url = new URL(
+    `v1/accounts/${accountId}/datasets`,
+    FIREWORKS_API_URL,
+  ).toString();
+  const options = {
+    method: "POST",
+    headers: {
+      Authorization: `Bearer ${FIREWORKS_API_KEY}`,
+      "Content-Type": "application/json",
+    },
+    body: JSON.stringify({
+      datasetId: datasetId,
+      dataset: {
+        displayName: datasetId,
+        exampleCount: exampleCount.toString(),
+        userUploaded: {}, // We can use this for e.g. function_name, timestamp, etc. later
+        format: "CHAT", // Options here are CHAT, COMPLETION, and FORMAT_UNSPECIFIED
+      },
+    }),
+  };
+  await fetch(url, options).then((r) => r.json());
+  // TODO(Viraj: check it more robustly)
+
+  return datasetId;
+}
+
+// Docs: https://docs.fireworks.ai/api-reference/upload-dataset-files
+// Note: if the data is larger than 150MB, we need to do something else
+// described here: https://docs.fireworks.ai/api-reference/get-dataset-upload-endpoint
+async function upload_dataset(
+  accountId: string,
+  datasetId: string,
+  examples: FireworksExample[],
+) {
+  const url = new URL(
+    `v1/accounts/${accountId}/datasets/${datasetId}:upload`,
+    FIREWORKS_API_URL,
+  ).toString();
+
+  // Take the data and turn it into JSONL
+  const jsonlData = examples
+    .map((example) => JSON.stringify(example))
+    .join("\n");
+
+  // Create a Blob from the JSONL data
+  const blob = new Blob([jsonlData], { type: "application/jsonl" });
+
+  // Create FormData and append the file
+  const form = new FormData();
+  form.append("file", blob, "dataset.jsonl");
+
+  const options = {
+    method: "POST",
+    headers: {
+      Authorization: `Bearer ${FIREWORKS_API_KEY}`,
+    },
+    body: form,
+  };
+
+  const response = await fetch(url, options).then((r) => r.json());
+
+  return response;
+}
+
+// Returns true if the dataset is ready for fine-tuning
+// Returns false if the dataset is not ready for fine-tuning
+async function dataset_is_ready(accountId: string, datasetId: string) {
+  const url = new URL(
+    `v1/accounts/${accountId}/datasets/${datasetId}`,
+    FIREWORKS_API_URL,
+  ).toString();
+
+  const options = {
+    method: "GET",
+    headers: {
+      Authorization: `Bearer ${FIREWORKS_API_KEY}`,
+    },
+  };
+
+  try {
+    const response = await fetch(url, options);
+    if (!response.ok) {
+      throw new Error(
+        `Failed to check dataset status: ${response.status} ${response.statusText}`,
+      );
+    }
+    const data = await response.json();
+    if (!data.state) {
+      throw new Error("Dataset status response missing state field");
+    }
+    return data.state === "READY";
+  } catch (error) {
+    throw new Error(
+      `Error checking dataset status: ${
+        error instanceof Error ? error.message : "Unknown error"
+      }`,
+    );
+  }
+}
+
+// Docs: https://docs.fireworks.ai/api-reference/create-fine-tuning-job
+// IMPORTANT: this function returns a path like "accounts/viraj-ebfe5a/fineTuningJobs/2aecc5ff56364010a143b6b0b0568b5a"
+// We need to directly use this path for getting the job status
+async function create_fine_tuning_job(
+  accountId: string,
+  datasetId: string,
+  baseModel: string,
+  valSplit: number,
+): Promise<string> {
+  const url = new URL(
+    `v1/accounts/${accountId}/fineTuningJobs`,
+    FIREWORKS_API_URL,
+  ).toString();
+
+  const body = {
+    dataset: `accounts/${accountId}/datasets/${datasetId}`,
+    baseModel: baseModel,
+    conversation: {}, // empty due to us using the default conversation template
+    evaluationSplit: valSplit / 100,
+  };
+
+  const options = {
+    method: "POST",
+    headers: {
+      Authorization: `Bearer ${FIREWORKS_API_KEY}`,
+      "Content-Type": "application/json",
+    },
+    body: JSON.stringify(body),
+  };
+
+  try {
+    const response = await fetch(url, options);
+    if (!response.ok) {
+      throw new Error(
+        `Failed to create fine tuning job: ${response.status} ${response.statusText}`,
+      );
+    }
+    const data = await response.json();
+    if (!data.name) {
+      throw new Error("Fine tuning job response missing name field");
+    }
+    return data.name;
+  } catch (error) {
+    throw new Error(
+      `Error creating fine tuning job: ${
+        error instanceof Error ? error.message : "Unknown error"
+      }`,
+    );
+  }
+}
diff --git a/dashboard/app/utils/fine_tuning/openai.ts b/dashboard/app/utils/fine_tuning/openai.ts
new file mode 100644
index 000000000..b72ded181
--- /dev/null
+++ b/dashboard/app/utils/fine_tuning/openai.ts
@@ -0,0 +1,286 @@
+import * as fs from "fs/promises";
+import * as os from "os";
+import * as path from "path";
+import { createReadStream } from "fs";
+import OpenAI from "openai";
+import type { SFTFormValues } from "~/routes/optimization/fine-tuning/types";
+import {
+  getCuratedInferences,
+  type ContentBlockOutput,
+  type InputMessageContent,
+  type JsonInferenceOutput,
+  type ParsedInferenceRow,
+  type Role,
+} from "../clickhouse";
+import { get_template_env, type ChatCompletionConfig } from "../config/variant";
+import { getConfig } from "../config/index.server";
+import type { JsExposedEnv } from "../minijinja/pkg/minijinja_bindings";
+import { splitValidationData, type SFTJobStatus } from "./common";
+import { render_message } from "./rendering";
+import { SFTJob } from "./common";
+import type { ProviderType } from "../config/models";
+
+export const client = new OpenAI({
+  apiKey: process.env.OPENAI_API_KEY,
+});
+
+interface OpenAISFTJobParams {
+  jobId: string;
+  status: string;
+  fineTunedModel?: string;
+}
+
+export class OpenAISFTJob extends SFTJob {
+  public jobId: string;
+  public jobStatus: string;
+  public fineTunedModel?: string;
+
+  constructor(params: OpenAISFTJobParams) {
+    super();
+    this.jobId = params.jobId;
+    this.jobStatus = params.status;
+    this.fineTunedModel = params.fineTunedModel;
+  }
+
+  static async fromFormData(data: SFTFormValues): Promise<OpenAISFTJob> {
+    const config = await getConfig();
+    const currentVariant = config.functions[data.function].variants[
+      data.variant
+    ] as ChatCompletionConfig;
+    if (currentVariant.type != "chat_completion") {
+      throw new Error(
+        "Supervised fine-tuning is only supported for chat completion variants",
+      );
+    }
+    const curatedInferences = await getCuratedInferences(
+      data.function,
+      config.functions[data.function],
+      data.metric,
+      config.metrics[data.metric],
+      data.maxSamples,
+    );
+    if (!curatedInferences || curatedInferences.length === 0) {
+      throw new Error("No curated inferences found");
+    }
+    const templateEnv = await get_template_env(currentVariant);
+    const job = await start_sft_openai(
+      data.model.name,
+      curatedInferences,
+      data.validationSplitPercent,
+      templateEnv,
+    );
+    return job;
+  }
+
+  result(): string | undefined {
+    return this.fineTunedModel;
+  }
+
+  provider(): ProviderType {
+    return "openai";
+  }
+
+  status(): SFTJobStatus {
+    if (this.jobStatus === "failed") return "error";
+    return this.jobStatus === "succeeded" ? "completed" : "running";
+  }
+
+  async poll(): Promise<OpenAISFTJob> {
+    if (!this.jobId) {
+      throw new Error("Job ID is required to poll OpenAI SFT");
+    }
+    const job = await client.fineTuning.jobs.retrieve(this.jobId);
+    return new OpenAISFTJob({
+      jobId: job.id,
+      status: job.status,
+      fineTunedModel: job.fine_tuned_model ?? undefined,
+    });
+  }
+}
+
+export async function start_sft_openai(
+  modelName: string,
+  inferences: ParsedInferenceRow[],
+  validationSplitPercent: number,
+  templateEnv: JsExposedEnv,
+) {
+  const { trainInferences, valInferences } = splitValidationData(
+    inferences,
+    validationSplitPercent,
+  );
+  const trainMessages = trainInferences.map((inference) =>
+    tensorzero_inference_to_openai_messages(inference, templateEnv),
+  );
+  const valMessages = valInferences.map((inference) =>
+    tensorzero_inference_to_openai_messages(inference, templateEnv),
+  );
+  const [file_id, val_file_id] = await Promise.all([
+    upload_examples_to_openai(trainMessages),
+    upload_examples_to_openai(valMessages),
+  ]);
+  const job_id = await create_openai_fine_tuning_job(
+    modelName,
+    file_id,
+    val_file_id ?? undefined,
+  );
+  return new OpenAISFTJob({
+    jobId: job_id,
+    status: "created",
+    fineTunedModel: undefined,
+  });
+}
+
+export function tensorzero_inference_to_openai_messages(
+  sample: ParsedInferenceRow,
+  env: JsExposedEnv,
+) {
+  const system = sample.input.system;
+  const messages: OpenAIMessage[] = [];
+  if (env.has_template("system")) {
+    const rendered_system = env.render("system", system);
+    messages.push({
+      role: "system",
+      content: rendered_system,
+    });
+  } else if (system) {
+    if (typeof system !== "string") {
+      throw new Error(
+        "System message must be a string when not using templates",
+      );
+    }
+    messages.push({
+      role: "system",
+      content: system,
+    });
+  }
+  for (const message of sample.input.messages) {
+    for (const content of message.content) {
+      const rendered_message = content_block_to_openai_message(
+        content,
+        message.role,
+        env,
+      );
+      messages.push(rendered_message);
+    }
+  }
+  const isChatInference = Array.isArray(sample.output);
+  if (isChatInference) {
+    const output = sample.output as ContentBlockOutput[];
+    if (output.length !== 1) {
+      throw new Error("Chat inference must have exactly one message");
+    }
+    if (output[0].type !== "text") {
+      throw new Error("Chat inference must have a text message as output");
+    }
+    messages.push({ role: "assistant", content: output[0].text });
+  } else if ("raw" in sample.output) {
+    // Must be a JSON inference if it has "raw"
+    const output = sample.output as JsonInferenceOutput;
+    messages.push({ role: "assistant", content: output.raw });
+  } else {
+    throw new Error("Invalid inference type");
+  }
+  return messages;
+}
+
+export function content_block_to_openai_message(
+  content: InputMessageContent,
+  role: Role,
+  env: JsExposedEnv,
+): OpenAIMessage {
+  switch (content.type) {
+    case "text":
+      return {
+        role: role as OpenAIRole,
+        content: render_message(env, role, content),
+      };
+    case "tool_call":
+      return {
+        role: "assistant" as OpenAIRole,
+        tool_calls: [
+          {
+            id: content.id,
+            type: "function",
+            function: { name: content.name, arguments: content.arguments },
+          },
+        ],
+      };
+    case "tool_result":
+      return {
+        role: "tool" as OpenAIRole,
+        tool_call_id: content.id,
+        content: content.result,
+      };
+  }
+}
+
+type OpenAIRole = "system" | "user" | "assistant" | "tool";
+
+type OpenAIMessage = {
+  role: OpenAIRole;
+  content?: string;
+  tool_calls?: {
+    id: string;
+    type: string;
+    function: { name: string; arguments: string };
+  }[];
+  tool_call_id?: string;
+};
+
+async function upload_examples_to_openai(samples: OpenAIMessage[][]) {
+  // Convert samples to JSONL format
+  let tempFile: string | null = null;
+  try {
+    const jsonl = samples
+      .map((messages) => JSON.stringify({ messages }))
+      .join("\n");
+
+    // Write to temporary file
+    tempFile = path.join(
+      os.tmpdir(),
+      `temp_training_data_${Math.random().toString(36).substring(2, 10)}.jsonl`,
+    );
+    await fs.writeFile(tempFile, jsonl);
+
+    const file = await client.files.create({
+      file: createReadStream(tempFile),
+      purpose: "fine-tune",
+    });
+    return file.id;
+  } finally {
+    // Clean up temp file
+    if (tempFile) {
+      try {
+        await fs.unlink(tempFile);
+      } catch (err) {
+        console.error(`Error deleting temp file ${tempFile}: ${err}`);
+      }
+    }
+  }
+}
+
+async function create_openai_fine_tuning_job(
+  model: string,
+  train_file_id: string,
+  val_file_id?: string,
+) {
+  const params: OpenAI.FineTuning.JobCreateParams = {
+    model,
+    training_file: train_file_id,
+    hyperparameters: {
+      n_epochs: 1,
+    },
+  };
+
+  if (val_file_id) {
+    params.validation_file = val_file_id;
+  }
+
+  try {
+    const job = await client.fineTuning.jobs.create(params);
+    return job.id;
+  } catch (error) {
+    console.error("Error creating fine-tuning job:", error);
+    throw error;
+  }
+}
diff --git a/dashboard/app/utils/fine_tuning/rendering.ts b/dashboard/app/utils/fine_tuning/rendering.ts
new file mode 100644
index 000000000..d9e1a1ca1
--- /dev/null
+++ b/dashboard/app/utils/fine_tuning/rendering.ts
@@ -0,0 +1,26 @@
+import type { InputMessageContent, Role } from "~/utils/clickhouse";
+import { JsExposedEnv } from "../minijinja/pkg";
+
+/**
+ * Renders a text message using the provided environment and content.
+ *
+ * @param env - The Minijinja environment for rendering (should contain templates for "system", "user" and "assistant" if and only
+ *                                                       if the function takes structured input)
+ * @param role - The role of the message sender (must be "user" or "assistant")
+ * @param content - Array of message content blocks (must contain exactly one text block)
+ * @returns The rendered message string
+ * @throws {Error} If role is invalid, content length is not 1, or content type is not text
+ */
+export function render_message(
+  env: JsExposedEnv,
+  role: Role,
+  content: InputMessageContent,
+) {
+  if (content.type !== "text") {
+    throw new Error("Content must be a text block");
+  }
+  if (typeof content.value === "string") {
+    return content.value;
+  }
+  return env.render(role, content.value);
+}
diff --git a/dashboard/app/utils/minijinja/.gitignore b/dashboard/app/utils/minijinja/.gitignore
new file mode 100644
index 000000000..5fff1d9c1
--- /dev/null
+++ b/dashboard/app/utils/minijinja/.gitignore
@@ -0,0 +1,1 @@
+pkg
diff --git a/dashboard/app/utils/minijinja/Cargo.toml b/dashboard/app/utils/minijinja/Cargo.toml
new file mode 100644
index 000000000..a8116b9c4
--- /dev/null
+++ b/dashboard/app/utils/minijinja/Cargo.toml
@@ -0,0 +1,27 @@
+[package]
+name = "minijinja-bindings"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "rlib"]
+
+[features]
+default = []
+# Uncomment this to enable the console_error_panic_hook feature
+# or do `wasm-pack build --features console_error_panic_hook`
+# default = ["console_error_panic_hook"]
+
+[dependencies]
+wasm-bindgen = "0.2.62"
+minijinja = { version = "2.1.0", features = ["loader"] }
+
+# The `console_error_panic_hook` crate provides better debugging of panics by
+# logging them with `console.error`. This is great for development, but requires
+# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
+# code size when deploying.
+console_error_panic_hook = { version = "0.1.6", optional = true }
+serde_json = { version = "1.0.120", features = ["preserve_order"] }
+serde-wasm-bindgen = "0.6.5"
+serde = { version = "1.0.204", features = ["derive"] }
+wasm-bindgen-test = "0.3.45"
diff --git a/dashboard/app/utils/minijinja/README.md b/dashboard/app/utils/minijinja/README.md
new file mode 100644
index 000000000..7c0221ab8
--- /dev/null
+++ b/dashboard/app/utils/minijinja/README.md
@@ -0,0 +1,15 @@
+# WASM Bindings for Minijinja
+
+This crate provides a WASM bindings for the Minijinja templating library.
+
+## Installation
+
+Install `wasm-pack` using the instructions [here](https://rustwasm.github.io/wasm-pack/installer/).
+
+## Building
+
+Run `wasm-pack build` from this directory.
+
+## Testing
+
+Run `wasm-pack test --node` from this directory.
diff --git a/dashboard/app/utils/minijinja/src/lib.rs b/dashboard/app/utils/minijinja/src/lib.rs
new file mode 100644
index 000000000..6d5d51c8d
--- /dev/null
+++ b/dashboard/app/utils/minijinja/src/lib.rs
@@ -0,0 +1,96 @@
+use minijinja::{Environment, UndefinedBehavior};
+
+use std::collections::HashMap;
+use wasm_bindgen::prelude::*;
+
+#[wasm_bindgen]
+pub fn set_panic_hook() {
+    // When the `console_error_panic_hook` feature is enabled, we can call the
+    // `set_panic_hook` function at least once during initialization, and then
+    // we will get better error messages if our code ever panics.
+    //
+    // For more details see
+    // https://github.com/rustwasm/console_error_panic_hook#readme
+    #[cfg(feature = "console_error_panic_hook")]
+    console_error_panic_hook::set_once();
+}
+
+#[wasm_bindgen]
+pub struct JsExposedEnv {
+    env: Environment<'static>,
+}
+
+fn annotate_error(err: minijinja::Error) -> JsError {
+    JsError::new(&format!("{:#}", err))
+}
+
+#[wasm_bindgen]
+impl JsExposedEnv {
+    pub fn render(&self, template: &str, context: JsValue) -> Result<String, JsError> {
+        let tmpl = self.env.get_template(template).map_err(annotate_error)?;
+        let context: serde_json::Value = serde_wasm_bindgen::from_value(context)?;
+        tmpl.render(context).map_err(annotate_error)
+    }
+
+    pub fn has_template(&self, template: &str) -> bool {
+        self.env.get_template(template).is_ok()
+    }
+}
+
+#[wasm_bindgen]
+pub fn create_env(templates: JsValue) -> Result<JsExposedEnv, JsError> {
+    let templates: HashMap<String, String> = serde_wasm_bindgen::from_value(templates)?;
+    let mut env = Environment::new();
+    env.set_undefined_behavior(UndefinedBehavior::Strict);
+    for (name, template) in templates.into_iter() {
+        env.add_template_owned(name, template)
+            .map_err(annotate_error)?;
+    }
+    Ok(JsExposedEnv { env })
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use serde_json::json;
+    use wasm_bindgen_test::*;
+
+    #[wasm_bindgen_test]
+    #[test]
+    fn test_basic_template_rendering() {
+        // Create a simple template environment
+        let templates = HashMap::from([("hello".to_string(), "Hello, {{ name }}!".to_string())]);
+        let js_templates = serde_wasm_bindgen::to_value(&templates).unwrap();
+
+        // Create the environment
+        let env = create_env(js_templates).unwrap();
+
+        // Create the context
+        let context = serde_wasm_bindgen::to_value(&json!({
+            "name": "World"
+        }))
+        .unwrap();
+
+        // Render the template
+        let result = env.render("hello", context).unwrap();
+        assert_eq!(result, "Hello, World!");
+
+        assert!(env.has_template("hello"));
+        assert!(!env.has_template("goodbye"));
+    }
+
+    #[wasm_bindgen_test]
+    #[test]
+    fn test_template_error_handling() {
+        // Test with invalid template syntax
+        let templates = HashMap::from([(
+            "invalid".to_string(),
+            "Hello, {{ invalid syntax }}".to_string(),
+        )]);
+        let js_templates = serde_wasm_bindgen::to_value(&templates).unwrap();
+
+        // Create should fail
+        let env = create_env(js_templates);
+        assert!(env.is_err());
+    }
+}
diff --git a/dashboard/components.json b/dashboard/components.json
new file mode 100644
index 000000000..c80fcadd7
--- /dev/null
+++ b/dashboard/components.json
@@ -0,0 +1,21 @@
+{
+  "$schema": "https://ui.shadcn.com/schema.json",
+  "style": "new-york",
+  "rsc": false,
+  "tsx": true,
+  "tailwind": {
+    "config": "tailwind.config.ts",
+    "css": "app/tailwind.css",
+    "baseColor": "slate",
+    "cssVariables": true,
+    "prefix": ""
+  },
+  "aliases": {
+    "components": "~/components",
+    "utils": "~/lib/utils",
+    "ui": "~/components/ui",
+    "lib": "~/lib",
+    "hooks": "~/hooks"
+  },
+  "iconLibrary": "lucide"
+}
diff --git a/dashboard/eslint.config.js b/dashboard/eslint.config.js
new file mode 100644
index 000000000..48ad99567
--- /dev/null
+++ b/dashboard/eslint.config.js
@@ -0,0 +1,49 @@
+import pluginJs from "@eslint/js";
+import tseslint from "typescript-eslint";
+import pluginReact from "eslint-plugin-react";
+
+export default [
+  {
+    ignores: [
+      "**/minijinja/pkg/",
+      "**/node_modules/**",
+      "**/build/**",
+      "**/.react-router/**",
+      "**/.venv/**",
+    ],
+  },
+  {
+    files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"],
+    plugins: {
+      react: pluginReact,
+    },
+    languageOptions: {
+      globals: {
+        document: true,
+        window: true,
+        process: true,
+        require: true,
+        module: true,
+        __dirname: true,
+        console: true,
+      },
+      parserOptions: {
+        ecmaFeatures: {
+          jsx: true,
+        },
+      },
+    },
+    settings: {
+      react: {
+        version: "detect",
+      },
+    },
+    rules: {
+      "react/jsx-uses-react": "error",
+      "react/jsx-uses-vars": "error",
+      "react/react-in-jsx-scope": "off",
+    },
+  },
+  pluginJs.configs.recommended,
+  ...tseslint.configs.recommended,
+];
diff --git a/dashboard/fixtures/boolean_metric_feedback_examples.csv b/dashboard/fixtures/boolean_metric_feedback_examples.csv
new file mode 100644
index 000000000..c96c39c17
--- /dev/null
+++ b/dashboard/fixtures/boolean_metric_feedback_examples.csv
@@ -0,0 +1,101 @@
+id,target_id,metric_name,value,tags
+0192ced0-b36b-7e93-8fc7-99f9210392f7,0192ced0-b357-7720-839c-b9218b9a249e,dashboard_fixture_exact_match,True,{}
+0192ced0-acfa-77e1-a359-2f677fb949a8,0192ced0-acf0-7053-a102-a3dc88094e54,dashboard_fixture_exact_match,False,{}
+0192ced0-a93e-7ed0-808f-135e1ce2dd32,0192ced0-a937-70d0-82a7-2927e774ea56,dashboard_fixture_exact_match,False,{}
+0192ced0-a9a0-7a82-a66d-c43fdf51b48f,0192ced0-a999-7300-9915-5a01209cd211,dashboard_fixture_exact_match,True,{}
+0192ced0-a830-7e82-96d7-15d7f3b1ae70,0192ced0-a82a-7292-9a1c-5199c69a5ecd,dashboard_fixture_exact_match,False,{}
+0192ced0-a8b7-76e1-bbfa-ddb470b2f8a7,0192ced0-a8b4-7883-bf2e-6eaec5c5431b,dashboard_fixture_exact_match,False,{}
+0192ced0-a956-7b00-b067-0e7c45b6ad16,0192ced0-a94c-7313-ab04-766fc4a82cea,dashboard_fixture_exact_match,False,{}
+0192ced0-a869-7d83-a9be-d4e9971caab1,0192ced0-a860-70d1-8711-b5024aa85647,dashboard_fixture_exact_match,False,{}
+0192ced0-a8a7-7592-b6d0-79b6d6ecf87c,0192ced0-a890-7f70-83de-4aacea6f4807,dashboard_fixture_exact_match,False,{}
+0192ced0-aa42-77a2-ad2e-e8aaf501cfab,0192ced0-aa3c-7900-9a9c-7b467d0170f2,dashboard_fixture_exact_match,False,{}
+0192ced0-a8a4-7472-8a02-d45ad8b75a67,0192ced0-a892-7641-acd5-5eaec649ac95,dashboard_fixture_exact_match,False,{}
+0192ced0-abdd-77b1-a138-5a5f89f39caa,0192ced0-abd4-71c0-9abd-d042951ac83f,dashboard_fixture_exact_match,False,{}
+0192ced0-aab7-7ed1-acba-ce7a43aefc61,0192ced0-aaae-7401-bed2-56a6ba9c8149,dashboard_fixture_exact_match,False,{}
+0192ced0-aa33-7b32-9005-aa38d1c8a06b,0192ced0-aa2e-7410-8d55-d5611abf1b92,dashboard_fixture_exact_match,True,{}
+0192ced0-a8a7-7592-b6d0-79adf0a9716b,0192ced0-a891-7a82-9094-e54a93ab4579,dashboard_fixture_exact_match,False,{}
+0192ced0-a834-7ba2-ac6e-76d5304270e9,0192ced0-a82f-76f2-92b8-5800c421b58f,dashboard_fixture_exact_match,True,{}
+0192ced0-ab18-7d80-9b29-a74975944f89,0192ced0-ab0f-7680-b08d-0c6a5d0e60d2,dashboard_fixture_exact_match,True,{}
+0192ced0-a8b1-7ee1-9c85-5a01ff860e67,0192ced0-a8ae-79d3-81b2-e1cc494d77d7,dashboard_fixture_exact_match,False,{}
+0192ced0-a950-7480-a956-be614c2e6132,0192ced0-a949-7f73-80ef-69e5e99b51cc,dashboard_fixture_exact_match,True,{}
+0192ced0-a9ad-7f20-9e34-201a2bdb2fe1,0192ced0-a9a6-7a92-94c3-b8102bc68217,dashboard_fixture_exact_match,False,{}
+0192ced0-aa2e-7410-8d55-d5706c504fd2,0192ced0-aa28-70a0-9bc8-ab5d193dc8d4,dashboard_fixture_exact_match,False,{}
+0192ced0-aa96-7823-9868-182c962d1479,0192ced0-aa8a-7060-a01f-dbdda0400212,dashboard_fixture_exact_match,True,{}
+0192ced0-a8ad-7b21-9d5b-c816328e40b5,0192ced0-a8aa-7ff3-b253-f9abc6541246,dashboard_fixture_exact_match,True,{}
+0192ced0-a8a9-7201-af34-24702897d237,0192ced0-a89a-7900-9e8b-22b0ec55d905,dashboard_fixture_exact_match,False,{}
+0192ced0-a84f-7490-a104-394bc13a0bcc,0192ced0-a849-7532-b432-9003c7f9c3ea,dashboard_fixture_exact_match,False,{}
+0192ced0-a8a8-76a0-a2e7-d308aac30ff1,0192ced0-a89b-7412-8cf0-454cf309b21c,dashboard_fixture_exact_match,True,{}
+0192ced0-a813-7272-b446-52c0b3116927,0192ced0-a806-7152-b5bc-172cef1830b6,dashboard_fixture_exact_match,False,{}
+0192ced0-a67b-7bf1-91fc-9fdc7c3966f1,0192ced0-a676-7901-b571-32e36cd95af0,dashboard_fixture_exact_match,True,{}
+0192ced0-a6bc-73b0-aa83-843761eaf9b4,0192ced0-a6b5-7df3-9daf-11207b3e7ffc,dashboard_fixture_exact_match,True,{}
+0192ced0-a599-74a1-aa4b-84268b3f4e8c,0192ced0-a595-70d3-b19d-5742e40601fe,dashboard_fixture_exact_match,True,{}
+0192ced0-a602-7733-a98d-dcc9ce1cffe5,0192ced0-a5fb-7e22-8b10-81139dfd51d8,dashboard_fixture_exact_match,True,{}
+0192ced0-a777-7252-9a74-581ddfdd2b5f,0192ced0-a770-7013-a1f4-2fc69dce4472,dashboard_fixture_exact_match,True,{}
+0192ced0-a56d-7e12-8f4a-8ea20bfad2fa,0192ced0-a563-70b0-a322-a5980b7751fb,dashboard_fixture_exact_match,False,{}
+0192ced0-a6a0-7032-968c-3cef46ba3d11,0192ced0-a69c-77d3-9b29-8600004ce895,dashboard_fixture_exact_match,False,{}
+0192ced0-a56b-7e73-90b2-9fe780c992b1,0192ced0-a563-70b0-a322-a5c8f8be41f7,dashboard_fixture_exact_match,False,{}
+0192ced0-a68e-74f3-8543-82e2b842e701,0192ced0-a68a-7b02-ad78-5760c318602d,dashboard_fixture_exact_match,True,{}
+0192ced0-a6bf-76b3-8ca5-ef82e6116e8e,0192ced0-a6b8-7ed2-8478-9ddf36c46c19,dashboard_fixture_exact_match,True,{}
+0192ced0-a5ca-79a1-abd7-cb70360568fe,0192ced0-a5c4-70a1-a569-a5413e44d6a2,dashboard_fixture_exact_match,False,{}
+0192ced0-a667-7320-b24f-b41180d4c512,0192ced0-a663-7703-88b1-f860b8bf5019,dashboard_fixture_exact_match,True,{}
+0192ced0-a544-70f3-9a06-3db8d624f30a,0192ced0-a525-7bd0-a8f7-7db9fa0f055d,dashboard_fixture_exact_match,False,{}
+0192ced0-a77a-7b02-8e91-244f703e3f24,0192ced0-a776-78c3-a9a1-b21698ac07a9,dashboard_fixture_exact_match,False,{}
+0192ced0-a680-7ff0-911d-fa7e16de4d9d,0192ced0-a67c-7df3-987d-e094d4dfc933,dashboard_fixture_exact_match,True,{}
+0192ced0-a664-7a30-84fd-8839694e17c4,0192ced0-a65e-7a41-8f69-fef3d1aa3082,dashboard_fixture_exact_match,False,{}
+0192ced0-a5cb-7b51-b6c3-6941b0a96cdb,0192ced0-a5c7-7670-b9ce-4dc280ba0a1c,dashboard_fixture_exact_match,True,{}
+0192ced0-a665-7181-8087-643e044cc09f,0192ced0-a65e-7a41-8f69-ff5a6e7bc078,dashboard_fixture_exact_match,False,{}
+0192ced0-a663-7703-88b1-f8489c80ea34,0192ced0-a65e-7a41-8f69-ff123d8aa13c,dashboard_fixture_exact_match,True,{}
+0192ced0-a655-7412-9e16-ace1d9393b76,0192ced0-a651-7e10-8d2b-dbf37dfa9440,dashboard_fixture_exact_match,True,{}
+0192ced0-a6a6-7110-8651-531f38bac1d6,0192ced0-a6a2-7731-bc86-81a0a56fc9bf,dashboard_fixture_exact_match,False,{}
+0192ced0-a592-7303-b336-88aa78751bf6,0192ced0-a58e-7d53-bfaa-0e377cde53d3,dashboard_fixture_exact_match,False,{}
+0192ced0-a6b5-7df3-9daf-11418c4b4ad1,0192ced0-a6b0-7e12-93ad-d4f6be12df34,dashboard_fixture_exact_match,False,{}
+0192ced0-a592-7303-b336-889f6bf7049a,0192ced0-a58d-7563-beb1-6292dbea6e70,dashboard_fixture_exact_match,False,{}
+0192ced0-a750-7a31-95e8-a142ef0be2f6,0192ced0-a740-77c3-be1a-667655e77958,dashboard_fixture_exact_match,True,{}
+0192ced0-a750-7a31-95e8-a12ded1f3927,0192ced0-a740-77c3-be1a-664cea1d63c4,dashboard_fixture_exact_match,True,{}
+0192ced0-a750-7a31-95e8-a13e58ad2333,0192ced0-a740-77c3-be1a-6629290d5d90,dashboard_fixture_exact_match,False,{}
+0192ced0-a676-7901-b571-32cda8f4dbea,0192ced0-a672-7f81-9108-d592895419df,dashboard_fixture_exact_match,False,{}
+0192ced0-a5c1-7263-b54d-9702c13baf07,0192ced0-a5bb-7041-bdca-0fce5a9b64eb,dashboard_fixture_exact_match,True,{}
+0192ced0-a547-7650-8581-1c1e8a48a1e6,0192ced0-a538-71f2-bdb6-39796fc7aab6,dashboard_fixture_exact_match,False,{}
+0192ced0-a56f-7de3-b491-8c1938f84beb,0192ced0-a568-7ab2-9079-98e1499ae3d5,dashboard_fixture_exact_match,False,{}
+0192ced0-a605-7091-8c97-de3b6f81750d,0192ced0-a5fe-7590-90c0-b29635f009df,dashboard_fixture_exact_match,False,{}
+0192ced0-a7f3-71d0-9c0c-89bcce44f8bb,0192ced0-a7e8-7b93-bb81-242077f496b3,dashboard_fixture_exact_match,True,{}
+0192ced0-9c62-7b22-9368-ec77a226a3b3,0192ced0-9c5b-7892-a3b7-528745d2fb61,dashboard_fixture_exact_match,True,{}
+0192ced0-9efe-7d20-ade3-04084b77fb19,0192ced0-9ef5-7681-b187-caaa960fcf72,dashboard_fixture_exact_match,False,{}
+0192ced0-9eff-7003-9ffc-24dbedef8220,0192ced0-9ef5-7681-b187-ca89a7143a09,dashboard_fixture_exact_match,False,{}
+0192ced0-9a7c-7023-9957-5b35de635e37,0192ced0-9a71-77a2-b3da-a07f8d7d6921,dashboard_fixture_exact_match,False,{}
+0192ced0-98ca-7781-a38c-d20c061774ab,0192ced0-98ba-7251-9c48-993380d27c11,dashboard_fixture_exact_match,False,{}
+0192ced0-9af4-72c1-821d-ac5bf1a77713,0192ced0-9af0-7381-b318-7ff25f54628b,dashboard_fixture_exact_match,False,{}
+0192ced0-98f5-7c00-beb5-1328317cf4dd,0192ced0-98f0-7b33-9f27-ec6d460e1cc6,dashboard_fixture_exact_match,True,{}
+0192ced0-98c9-7411-8d73-d46d63b1b83f,0192ced0-98ba-7251-9c48-991e27386ce4,dashboard_fixture_exact_match,True,{}
+0192ced0-98ca-7781-a38c-d1f20e9a68dd,0192ced0-98ba-7251-9c48-99033278d090,dashboard_fixture_exact_match,True,{}
+0192ced0-98c7-78f2-b0eb-6059bed51d69,0192ced0-98ba-7251-9c48-98cf94489068,dashboard_fixture_exact_match,True,{}
+0192ced0-999e-7f73-8b47-b3dba302ae86,0192ced0-9998-7050-94e1-169aa33d0656,dashboard_fixture_exact_match,False,{}
+0192ced0-9952-7821-a0f7-d70be25e7ab4,0192ced0-993f-73a3-9fa8-e7f4edfb8c57,dashboard_fixture_exact_match,False,{}
+0192ced0-9c25-7f83-a57f-753d3d45c2ff,0192ced0-9c1d-7261-9c77-ae24df02f4bc,dashboard_fixture_exact_match,False,{}
+0192ced0-9ba2-7fb0-aa3c-b7589230fdb4,0192ced0-9b9b-7323-8d3b-5648b4010991,dashboard_fixture_exact_match,True,{}
+0192ced0-9a2b-7692-9f09-69e3efab404e,0192ced0-9a25-7b42-9531-76bda018fc76,dashboard_fixture_exact_match,False,{}
+0192ced0-9a16-78f3-9435-3f67003d3789,0192ced0-9a12-7fc1-9ffe-12f71a46a9a1,dashboard_fixture_exact_match,False,{}
+0192ced0-98de-7323-bc5a-509113261f5f,0192ced0-98d9-75b1-9cfd-f2431a407070,dashboard_fixture_exact_match,False,{}
+0192ced0-98ca-7781-a38c-d21829cb408d,0192ced0-98bb-7ab1-bbe9-d66735c66b7d,dashboard_fixture_exact_match,True,{}
+0192ced0-99a2-7232-abc3-d51a839ebf90,0192ced0-99a0-7502-9aaf-dc262e960523,dashboard_fixture_exact_match,False,{}
+0192ced0-989b-7850-9e59-c658ffa6e400,0192ced0-9895-7453-85e5-00cdcfbce8e3,dashboard_fixture_exact_match,False,{}
+0192ced0-98c8-7232-a2ae-8d3d63de3f75,0192ced0-98be-7372-94af-c03f07cbcc67,dashboard_fixture_exact_match,True,{}
+0192ced0-9c01-78f2-8ecb-88ebc1a26c59,0192ced0-9bf4-7013-b140-ab528b3dcfa3,dashboard_fixture_exact_match,False,{}
+0192ced0-9b68-73d2-8add-d90d1307734c,0192ced0-9b5d-79f3-8433-5b568580ad3f,dashboard_fixture_exact_match,False,{}
+0192ced0-9b68-73d2-8add-d8f54993e26e,0192ced0-9b5b-7ed0-8426-c80c07cf7063,dashboard_fixture_exact_match,False,{}
+0192ced0-9b9a-7c81-abfc-8dcfe0c59518,0192ced0-9b8e-7871-97b9-47e4e28fdf8a,dashboard_fixture_exact_match,True,{}
+0192ced0-9986-7ab1-a384-8671961f0923,0192ced0-9979-7ae2-ad8d-fd741623846e,dashboard_fixture_exact_match,False,{}
+0192ced0-9880-7f81-bf26-72391b551125,0192ced0-987b-7763-a428-b3ec3a9ea20f,dashboard_fixture_exact_match,True,{}
+0192ced0-9ba9-7303-a158-4be6eae9b158,0192ced0-9ba4-7991-a3eb-144fa1502650,dashboard_fixture_exact_match,False,{}
+0192ced0-9a59-70a3-a800-bafe3994142b,0192ced0-9a51-7bf0-a71a-0b742cbba18f,dashboard_fixture_exact_match,False,{}
+0192ced0-9b65-7713-81ac-341acdd58e93,0192ced0-9b5a-7c11-9a03-3dbca22fa726,dashboard_fixture_exact_match,False,{}
+0192ced0-9954-7701-88c1-54082571ac8c,0192ced0-994a-7093-86bf-53e5efb29816,dashboard_fixture_exact_match,False,{}
+0192ced0-99cf-7a62-87dd-291539c51bbb,0192ced0-99cc-7962-9181-5ce939f765ec,dashboard_fixture_exact_match,True,{}
+0192ced0-9919-78c1-ab51-d6e0dde051ec,0192ced0-9912-7da1-aad1-43a0a6c960fc,dashboard_fixture_exact_match,True,{}
+0192ced0-989c-7a51-9d5b-1675fc68e400,0192ced0-9895-7453-85e5-00ae27921722,dashboard_fixture_exact_match,True,{}
+0192ced0-9952-7821-a0f7-d71d990f1e78,0192ced0-9940-75a3-a7a5-46ecc40fd161,dashboard_fixture_exact_match,False,{}
+0192ced0-9a7e-7c20-b6dc-40b3c267a47a,0192ced0-9a7a-7f82-a1b5-398635c3c76d,dashboard_fixture_exact_match,True,{}
+0192ced0-9950-7662-b71e-22438e67ab97,0192ced0-9940-75a3-a7a5-46c2efc4435f,dashboard_fixture_exact_match,False,{}
+0192ced0-9919-78c1-ab51-d6f1438f8bcc,0192ced0-990c-7b01-af7a-ecbe3fb9983f,dashboard_fixture_exact_match,True,{}
+0192ced0-9877-7571-85b3-7cdff688ac04,0192ced0-9873-70e2-ade5-dc5b8faea232,dashboard_fixture_exact_match,True,{}
+0192ced0-9872-75c2-9bbe-545804d9b103,0192ced0-986c-7621-bf9f-e5377d9f904a,dashboard_fixture_exact_match,False,{}
diff --git a/dashboard/fixtures/config/functions/extract_entities/initial_prompt/system_template.minijinja b/dashboard/fixtures/config/functions/extract_entities/initial_prompt/system_template.minijinja
new file mode 100644
index 000000000..588592a86
--- /dev/null
+++ b/dashboard/fixtures/config/functions/extract_entities/initial_prompt/system_template.minijinja
@@ -0,0 +1,17 @@
+You are an assistant that is performing a named entity recognition task.
+Your job is to extract entities from a given text.
+
+The entities you are extracting are:
+- people
+- organizations
+- locations
+- miscellaneous other entities
+
+Please return the entities in the following JSON format:
+
+{
+    "person": ["person1", "person2", ...],
+    "organization": ["organization1", "organization2", ...],
+    "location": ["location1", "location2", ...],
+    "miscellaneous": ["miscellaneous1", "miscellaneous2", ...]
+}
\ No newline at end of file
diff --git a/dashboard/fixtures/config/output_schema.json b/dashboard/fixtures/config/output_schema.json
new file mode 100644
index 000000000..73e25bc3f
--- /dev/null
+++ b/dashboard/fixtures/config/output_schema.json
@@ -0,0 +1,32 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "type": "object",
+  "properties": {
+    "person": {
+      "type": "array",
+      "items": {
+        "type": "string"
+      }
+    },
+    "organization": {
+      "type": "array",
+      "items": {
+        "type": "string"
+      }
+    },
+    "location": {
+      "type": "array",
+      "items": {
+        "type": "string"
+      }
+    },
+    "miscellaneous": {
+      "type": "array",
+      "items": {
+        "type": "string"
+      }
+    }
+  },
+  "required": ["person", "organization", "location", "miscellaneous"],
+  "additionalProperties": false
+}
diff --git a/dashboard/fixtures/config/tensorzero.toml b/dashboard/fixtures/config/tensorzero.toml
new file mode 100644
index 000000000..6339489a5
--- /dev/null
+++ b/dashboard/fixtures/config/tensorzero.toml
@@ -0,0 +1,31 @@
+# ┌────────────────────────────────────────────────────────────────────────────┐
+# │                                   MODELS                                   │
+# └────────────────────────────────────────────────────────────────────────────┘
+
+[models."gpt-4o-mini-2024-07-18"]
+routing = ["openai"]
+
+[models."gpt-4o-mini-2024-07-18".providers.openai]
+type = "openai"
+model_name = "gpt-4o-mini-2024-07-18"
+
+# ┌────────────────────────────────────────────────────────────────────────────┐
+# │                                 FUNCTIONS                                  │
+# └────────────────────────────────────────────────────────────────────────────┘
+
+[functions.dashboard_fixture_extract_entities]
+type = "json"
+
+[functions.dashboard_fixture_extract_entities.variants.baseline]
+type = "chat_completion"
+model = "gpt-4o-mini-2024-07-18"
+system_template = "functions/extract_entities/initial_prompt/system_template.minijinja"
+
+# ┌────────────────────────────────────────────────────────────────────────────┐
+# │                                  METRICS                                   │
+# └────────────────────────────────────────────────────────────────────────────┘
+
+[metrics.dashboard_fixture_exact_match]
+type = "boolean"
+optimize = "max"
+level = "inference"
diff --git a/dashboard/fixtures/docker-compose.yml b/dashboard/fixtures/docker-compose.yml
new file mode 100644
index 000000000..2ebe95ad2
--- /dev/null
+++ b/dashboard/fixtures/docker-compose.yml
@@ -0,0 +1,68 @@
+services:
+  clickhouse:
+    container_name: tensorzero-clickhouse-dashboard-tests
+    image: clickhouse/clickhouse-server:latest
+    tmpfs:
+      # So the fixtures aren't persisted between restarts of the containers and double-added
+      - /var/lib/clickhouse
+    ports:
+      - "8123:8123" # HTTP port
+      - "9000:9000" # Native port
+    ulimits:
+      nofile:
+        soft: 262144
+        hard: 262144
+    healthcheck:
+      test:
+        [
+          "CMD",
+          "wget",
+          "--no-verbose",
+          "--tries=1",
+          "--spider",
+          "http://localhost:8123/ping",
+        ]
+      start_period: 30s
+      start_interval: 1s
+      timeout: 1s
+
+  gateway:
+    container_name: tensorzero-gateway-dashboard-tests
+    image: tensorzero/gateway
+    volumes:
+      - ./config:/app/config:ro
+    environment:
+      - CLICKHOUSE_URL=http://tensorzero-clickhouse-dashboard-tests:8123/tensorzero
+    env_file:
+      - ${ENV_FILE:-../.env}
+    ports:
+      - "3000:3000"
+    depends_on:
+      clickhouse:
+        condition: service_healthy
+    healthcheck:
+      test:
+        [
+          "CMD",
+          "wget",
+          "--no-verbose",
+          "--tries=1",
+          "--spider",
+          "http://localhost:3000/health",
+        ]
+      start_period: 1s
+      start_interval: 1s
+      timeout: 1s
+
+  fixtures:
+    # NOTE: This is expected to quickly terminate with status code 0
+    container_name: tensorzero-fixtures-dashboard-tests
+    image: clickhouse/clickhouse-server:latest
+    volumes:
+      - .:/fixtures:ro
+    environment:
+      - CLICKHOUSE_HOST=tensorzero-clickhouse-dashboard-tests
+    depends_on:
+      gateway:
+        condition: service_healthy
+    command: ["bash", "-c", "cd /fixtures && ./load_fixtures.sh"]
diff --git a/dashboard/fixtures/json_inference_examples.csv b/dashboard/fixtures/json_inference_examples.csv
new file mode 100644
index 000000000..1dd891695
--- /dev/null
+++ b/dashboard/fixtures/json_inference_examples.csv
@@ -0,0 +1,101 @@
+id,function_name,variant_name,episode_id,input,output,output_schema,inference_params,processing_time_ms
+0192ced0-b357-7720-839c-b9218b9a249e,dashboard_fixture_extract_entities,dicl,0192ced0-a2b6-7083-8c26-c22a78a1b54d,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Natalia Karimova ( Russia ) 3:40.036 beat Yvonne McGregor""}]}]}","{""raw"":""{\""person\"":[\""Natalia Karimova\"",\""Yvonne McGregor\""],\""organization\"":[],\""location\"":[\""Russia\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Natalia Karimova"",""Yvonne McGregor""],""organization"":[],""location"":[""Russia""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",4257
+0192ced0-acf0-7053-a102-a3dc88094e54,dashboard_fixture_extract_entities,dicl,0192ced0-a2b6-7083-8c26-c21399c26e14,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Results of Yugoslav league""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Yugoslav league\""],\""location\"":[],\""miscellaneous\"":[\""Results\""]}"",""parsed"":{""person"":[],""organization"":[""Yugoslav league""],""location"":[],""miscellaneous"":[""Results""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",2618
+0192ced0-abd4-71c0-9abd-d042951ac83f,dashboard_fixture_extract_entities,dicl,0192ced0-a2c6-7323-be23-ce5797732f2d,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""At least 17 miners have been killed in labour unrest -- sparked by ethnic differences -- at Driefontein Consolidated and Gold Fields ' Kloof Gold Mining Co this month .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Driefontein Consolidated\"",\""Gold Fields\"",\""Kloof Gold Mining Co\""],\""location\"":[],\""miscellaneous\"":[\""17\"",\""labour unrest\"",\""ethnic differences\""]}"",""parsed"":{""person"":[],""organization"":[""Driefontein Consolidated"",""Gold Fields"",""Kloof Gold Mining Co""],""location"":[],""miscellaneous"":[""17"",""labour unrest"",""ethnic differences""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",2317
+0192ced0-a89b-7412-8cf0-454cf309b21c,dashboard_fixture_extract_entities,dicl,0192ced0-a2c6-7323-be23-ce2a24429833,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Sjeng Schalken ( Netherlands ) beat David Rikl ( Czech Republic ) 6 - 2 6-4 6-4""}]}]}","{""raw"":""{\""person\"":[\""Sjeng Schalken\"",\""David Rikl\""],\""organization\"":[],\""location\"":[\""Netherlands\"",\""Czech Republic\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Sjeng Schalken"",""David Rikl""],""organization"":[],""location"":[""Netherlands"",""Czech Republic""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1492
+0192ced0-a82f-76f2-92b8-5800c421b58f,dashboard_fixture_extract_entities,turbo,0192ced0-a2c8-7f73-9b38-da82351b91b1,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""287 Ian Woosnam 70 76 71 70""}]}]}","{""raw"":""{\""person\"":[\""Ian Woosnam\""],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Ian Woosnam""],""organization"":[],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1383
+0192ced0-a8b4-7883-bf2e-6eaec5c5431b,dashboard_fixture_extract_entities,turbo,0192ced0-a2c8-7f73-9b38-da93002b1a4c,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Sjeng Schalken ( Netherlands ) beat David Rikl ( Czech Republic ) 6 - 2 6-4 6-4""}]}]}","{""raw"":""{\""person\"":[\""Sjeng Schalken\"",\""David Rikl\""],\""organization\"":[],\""location\"":[\""Netherlands\""],\""miscellaneous\"":[\""Czech Republic\""]}"",""parsed"":{""person"":[""Sjeng Schalken"",""David Rikl""],""organization"":[],""location"":[""Netherlands""],""miscellaneous"":[""Czech Republic""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1515
+0192ced0-a8aa-7ff3-b253-f9abc6541246,dashboard_fixture_extract_entities,dicl,0192ced0-a2b5-7d90-a4b7-eac823d55636,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""9. Mauricio Gugelmin ( Brazil ) , Reynard Ford Cosworth , 54.762""}]}]}","{""raw"":""{\""person\"":[\""Mauricio Gugelmin\""],\""organization\"":[\""Reynard Ford Cosworth\""],\""location\"":[\""Brazil\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Mauricio Gugelmin""],""organization"":[""Reynard Ford Cosworth""],""location"":[""Brazil""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1524
+0192ced0-a8ae-79d3-81b2-e1cc494d77d7,dashboard_fixture_extract_entities,dicl,0192ced0-a2b5-7d90-a4b7-eab3047b7229,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Boatmen 's was the prize in Missouri , where barriers to outside acquirers were brought down last year by a federal banking statute .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Boatmen's\""],\""location\"":[\""Missouri\""],\""miscellaneous\"":[\""federal banking statute\""]}"",""parsed"":{""person"":[],""organization"":[""Boatmen's""],""location"":[""Missouri""],""miscellaneous"":[""federal banking statute""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1529
+0192ced0-a89a-7900-9e8b-22b0ec55d905,dashboard_fixture_extract_entities,turbo,0192ced0-a2c7-7c83-96e1-bdd0889187cc,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""A Polish consortium including the Bank Rozwoju Exportu SA ( BRE ) plans to rival France 's Hachette in bidding for Polish state-owned press distribution chain Ruch SA , Zycie Warszawy daily said on Saturday .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Bank Rozwoju Exportu SA ( BRE )\"",\""Ruch SA\"",\""Zycie Warszawy\""],\""location\"":[\""France\""],\""miscellaneous\"":[\""Polish\"",\""Polish\""]}"",""parsed"":{""person"":[],""organization"":[""Bank Rozwoju Exportu SA ( BRE )"",""Ruch SA"",""Zycie Warszawy""],""location"":[""France""],""miscellaneous"":[""Polish"",""Polish""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1491
+0192ced0-aa2e-7410-8d55-d5611abf1b92,dashboard_fixture_extract_entities,dicl,0192ced0-a2c7-7c83-96e1-bdb9a47cf559,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Brechin 3 0 3 0 2 2 3""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Brechin\""],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[""Brechin""],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1895
+0192ced0-a849-7532-b432-9003c7f9c3ea,dashboard_fixture_extract_entities,dicl,0192ced0-a2b0-7be1-afe6-50c2f355f99d,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Adams and Platt are both injured and will miss England 's opening World Cup qualifier against Moldova on Sunday .""}]}]}","{""raw"":""{\""person\"":[\""Adams\"",\""Platt\""],\""organization\"":[\""World Cup\""],\""location\"":[\""England\"",\""Moldova\""],\""miscellaneous\"":[\""opening qualifier\"",\""Sunday\""]}"",""parsed"":{""person"":[""Adams"",""Platt""],""organization"":[""World Cup""],""location"":[""England"",""Moldova""],""miscellaneous"":[""opening qualifier"",""Sunday""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1432
+0192ced0-a949-7f73-80ef-69e5e99b51cc,dashboard_fixture_extract_entities,dicl,0192ced0-a2b0-7be1-afe6-50d37d5a3cb7,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""One out later , Gonzalez smacked his 40th homer , extending his hitting streak to 20 games .""}]}]}","{""raw"":""{\""person\"":[\""Gonzalez\""],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Gonzalez""],""organization"":[],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1689
+0192ced0-a890-7f70-83de-4aacea6f4807,dashboard_fixture_extract_entities,turbo,0192ced0-a2c6-7323-be23-cd8b5784adec,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""At least 17 miners have been killed in labour unrest -- sparked by ethnic differences -- at Driefontein Consolidated and Gold Fields ' Kloof Gold Mining Co this month .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Gold Fields ' Kloof Gold Mining Co\""],\""location\"":[\""Driefontein Consolidated\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[""Gold Fields ' Kloof Gold Mining Co""],""location"":[""Driefontein Consolidated""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1482
+0192ced0-a860-70d1-8711-b5024aa85647,dashboard_fixture_extract_entities,dicl,0192ced0-a2af-7ec0-be0c-926a4c21e5a8,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""The reports fanned worries on Wall Street that the Fed , the nation 's central bank , would raise rates next month in a bid to ward off inflation , driving stock and bond prices sharply lower for a second day running .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Fed\""],\""location\"":[\""Wall Street\""],\""miscellaneous\"":[\""inflation\""]}"",""parsed"":{""person"":[],""organization"":[""Fed""],""location"":[""Wall Street""],""miscellaneous"":[""inflation""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1456
+0192ced0-a94c-7313-ab04-766fc4a82cea,dashboard_fixture_extract_entities,baseline,0192ced0-a2ae-75f2-b3d4-d27b8c72da7f,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Results of Yugoslav league""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Yugoslav league\""],\""location\"":[\""Yugoslavia\""],\""miscellaneous\"":[\""results\""]}"",""parsed"":{""person"":[],""organization"":[""Yugoslav league""],""location"":[""Yugoslavia""],""miscellaneous"":[""results""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1694
+0192ced0-a891-7a82-9094-e54a93ab4579,dashboard_fixture_extract_entities,dicl,0192ced0-a2c6-7323-be23-cd35113264b5,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" Last year we stood on the court after we had lost and we put out hands together and made it our committment to bring back the Cup , \"" U.S. captain Billie Jean King said at the draw . \""""}]}]}","{""raw"":""{\""person\"":[\""Billie Jean King\""],\""organization\"":[\""U.S.\""],\""location\"":[],\""miscellaneous\"":[\""Cup\""]}"",""parsed"":{""person"":[""Billie Jean King""],""organization"":[""U.S.""],""location"":[],""miscellaneous"":[""Cup""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1483
+0192ced0-ab0f-7680-b08d-0c6a5d0e60d2,dashboard_fixture_extract_entities,dicl,0192ced0-a2c6-7323-be23-cdc9057a9534,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" I told Monica we need her if we want to win , \"" King said .""}]}]}","{""raw"":""{\""person\"":[\""Monica\"",\""King\""],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Monica"",""King""],""organization"":[],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",2121
+0192ced0-aaae-7401-bed2-56a6ba9c8149,dashboard_fixture_extract_entities,dicl,0192ced0-a2c6-7323-be23-cdec737392ee,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" The worst thing that could happen for financial markets is that if Clinton and Dole start to trade shots in the middle of the ring with one-upmanship , \"" said Hugh Johnson , chief investment officer at First Albany Corp. \"" That 's when Wall Street will need to worry . \""""}]}]}","{""raw"":""{\""person\"":[\""Clinton\"",\""Dole\"",\""Hugh Johnson\""],\""organization\"":[\""First Albany Corp\""],\""location\"":[],\""miscellaneous\"":[\""Wall Street\""]}"",""parsed"":{""person"":[""Clinton"",""Dole"",""Hugh Johnson""],""organization"":[""First Albany Corp""],""location"":[],""miscellaneous"":[""Wall Street""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",2024
+0192ced0-aa28-70a0-9bc8-ab5d193dc8d4,dashboard_fixture_extract_entities,baseline,0192ced0-a2ae-75f2-b3d4-d29ce1631ab9,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""At least 17 miners have been killed in labour unrest -- sparked by ethnic differences -- at Driefontein Consolidated and Gold Fields ' Kloof Gold Mining Co this month .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Driefontein Consolidated\"",\""Gold Fields\"",\""Kloof Gold Mining Co\""],\""location\"":[],\""miscellaneous\"":[\""17 miners\"",\""labour unrest\"",\""ethnic differences\""]}"",""parsed"":{""person"":[],""organization"":[""Driefontein Consolidated"",""Gold Fields"",""Kloof Gold Mining Co""],""location"":[],""miscellaneous"":[""17 miners"",""labour unrest"",""ethnic differences""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1913
+0192ced0-a9a6-7a92-94c3-b8102bc68217,dashboard_fixture_extract_entities,dicl,0192ced0-a2c6-7323-be23-cdf8a23752c0,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""But on Saturday the people gathered just outside the town seemed to be united in favour of the separatists .""}]}]}","{""raw"":""{\""person\"":[\""the people\""],\""organization\"":[\""separatists\""],\""location\"":[\""the town\""],\""miscellaneous\"":[\""Saturday\""]}"",""parsed"":{""person"":[""the people""],""organization"":[""separatists""],""location"":[""the town""],""miscellaneous"":[""Saturday""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1760
+0192ced0-aa8a-7060-a01f-dbdda0400212,dashboard_fixture_extract_entities,dicl,0192ced0-a2b6-7083-8c26-c20166f26756,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""287 Ian Woosnam 70 76 71 70""}]}]}","{""raw"":""{\""person\"":[\""Ian Woosnam\""],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Ian Woosnam""],""organization"":[],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",2004
+0192ced0-aa3c-7900-9a9c-7b467d0170f2,dashboard_fixture_extract_entities,baseline,0192ced0-a2a8-71b0-a24c-2e06cc086df3,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""A Polish consortium including the Bank Rozwoju Exportu SA ( BRE ) plans to rival France 's Hachette in bidding for Polish state-owned press distribution chain Ruch SA , Zycie Warszawy daily said on Saturday .""}]}]}","{""raw"":""{\n    \""person\"": [],\n    \""organization\"": [\""Bank Rozwoju Exportu SA\"", \""Hachette\"", \""Ruch SA\"", \""Zycie Warszawy\""],\n    \""location\"": [\""Poland\"", \""France\""],\n    \""miscellaneous\"": [\""consortium\"", \""bidding\"", \""state-owned press distribution chain\""]\n}"",""parsed"":{""person"":[],""organization"":[""Bank Rozwoju Exportu SA"",""Hachette"",""Ruch SA"",""Zycie Warszawy""],""location"":[""Poland"",""France""],""miscellaneous"":[""consortium"",""bidding"",""state-owned press distribution chain""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1939
+0192ced0-a892-7641-acd5-5eaec649ac95,dashboard_fixture_extract_entities,dicl,0192ced0-a2c9-7dc3-8865-44cb3190e889,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""We have in no way seen any Iraqi troops in the city or in its approaches , \"" a U.N. relief official told Reuters .""}]}]}","{""raw"":""{\""person\"":[\""U.N. relief official\""],\""organization\"":[\""U.N.\"",\""Reuters\""],\""location\"":[\""Iraqi\"",\""city\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""U.N. relief official""],""organization"":[""U.N."",""Reuters""],""location"":[""Iraqi"",""city""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1482
+0192ced0-a937-70d0-82a7-2927e774ea56,dashboard_fixture_extract_entities,dicl,0192ced0-a2c9-7dc3-8865-44b120deef94,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""A Polish consortium including the Bank Rozwoju Exportu SA ( BRE ) plans to rival France 's Hachette in bidding for Polish state-owned press distribution chain Ruch SA , Zycie Warszawy daily said on Saturday .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Bank Rozwoju Exportu SA\"",\""BRE\"",\""Hachette\"",\""Ruch SA\"",\""Zycie Warszawy\""],\""location\"":[\""Poland\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[""Bank Rozwoju Exportu SA"",""BRE"",""Hachette"",""Ruch SA"",""Zycie Warszawy""],""location"":[""Poland""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1646
+0192ced0-a82a-7292-9a1c-5199c69a5ecd,dashboard_fixture_extract_entities,baseline,0192ced0-a2c6-7323-be23-cddc90847977,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""6. Oksana Grichina ( Russia ) 36.242""}]}]}","{""raw"":""{\n    \""person\"": [\""Oksana Grichina\""],\n    \""organization\"": [],\n    \""location\"": [\""Russia\""],\n    \""miscellaneous\"": [\""36.242\""]\n}"",""parsed"":{""person"":[""Oksana Grichina""],""organization"":[],""location"":[""Russia""],""miscellaneous"":[""36.242""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1380
+0192ced0-a999-7300-9915-5a01209cd211,dashboard_fixture_extract_entities,dicl,0192ced0-a2c6-7323-be23-ce66bf0ae2aa,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""6. Oksana Grichina ( Russia ) 36.242""}]}]}","{""raw"":""{\""person\"":[\""Oksana Grichina\""],\""organization\"":[],\""location\"":[\""Russia\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Oksana Grichina""],""organization"":[],""location"":[""Russia""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1746
+0192ced0-a563-70b0-a322-a5980b7751fb,dashboard_fixture_extract_entities,baseline,0192ced0-a2c6-7323-be23-ce38b01e63ed,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Brechin 3 0 3 0 2 2 3""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""Brechin\""],\""miscellaneous\"":[\""3\"",\""0\"",\""2\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""Brechin""],""miscellaneous"":[""3"",""0"",""2""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",668
+0192ced0-a672-7f81-9108-d592895419df,dashboard_fixture_extract_entities,baseline,0192ced0-a2a4-77a2-a7fa-1e8843925b29,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" We expect the international community to take a clear and firm position , based on international law and in accordance with U.N. resolutions , against all such Israeli violations and illegal practices , \"" he said .""}]}]}","{""raw"":""{\n    \""person\"": [],\n    \""organization\"": [\""U.N.\""],\n    \""location\"": [\""Israeli\""],\n    \""miscellaneous\"": [\""international community\"", \""international law\"", \""U.N. resolutions\"", \""Israeli violations\"", \""illegal practices\""]\n}"",""parsed"":{""person"":[],""organization"":[""U.N.""],""location"":[""Israeli""],""miscellaneous"":[""international community"",""international law"",""U.N. resolutions"",""Israeli violations"",""illegal practices""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",973
+0192ced0-a538-71f2-bdb6-39796fc7aab6,dashboard_fixture_extract_entities,baseline,0192ced0-a2c6-7323-be23-cdbf669b1cb0,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Boatmen 's was the prize in Missouri , where barriers to outside acquirers were brought down last year by a federal banking statute .""}]}]}","{""raw"":""{\n    \""person\"": [],\n    \""organization\"": [],\n    \""location\"": [\""Missouri\""],\n    \""miscellaneous\"": [\""federal banking statute\""]\n}"",""parsed"":{""person"":[],""organization"":[],""location"":[""Missouri""],""miscellaneous"":[""federal banking statute""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",626
+0192ced0-a58d-7563-beb1-6292dbea6e70,dashboard_fixture_extract_entities,baseline,0192ced0-a2c6-7323-be23-cd743a32da9c,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""One out later , Gonzalez smacked his 40th homer , extending his hitting streak to 20 games .""}]}]}","{""raw"":""{\""person\"":[\""Gonzalez\""],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[\""40th homer\"",\""20 games\""]}"",""parsed"":{""person"":[""Gonzalez""],""organization"":[],""location"":[],""miscellaneous"":[""40th homer"",""20 games""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",711
+0192ced0-a740-77c3-be1a-6629290d5d90,dashboard_fixture_extract_entities,baseline,0192ced0-a2c6-7323-be23-cd4f90cd6490,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""We have in no way seen any Iraqi troops in the city or in its approaches , \"" a U.N. relief official told Reuters .""}]}]}","{""raw"":""{\n    \""person\"": [\""U.N. relief official\""],\n    \""organization\"": [\""Reuters\""],\n    \""location\"": [\""Iraq\"", \""the city\""],\n    \""miscellaneous\"": []\n}"",""parsed"":{""person"":[""U.N. relief official""],""organization"":[""Reuters""],""location"":[""Iraq"",""the city""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1146
+0192ced0-a58e-7d53-bfaa-0e377cde53d3,dashboard_fixture_extract_entities,baseline,0192ced0-a2a0-79d2-a02a-b5b5d8987eda,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""The reports fanned worries on Wall Street that the Fed , the nation 's central bank , would raise rates next month in a bid to ward off inflation , driving stock and bond prices sharply lower for a second day running .""}]}]}","{""raw"":""{\n    \""person\"": [],\n    \""organization\"": [\""Fed\"", \""Wall Street\""],\n    \""location\"": [],\n    \""miscellaneous\"": [\""central bank\"", \""inflation\"", \""stock\"", \""bond prices\""]\n}"",""parsed"":{""person"":[],""organization"":[""Fed"",""Wall Street""],""location"":[],""miscellaneous"":[""central bank"",""inflation"",""stock"",""bond prices""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",750
+0192ced0-a5c4-70a1-a569-a5413e44d6a2,dashboard_fixture_extract_entities,baseline,0192ced0-a2af-7ec0-be0c-925f7560b339,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" The worst thing that could happen for financial markets is that if Clinton and Dole start to trade shots in the middle of the ring with one-upmanship , \"" said Hugh Johnson , chief investment officer at First Albany Corp. \"" That 's when Wall Street will need to worry . \""""}]}]}","{""raw"":""{\n    \""person\"": [\""Clinton\"", \""Dole\"", \""Hugh Johnson\""],\n    \""organization\"": [\""First Albany Corp\""],\n    \""location\"": [\""Wall Street\""],\n    \""miscellaneous\"": [\""financial markets\"", \""one-upmanship\""]\n}"",""parsed"":{""person"":[""Clinton"",""Dole"",""Hugh Johnson""],""organization"":[""First Albany Corp""],""location"":[""Wall Street""],""miscellaneous"":[""financial markets"",""one-upmanship""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",788
+0192ced0-a6b0-7e12-93ad-d4f6be12df34,dashboard_fixture_extract_entities,baseline,0192ced0-a2b3-77d0-90c6-cdfb5b71daaf,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Adams and Platt are both injured and will miss England 's opening World Cup qualifier against Moldova on Sunday .""}]}]}","{""raw"":""{\n    \""person\"": [\""Adams\"", \""Platt\""],\n    \""organization\"": [\""England\""],\n    \""location\"": [\""Moldova\""],\n    \""miscellaneous\"": [\""World Cup qualifier\"", \""Sunday\""]\n}"",""parsed"":{""person"":[""Adams"",""Platt""],""organization"":[""England""],""location"":[""Moldova""],""miscellaneous"":[""World Cup qualifier"",""Sunday""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1021
+0192ced0-a676-7901-b571-32e36cd95af0,dashboard_fixture_extract_entities,turbo,0192ced0-a2c7-7c83-96e1-be14a1ecbaac,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""One out later , Gonzalez smacked his 40th homer , extending his hitting streak to 20 games .""}]}]}","{""raw"":""{\""person\"":[\""Gonzalez\""],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Gonzalez""],""organization"":[],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",943
+0192ced0-a568-7ab2-9079-98e1499ae3d5,dashboard_fixture_extract_entities,baseline,0192ced0-a2af-7ec0-be0c-92480cc23e9e,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Southend 1 Swindon 3""}]}]}","{""raw"":""{\n    \""person\"": [],\n    \""organization\"": [],\n    \""location\"": [\""Southend\"", \""Swindon\""],\n    \""miscellaneous\"": []\n}"",""parsed"":{""person"":[],""organization"":[],""location"":[""Southend"",""Swindon""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",697
+0192ced0-a595-70d3-b19d-5742e40601fe,dashboard_fixture_extract_entities,baseline,0192ced0-a2ae-75f2-b3d4-d286e486f1d4,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Sjeng Schalken ( Netherlands ) beat David Rikl ( Czech Republic ) 6 - 2 6-4 6-4""}]}]}","{""raw"":""{\n    \""person\"": [\""Sjeng Schalken\"", \""David Rikl\""],\n    \""organization\"": [],\n    \""location\"": [\""Netherlands\"", \""Czech Republic\""],\n    \""miscellaneous\"": []\n}"",""parsed"":{""person"":[""Sjeng Schalken"",""David Rikl""],""organization"":[],""location"":[""Netherlands"",""Czech Republic""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",743
+0192ced0-a770-7013-a1f4-2fc69dce4472,dashboard_fixture_extract_entities,turbo,0192ced0-a2c6-7323-be23-cd21b7b4f97f,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""9. Mauricio Gugelmin ( Brazil ) , Reynard Ford Cosworth , 54.762""}]}]}","{""raw"":""{\""person\"":[\""Mauricio Gugelmin\""],\""organization\"":[\""Reynard Ford Cosworth\""],\""location\"":[\""Brazil\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Mauricio Gugelmin""],""organization"":[""Reynard Ford Cosworth""],""location"":[""Brazil""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1194
+0192ced0-a776-78c3-a9a1-b21698ac07a9,dashboard_fixture_extract_entities,turbo,0192ced0-a2c6-7323-be23-cd5e0b623357,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" The worst thing that could happen for financial markets is that if Clinton and Dole start to trade shots in the middle of the ring with one-upmanship , \"" said Hugh Johnson , chief investment officer at First Albany Corp. \"" That 's when Wall Street will need to worry . \""""}]}]}","{""raw"":""{\""person\"":[\""Clinton\"",\""Dole\"",\""Hugh Johnson\""],\""organization\"":[\""Wall Street\"",\""First Albany Corp.\""],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Clinton"",""Dole"",""Hugh Johnson""],""organization"":[""Wall Street"",""First Albany Corp.""],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1199
+0192ced0-a5bb-7041-bdca-0fce5a9b64eb,dashboard_fixture_extract_entities,baseline,0192ced0-a2c9-7dc3-8865-44a2b090607b,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" I told Monica we need her if we want to win , \"" King said .""}]}]}","{""raw"":""{\n    \""person\"": [\""Monica\"", \""King\""],\n    \""organization\"": [],\n    \""location\"": [],\n    \""miscellaneous\"": []\n}"",""parsed"":{""person"":[""Monica"",""King""],""organization"":[],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",754
+0192ced0-a740-77c3-be1a-667655e77958,dashboard_fixture_extract_entities,turbo,0192ced0-a2c6-7323-be23-cd6fd27bfa59,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Natalia Karimova ( Russia ) 3:40.036 beat Yvonne McGregor""}]}]}","{""raw"":""{\""person\"":[\""Natalia Karimova\"",\""Yvonne McGregor\""],\""organization\"":[],\""location\"":[\""Russia\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Natalia Karimova"",""Yvonne McGregor""],""organization"":[],""location"":[""Russia""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1146
+0192ced0-a7e8-7b93-bb81-242077f496b3,dashboard_fixture_extract_entities,dicl,0192ced0-a2b9-7e93-b3cd-cfa552758353,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Southend 1 Swindon 3""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Southend\"",\""Swindon\""],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[""Southend"",""Swindon""],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1326
+0192ced0-a65e-7a41-8f69-fef3d1aa3082,dashboard_fixture_extract_entities,turbo,0192ced0-a2c6-7323-be23-cd96b8dd8bf1,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" I told Monica we need her if we want to win , \"" King said .""}]}]}","{""raw"":""{\""person\"":[\""Monica\""],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Monica""],""organization"":[],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",919
+0192ced0-a740-77c3-be1a-664cea1d63c4,dashboard_fixture_extract_entities,turbo,0192ced0-a2c5-7e21-97da-46f63636f008,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Adams and Platt are both injured and will miss England 's opening World Cup qualifier against Moldova on Sunday .""}]}]}","{""raw"":""{\""person\"":[\""Adams\"",\""Platt\""],\""organization\"":[],\""location\"":[\""England\"",\""Moldova\""],\""miscellaneous\"":[\""World Cup\""]}"",""parsed"":{""person"":[""Adams"",""Platt""],""organization"":[],""location"":[""England"",""Moldova""],""miscellaneous"":[""World Cup""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1146
+0192ced0-a69c-77d3-9b29-8600004ce895,dashboard_fixture_extract_entities,turbo,0192ced0-a2c6-7323-be23-cda6b152e398,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" We expect the international community to take a clear and firm position , based on international law and in accordance with U.N. resolutions , against all such Israeli violations and illegal practices , \"" he said .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""U.N.\""],\""location\"":[\""Israeli\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[""U.N.""],""location"":[""Israeli""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",982
+0192ced0-a5c7-7670-b9ce-4dc280ba0a1c,dashboard_fixture_extract_entities,baseline,0192ced0-a2c7-7c83-96e1-bdcaf1460b49,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Natalia Karimova ( Russia ) 3:40.036 beat Yvonne McGregor""}]}]}","{""raw"":""{\n    \""person\"": [\""Natalia Karimova\"", \""Yvonne McGregor\""],\n    \""organization\"": [],\n    \""location\"": [\""Russia\""],\n    \""miscellaneous\"": []\n}"",""parsed"":{""person"":[""Natalia Karimova"",""Yvonne McGregor""],""organization"":[],""location"":[""Russia""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",768
+0192ced0-a65e-7a41-8f69-ff123d8aa13c,dashboard_fixture_extract_entities,turbo,0192ced0-a2c7-7c83-96e1-bdacce06b6e6,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Brechin 3 0 3 0 2 2 3""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Brechin\""],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[""Brechin""],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",918
+0192ced0-a5fe-7590-90c0-b29635f009df,dashboard_fixture_extract_entities,baseline,0192ced0-a2ac-7450-86f2-1d82fea5d958,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""9. Mauricio Gugelmin ( Brazil ) , Reynard Ford Cosworth , 54.762""}]}]}","{""raw"":""{\n    \""person\"": [\""Mauricio Gugelmin\""],\n    \""organization\"": [\""Reynard Ford Cosworth\""],\n    \""location\"": [\""Brazil\""],\n    \""miscellaneous\"": [\""54.762\""]\n}"",""parsed"":{""person"":[""Mauricio Gugelmin""],""organization"":[""Reynard Ford Cosworth""],""location"":[""Brazil""],""miscellaneous"":[""54.762""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",850
+0192ced0-a651-7e10-8d2b-dbf37dfa9440,dashboard_fixture_extract_entities,turbo,0192ced0-a2c6-7323-be23-ce0171b11a17,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""But on Saturday the people gathered just outside the town seemed to be united in favour of the separatists .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",906
+0192ced0-a806-7152-b5bc-172cef1830b6,dashboard_fixture_extract_entities,dicl,0192ced0-a2c7-7c83-96e1-be242a4ff8cb,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" We expect the international community to take a clear and firm position , based on international law and in accordance with U.N. resolutions , against all such Israeli violations and illegal practices , \"" he said .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""U.N.\""],\""location\"":[],\""miscellaneous\"":[\""international community\"",\""Israeli violations\"",\""illegal practices\""]}"",""parsed"":{""person"":[],""organization"":[""U.N.""],""location"":[],""miscellaneous"":[""international community"",""Israeli violations"",""illegal practices""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1342
+0192ced0-a6b5-7df3-9daf-11207b3e7ffc,dashboard_fixture_extract_entities,turbo,0192ced0-a2c6-7323-be23-ce1897dfcb38,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""6. Oksana Grichina ( Russia ) 36.242""}]}]}","{""raw"":""{\""person\"":[\""Oksana Grichina\""],\""organization\"":[],\""location\"":[\""Russia\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Oksana Grichina""],""organization"":[],""location"":[""Russia""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1006
+0192ced0-a6a2-7731-bc86-81a0a56fc9bf,dashboard_fixture_extract_entities,turbo,0192ced0-a2c7-7c83-96e1-bdf3217908ca,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" Last year we stood on the court after we had lost and we put out hands together and made it our committment to bring back the Cup , \"" U.S. captain Billie Jean King said at the draw . \""""}]}]}","{""raw"":""{\""person\"":[\""Billie Jean King\""],\""organization\"":[],\""location\"":[\""U.S.\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Billie Jean King""],""organization"":[],""location"":[""U.S.""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",986
+0192ced0-a6b8-7ed2-8478-9ddf36c46c19,dashboard_fixture_extract_entities,turbo,0192ced0-a2c8-7f73-9b38-da79e548e53c,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Southend 1 Swindon 3""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Southend\"",\""Swindon\""],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[""Southend"",""Swindon""],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1008
+0192ced0-a65e-7a41-8f69-ff5a6e7bc078,dashboard_fixture_extract_entities,turbo,0192ced0-a2c7-7c83-96e1-be030ddc03ca,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Boatmen 's was the prize in Missouri , where barriers to outside acquirers were brought down last year by a federal banking statute .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""Missouri\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""Missouri""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",918
+0192ced0-a68a-7b02-ad78-5760c318602d,dashboard_fixture_extract_entities,turbo,0192ced0-a2c6-7323-be23-ce4124e683d3,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""We have in no way seen any Iraqi troops in the city or in its approaches , \"" a U.N. relief official told Reuters .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""U.N.\"",\""Reuters\""],\""location\"":[],\""miscellaneous\"":[\""Iraqi\""]}"",""parsed"":{""person"":[],""organization"":[""U.N."",""Reuters""],""location"":[],""miscellaneous"":[""Iraqi""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",964
+0192ced0-a525-7bd0-a8f7-7db9fa0f055d,dashboard_fixture_extract_entities,baseline,0192ced0-a2aa-7d01-a66f-6433ff68db90,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""But on Saturday the people gathered just outside the town seemed to be united in favour of the separatists .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""town\""],\""miscellaneous\"":[\""separatists\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""town""],""miscellaneous"":[""separatists""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",635
+0192ced0-a5fb-7e22-8b10-81139dfd51d8,dashboard_fixture_extract_entities,baseline,0192ced0-a2c7-7c83-96e1-bdec0d19cf59,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" Last year we stood on the court after we had lost and we put out hands together and made it our committment to bring back the Cup , \"" U.S. captain Billie Jean King said at the draw . \""""}]}]}","{""raw"":""{\""person\"":[\""Billie Jean King\""],\""organization\"":[],\""location\"":[\""U.S.\""],\""miscellaneous\"":[\""Cup\""]}"",""parsed"":{""person"":[""Billie Jean King""],""organization"":[],""location"":[""U.S.""],""miscellaneous"":[""Cup""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",819
+0192ced0-a67c-7df3-987d-e094d4dfc933,dashboard_fixture_extract_entities,turbo,0192ced0-a2c8-7f73-9b38-daafd7e8dc7b,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Results of Yugoslav league""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[\""Yugoslav\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[],""miscellaneous"":[""Yugoslav""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",947
+0192ced0-a563-70b0-a322-a5c8f8be41f7,dashboard_fixture_extract_entities,baseline,0192ced0-a2ad-7d52-b383-684d7527c8a4,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""287 Ian Woosnam 70 76 71 70""}]}]}","{""raw"":""{\""person\"":[\""Ian Woosnam\""],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[\""287\"",\""70\"",\""76\"",\""71\""]}"",""parsed"":{""person"":[""Ian Woosnam""],""organization"":[],""location"":[],""miscellaneous"":[""287"",""70"",""76"",""71""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",693
+0192ced0-a663-7703-88b1-f860b8bf5019,dashboard_fixture_extract_entities,turbo,0192ced0-a2c6-7323-be23-ce7f39c0f76d,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""The reports fanned worries on Wall Street that the Fed , the nation 's central bank , would raise rates next month in a bid to ward off inflation , driving stock and bond prices sharply lower for a second day running .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Fed\""],\""location\"":[\""Wall Street\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[""Fed""],""location"":[""Wall Street""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",925
+0192ced0-9c5b-7892-a3b7-528745d2fb61,dashboard_fixture_extract_entities,dicl,0192ced0-9487-7c42-a0e9-3914a74eb32b,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Brown threw 119 pitches and won for the third time in as many starts against the Reds this season .""}]}]}","{""raw"":""{\""person\"":[\""Brown\""],\""organization\"":[\""Reds\""],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Brown""],""organization"":[""Reds""],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",2004
+0192ced0-9ef5-7681-b187-caaa960fcf72,dashboard_fixture_extract_entities,dicl,0192ced0-949e-71e3-965b-2835264cad0a,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""That followed a revised 0.7 percent decline in June orders .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[\""0.7 percent decline\"",\""June orders\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[],""miscellaneous"":[""0.7 percent decline"",""June orders""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",2647
+0192ced0-9ef5-7681-b187-ca89a7143a09,dashboard_fixture_extract_entities,dicl,0192ced0-949d-7063-900d-a4bd1065600b,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""We often see people dressed in military-style clothing here , \"" he said .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[\""military-style clothing\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[],""miscellaneous"":[""military-style clothing""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",2647
+0192ced0-9a7a-7f82-a1b5-398635c3c76d,dashboard_fixture_extract_entities,dicl,0192ced0-948b-7ed0-a104-7981cc98423e,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""SOCCER - AUSTRIA DOMINATE SCOTLAND IN WORLD CUP QUALIFIER .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""Austria\"",\""Scotland\""],\""miscellaneous\"":[\""World Cup\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""Austria"",""Scotland""],""miscellaneous"":[""World Cup""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1518
+0192ced0-9a71-77a2-b3da-a07f8d7d6921,dashboard_fixture_extract_entities,dicl,0192ced0-9486-7491-9b60-42dd2ef9194e,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Cofinec , the first foreign company to list on the Budapest bourse , released its consolidated first half figures ( IAS ) this morning .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Cofinec\""],\""location\"":[\""Budapest\""],\""miscellaneous\"":[\""first foreign company\"",\""consolidated first half figures\"",\""IAS\""]}"",""parsed"":{""person"":[],""organization"":[""Cofinec""],""location"":[""Budapest""],""miscellaneous"":[""first foreign company"",""consolidated first half figures"",""IAS""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1514
+0192ced0-9b8e-7871-97b9-47e4e28fdf8a,dashboard_fixture_extract_entities,dicl,0192ced0-9496-71d1-9722-cf5de87c845f,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Mark Philippoussis ( Australia ) beat Andrei Olhovskiy ( Russia ) 6 - 3 6-4 6-2""}]}]}","{""raw"":""{\""person\"":[\""Mark Philippoussis\"",\""Andrei Olhovskiy\""],\""organization\"":[],\""location\"":[\""Australia\"",\""Russia\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Mark Philippoussis"",""Andrei Olhovskiy""],""organization"":[],""location"":[""Australia"",""Russia""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1784
+0192ced0-9ba4-7991-a3eb-144fa1502650,dashboard_fixture_extract_entities,dicl,0192ced0-949e-71e3-965b-28aad7deddad,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""times in seconds ) :""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[\""times in seconds\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[],""miscellaneous"":[""times in seconds""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1797
+0192ced0-9a25-7b42-9531-76bda018fc76,dashboard_fixture_extract_entities,dicl,0192ced0-949e-71e3-965b-289f36c44690,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""2001 65,000""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[\""2001\"",\""65,000\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[],""miscellaneous"":[""2001"",""65,000""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1414
+0192ced0-9af0-7381-b318-7ff25f54628b,dashboard_fixture_extract_entities,dicl,0192ced0-949e-71e3-965b-2883ed7737f0,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Mexican army attacked in Michoacan state - report .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""Michoacan state\""],\""miscellaneous\"":[\""Mexican army\"",\""report\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""Michoacan state""],""miscellaneous"":[""Mexican army"",""report""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1618
+0192ced0-98ba-7251-9c48-98cf94489068,dashboard_fixture_extract_entities,baseline,0192ced0-949e-71e3-965b-28f84cc37437,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Mark Philippoussis ( Australia ) beat Andrei Olhovskiy ( Russia ) 6 - 3 6-4 6-2""}]}]}","{""raw"":""{\n    \""person\"": [\""Mark Philippoussis\"", \""Andrei Olhovskiy\""],\n    \""organization\"": [],\n    \""location\"": [\""Australia\"", \""Russia\""],\n    \""miscellaneous\"": []\n}"",""parsed"":{""person"":[""Mark Philippoussis"",""Andrei Olhovskiy""],""organization"":[],""location"":[""Australia"",""Russia""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1051
+0192ced0-9940-75a3-a7a5-46c2efc4435f,dashboard_fixture_extract_entities,baseline,0192ced0-949e-71e3-965b-28ce5b08b690,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""SOCCER - AUSTRIA DOMINATE SCOTLAND IN WORLD CUP QUALIFIER .""}]}]}","{""raw"":""{\n    \""person\"": [],\n    \""organization\"": [\""AUSTRIA\"", \""SCOTLAND\""],\n    \""location\"": [\""WORLD CUP\""],\n    \""miscellaneous\"": [\""SOCCER\"", \""QUALIFIER\""]\n}"",""parsed"":{""person"":[],""organization"":[""AUSTRIA"",""SCOTLAND""],""location"":[""WORLD CUP""],""miscellaneous"":[""SOCCER"",""QUALIFIER""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1185
+0192ced0-9895-7453-85e5-00cdcfbce8e3,dashboard_fixture_extract_entities,baseline,0192ced0-949e-71e3-965b-286935e73d44,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" All concerned must avoid taking any course of action that could pose an obstacle to the peace process and which could make a peaceful solution difficult , \"" he said , as news came of a renewed breakdown in Arab-Israeli peace talks in Jerusalem .""}]}]}","{""raw"":""{\n    \""person\"": [],\n    \""organization\"": [],\n    \""location\"": [\""Jerusalem\""],\n    \""miscellaneous\"": [\""Arab-Israeli peace talks\"", \""peace process\"", \""peaceful solution\""]\n}"",""parsed"":{""person"":[],""organization"":[],""location"":[""Jerusalem""],""miscellaneous"":[""Arab-Israeli peace talks"",""peace process"",""peaceful solution""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1014
+0192ced0-9a12-7fc1-9ffe-12f71a46a9a1,dashboard_fixture_extract_entities,dicl,0192ced0-949e-71e3-965b-2853ee2f7254,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" Seven percent creates psychological problems and a legitimate competitor for money from equities , \"" said Ralph Bloch , chief technical analyst at Raymond James .""}]}]}","{""raw"":""{\""person\"":[\""Ralph Bloch\""],\""organization\"":[\""Raymond James\""],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Ralph Bloch""],""organization"":[""Raymond James""],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1396
+0192ced0-9a46-75b0-a75b-ed37c1c341f5,dashboard_fixture_extract_entities,dicl,0192ced0-949e-71e3-965b-281bfce4fcab,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Hen Vipheak , former editor of the Sereipheap Thmei ( New Liberty ) newspaper , stepped through the gates of the run-down French colonial-era T3 prison late Friday afternoon , following intervention on his behalf by King Sihanouk .""}]}]}","{""raw"":""{\""person\"":[\""Hen Vipheak\"",\""King Sihanouk\""],\""organization\"":[\""Sereipheap Thmei\"",\""New Liberty\""],\""location\"":[\""T3 prison\""],\""miscellaneous\"":[\""French colonial-era\""]}"",""parsed"":{""person"":[""Hen Vipheak"",""King Sihanouk""],""organization"":[""Sereipheap Thmei"",""New Liberty""],""location"":[""T3 prison""],""miscellaneous"":[""French colonial-era""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1448
+0192ced0-993f-73a3-9fa8-e7f4edfb8c57,dashboard_fixture_extract_entities,dicl,0192ced0-948c-7da3-952e-12212cd39154,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Division three""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[\""Division three\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[],""miscellaneous"":[""Division three""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1203
+0192ced0-9c1d-7261-9c77-ae24df02f4bc,dashboard_fixture_extract_entities,dicl,0192ced0-948c-7da3-952e-1210c1b5c8da,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""AL-RAM , West Bank 1996-08-30""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""AL-RAM\"",\""West Bank\""],\""miscellaneous\"":[\""1996-08-30\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""AL-RAM"",""West Bank""],""miscellaneous"":[""1996-08-30""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1937
+0192ced0-9bf4-7013-b140-ab528b3dcfa3,dashboard_fixture_extract_entities,dicl,0192ced0-948c-7da3-952e-120ddf100442,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""ATHLETICS - HARRISON , EDWARDS TO MEET IN SARAJEVO .""}]}]}","{""raw"":""{\""person\"":[\""Harrison\"",\""Edwards\""],\""organization\"":[],\""location\"":[\""SARAJEVO\""],\""miscellaneous\"":[\""ATHLETICS\""]}"",""parsed"":{""person"":[""Harrison"",""Edwards""],""organization"":[],""location"":[""SARAJEVO""],""miscellaneous"":[""ATHLETICS""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1896
+0192ced0-9b9b-7323-8d3b-5648b4010991,dashboard_fixture_extract_entities,dicl,0192ced0-949d-7063-900d-a543e944a78e,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""East Stirling 3 0 2 1 3 4 2""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""East Stirling\""],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[""East Stirling""],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1789
+0192ced0-9a51-7bf0-a71a-0b742cbba18f,dashboard_fixture_extract_entities,dicl,0192ced0-949d-7063-900d-a53a25441ce6,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" All concerned must avoid taking any course of action that could pose an obstacle to the peace process and which could make a peaceful solution difficult , \"" he said , as news came of a renewed breakdown in Arab-Israeli peace talks in Jerusalem .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""Jerusalem\""],\""miscellaneous\"":[\""Arab-Israeli peace talks\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""Jerusalem""],""miscellaneous"":[""Arab-Israeli peace talks""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1459
+0192ced0-9b5b-7ed0-8426-c80c07cf7063,dashboard_fixture_extract_entities,dicl,0192ced0-949d-7063-900d-a522851e657d,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""GERMANY - Bunds extended losses , flirting with session lows after falling victim to sharply higher U.S. economic data which revived fears that interest rates may soon turn higher .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""GERMANY\""],\""miscellaneous\"":[\""Bunds\"",\""U.S.\"",\""economic data\"",\""interest rates\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""GERMANY""],""miscellaneous"":[""Bunds"",""U.S."",""economic data"",""interest rates""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1725
+0192ced0-9b5a-7c11-9a03-3dbca22fa726,dashboard_fixture_extract_entities,dicl,0192ced0-949d-7063-900d-a50d91022b1f,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""He said the repatriation would be carried out swiftly and would be enormous , starting with the closure of refugee camps .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[\""repatriation\"",\""refugee camps\"",\""closure\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[],""miscellaneous"":[""repatriation"",""refugee camps"",""closure""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1724
+0192ced0-9940-75a3-a7a5-46ecc40fd161,dashboard_fixture_extract_entities,dicl,0192ced0-949f-7193-8e91-ba8de82223a9,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""DETROIT 1996-08-31""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""DETROIT\""],\""location\"":[],\""miscellaneous\"":[\""1996-08-31\""]}"",""parsed"":{""person"":[],""organization"":[""DETROIT""],""location"":[],""miscellaneous"":[""1996-08-31""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1185
+0192ced0-9998-7050-94e1-169aa33d0656,dashboard_fixture_extract_entities,dicl,0192ced0-949b-71e3-8282-05d42287903f,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""The Organisation for Security and Cooperation in Europe ( OSCE ) postponed municipal elections as a result of the irregularities but decided to proceed with voting for higher offices .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Organisation for Security and Cooperation in Europe\"",\""OSCE\""],\""location\"":[],\""miscellaneous\"":[\""municipal elections\"",\""higher offices\""]}"",""parsed"":{""person"":[],""organization"":[""Organisation for Security and Cooperation in Europe"",""OSCE""],""location"":[],""miscellaneous"":[""municipal elections"",""higher offices""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1278
+0192ced0-99a0-7502-9aaf-dc262e960523,dashboard_fixture_extract_entities,turbo,0192ced0-949f-7193-8e91-ba7b1fe1c206,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Hen Vipheak , former editor of the Sereipheap Thmei ( New Liberty ) newspaper , stepped through the gates of the run-down French colonial-era T3 prison late Friday afternoon , following intervention on his behalf by King Sihanouk .""}]}]}","{""raw"":""{\""person\"":[\""Vipheak\"",\""Sihanouk\""],\""organization\"":[\""New Liberty\""],\""location\"":[],\""miscellaneous\"":[\""French\""]}"",""parsed"":{""person"":[""Vipheak"",""Sihanouk""],""organization"":[""New Liberty""],""location"":[],""miscellaneous"":[""French""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1281
+0192ced0-9912-7da1-aad1-43a0a6c960fc,dashboard_fixture_extract_entities,turbo,0192ced0-949f-7193-8e91-baa3ee76e8e4,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""ATHLETICS - HARRISON , EDWARDS TO MEET IN SARAJEVO .""}]}]}","{""raw"":""{\""person\"":[\""HARRISON\"",\""EDWARDS\""],\""organization\"":[],\""location\"":[\""SARAJEVO\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""HARRISON"",""EDWARDS""],""organization"":[],""location"":[""SARAJEVO""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1139
+0192ced0-9b5d-79f3-8433-5b568580ad3f,dashboard_fixture_extract_entities,baseline,0192ced0-947e-74b3-a3d7-02fd2c54d637,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" Seven percent creates psychological problems and a legitimate competitor for money from equities , \"" said Ralph Bloch , chief technical analyst at Raymond James .""}]}]}","{""raw"":""{\""person\"":[\""Ralph Bloch\""],\""organization\"":[\""Raymond James\""],\""location\"":[],\""miscellaneous\"":[\""psychological problems\"",\""legitimate competitor\"",\""money\"",\""equities\""]}"",""parsed"":{""person"":[""Ralph Bloch""],""organization"":[""Raymond James""],""location"":[],""miscellaneous"":[""psychological problems"",""legitimate competitor"",""money"",""equities""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1758
+0192ced0-99cc-7962-9181-5ce939f765ec,dashboard_fixture_extract_entities,turbo,0192ced0-949f-7193-8e91-bad56cc63624,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Mark Philippoussis ( Australia ) beat Andrei Olhovskiy ( Russia ) 6 - 3 6-4 6-2""}]}]}","{""raw"":""{\""person\"":[\""Mark Philippoussis\"",\""Andrei Olhovskiy\""],\""organization\"":[],\""location\"":[\""Australia\"",\""Russia\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Mark Philippoussis"",""Andrei Olhovskiy""],""organization"":[],""location"":[""Australia"",""Russia""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1325
+0192ced0-994a-7093-86bf-53e5efb29816,dashboard_fixture_extract_entities,baseline,0192ced0-949f-7193-8e91-bb09a360ce57,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Hen Vipheak , former editor of the Sereipheap Thmei ( New Liberty ) newspaper , stepped through the gates of the run-down French colonial-era T3 prison late Friday afternoon , following intervention on his behalf by King Sihanouk .""}]}]}","{""raw"":""{\n    \""person\"": [\""Hen Vipheak\"", \""King Sihanouk\""],\n    \""organization\"": [\""Sereipheap Thmei\"", \""New Liberty\""],\n    \""location\"": [\""T3 prison\""],\n    \""miscellaneous\"": [\""French colonial-era\""]\n}"",""parsed"":{""person"":[""Hen Vipheak"",""King Sihanouk""],""organization"":[""Sereipheap Thmei"",""New Liberty""],""location"":[""T3 prison""],""miscellaneous"":[""French colonial-era""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1194
+0192ced0-990c-7b01-af7a-ecbe3fb9983f,dashboard_fixture_extract_entities,turbo,0192ced0-949f-7193-8e91-bac43f3c3b38,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""SOCCER - AUSTRIA DOMINATE SCOTLAND IN WORLD CUP QUALIFIER .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""AUSTRIA\"",\""SCOTLAND\""],\""miscellaneous\"":[\""WORLD CUP\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""AUSTRIA"",""SCOTLAND""],""miscellaneous"":[""WORLD CUP""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1133
+0192ced0-98f0-7b33-9f27-ec6d460e1cc6,dashboard_fixture_extract_entities,turbo,0192ced0-949f-7193-8e91-bb35bd5ad521,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""GERMANY - Bunds extended losses , flirting with session lows after falling victim to sharply higher U.S. economic data which revived fears that interest rates may soon turn higher .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""GERMANY\"",\""U.S.\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""GERMANY"",""U.S.""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1104
+0192ced0-9873-70e2-ade5-dc5b8faea232,dashboard_fixture_extract_entities,turbo,0192ced0-949e-71e3-965b-28e9465cd560,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""times in seconds ) :""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",980
+0192ced0-98d9-75b1-9cfd-f2431a407070,dashboard_fixture_extract_entities,turbo,0192ced0-949e-71e3-965b-28b97e8d4672,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" Seven percent creates psychological problems and a legitimate competitor for money from equities , \"" said Ralph Bloch , chief technical analyst at Raymond James .""}]}]}","{""raw"":""{\""person\"":[\""Ralph Bloch\""],\""organization\"":[\""Raymond James\""],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Ralph Bloch""],""organization"":[""Raymond James""],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1082
+0192ced0-98ba-7251-9c48-99033278d090,dashboard_fixture_extract_entities,turbo,0192ced0-949e-71e3-965b-2873dc17e120,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""\"" All concerned must avoid taking any course of action that could pose an obstacle to the peace process and which could make a peaceful solution difficult , \"" he said , as news came of a renewed breakdown in Arab-Israeli peace talks in Jerusalem .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""Jerusalem\""],\""miscellaneous\"":[\""Arab-Israeli\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""Jerusalem""],""miscellaneous"":[""Arab-Israeli""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1052
+0192ced0-987b-7763-a428-b3ec3a9ea20f,dashboard_fixture_extract_entities,turbo,0192ced0-949e-71e3-965b-2802ea9341a1,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Division three""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",989
+0192ced0-9979-7ae2-ad8d-fd741623846e,dashboard_fixture_extract_entities,turbo,0192ced0-949d-7063-900d-a4f545ed6f83,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""East Stirling 3 0 2 1 3 4 2""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""East Stirling\"",\""3\"",\""0\"",\""2\"",\""1\"",\""3\"",\""4\"",\""2\""],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[""East Stirling"",""3"",""0"",""2"",""1"",""3"",""4"",""2""],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1243
+0192ced0-98bb-7ab1-bbe9-d66735c66b7d,dashboard_fixture_extract_entities,turbo,0192ced0-949d-7063-900d-a4e0d31e69c4,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""DETROIT 1996-08-31""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""DETROIT\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""DETROIT""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1053
+0192ced0-98ba-7251-9c48-993380d27c11,dashboard_fixture_extract_entities,turbo,0192ced0-949d-7063-900d-a4d3bbd2acfc,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Cofinec , the first foreign company to list on the Budapest bourse , released its consolidated first half figures ( IAS ) this morning .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[\""Cofinec\"",\""IAS\""],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[""Cofinec"",""IAS""],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1053
+0192ced0-98be-7372-94af-c03f07cbcc67,dashboard_fixture_extract_entities,turbo,0192ced0-949d-7063-900d-a4c7f1661358,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Mexican army attacked in Michoacan state - report .""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""Michoacan\""],\""miscellaneous\"":[\""Mexican\""]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""Michoacan""],""miscellaneous"":[""Mexican""]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1056
+0192ced0-9895-7453-85e5-00ae27921722,dashboard_fixture_extract_entities,turbo,0192ced0-949d-7063-900d-a4a6d3b4003b,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""Brown threw 119 pitches and won for the third time in as many starts against the Reds this season .""}]}]}","{""raw"":""{\""person\"":[\""Brown\""],\""organization\"":[\""Reds\""],\""location\"":[],\""miscellaneous\"":[]}"",""parsed"":{""person"":[""Brown""],""organization"":[""Reds""],""location"":[],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1015
+0192ced0-98ba-7251-9c48-991e27386ce4,dashboard_fixture_extract_entities,turbo,0192ced0-949f-7193-8e91-baeb174781be,"{""messages"":[{""role"":""user"",""content"":[{""type"":""text"",""value"":""AL-RAM , West Bank 1996-08-30""}]}]}","{""raw"":""{\""person\"":[],\""organization\"":[],\""location\"":[\""AL-RAM\"",\""West Bank\""],\""miscellaneous\"":[]}"",""parsed"":{""person"":[],""organization"":[],""location"":[""AL-RAM"",""West Bank""],""miscellaneous"":[]}}","{""$schema"":""http://json-schema.org/draft-07/schema#"",""type"":""object"",""properties"":{""person"":{""type"":""array"",""items"":{""type"":""string""}},""organization"":{""type"":""array"",""items"":{""type"":""string""}},""location"":{""type"":""array"",""items"":{""type"":""string""}},""miscellaneous"":{""type"":""array"",""items"":{""type"":""string""}}},""required"":[""person"",""organization"",""location"",""miscellaneous""],""additionalProperties"":false}","{""chat_completion"":{}}",1051
diff --git a/dashboard/fixtures/load_fixtures.sh b/dashboard/fixtures/load_fixtures.sh
new file mode 100755
index 000000000..a65b8b83c
--- /dev/null
+++ b/dashboard/fixtures/load_fixtures.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+set -e
+clickhouse-client --host $CLICKHOUSE_HOST --database tensorzero --query "INSERT INTO JsonInference FORMAT CSV" < json_inference_examples.csv
+clickhouse-client --host $CLICKHOUSE_HOST --database tensorzero --query "INSERT INTO BooleanMetricFeedback FORMAT CSV" < boolean_metric_feedback_examples.csv
+echo "Fixtures loaded; this container will now exit with status 0"
diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json
new file mode 100644
index 000000000..c2980284f
--- /dev/null
+++ b/dashboard/package-lock.json
@@ -0,0 +1,9468 @@
+{
+  "name": "tensorzero-dashboard",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "tensorzero-dashboard",
+      "dependencies": {
+        "@clickhouse/client": "^1.10.0",
+        "@eslint/js": "^9.17.0",
+        "@hookform/resolvers": "^3.9.1",
+        "@radix-ui/react-accordion": "^1.2.2",
+        "@radix-ui/react-dialog": "^1.1.4",
+        "@radix-ui/react-label": "^2.1.1",
+        "@radix-ui/react-select": "^2.1.4",
+        "@radix-ui/react-slot": "^1.1.1",
+        "@react-router/node": "^7.0.2",
+        "@react-router/serve": "^7.0.2",
+        "ajv": "^8.17.1",
+        "class-variance-authority": "^0.7.1",
+        "clsx": "^2.1.1",
+        "eslint-plugin-react": "^7.37.2",
+        "isbot": "^5.1.17",
+        "json-schema": "^0.4.0",
+        "lucide-react": "^0.469.0",
+        "openai": "^4.77.0",
+        "react": "^19.0.0",
+        "react-dom": "^19.0.0",
+        "react-hook-form": "^7.54.2",
+        "react-router": "^7.1.0",
+        "react-router-dom": "^7.1.0",
+        "smol-toml": "^1.3.1",
+        "tailwind-merge": "^2.5.5",
+        "tailwindcss-animate": "^1.0.7",
+        "typescript-eslint": "^8.18.1",
+        "uuid": "^11.0.3",
+        "vite-plugin-top-level-await": "^1.4.4",
+        "vite-plugin-wasm": "^3.4.1",
+        "zod": "^3.24.1"
+      },
+      "devDependencies": {
+        "@react-router/dev": "^7.0.2",
+        "@types/json-schema": "^7.0.15",
+        "@types/node": "^20",
+        "@types/react": "^19.0.0",
+        "@types/react-dom": "^19.0.0",
+        "autoprefixer": "^10.4.20",
+        "cross-env": "^7.0.3",
+        "postcss": "^8.4.49",
+        "tailwindcss": "^3.4.16",
+        "typescript": "^5.7.2",
+        "vite": "^5.4.11",
+        "vite-tsconfig-paths": "^5.1.4",
+        "vitest": "^2.1.8"
+      }
+    },
+    "node_modules/@alloc/quick-lru": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+      "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@ampproject/remapping": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+      "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.26.2",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
+      "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.25.9",
+        "js-tokens": "^4.0.0",
+        "picocolors": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.26.3",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz",
+      "integrity": "sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.26.0",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz",
+      "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@ampproject/remapping": "^2.2.0",
+        "@babel/code-frame": "^7.26.0",
+        "@babel/generator": "^7.26.0",
+        "@babel/helper-compilation-targets": "^7.25.9",
+        "@babel/helper-module-transforms": "^7.26.0",
+        "@babel/helpers": "^7.26.0",
+        "@babel/parser": "^7.26.0",
+        "@babel/template": "^7.25.9",
+        "@babel/traverse": "^7.25.9",
+        "@babel/types": "^7.26.0",
+        "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/babel"
+      }
+    },
+    "node_modules/@babel/core/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/@babel/generator": {
+      "version": "7.26.3",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz",
+      "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.26.3",
+        "@babel/types": "^7.26.3",
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.25",
+        "jsesc": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-annotate-as-pure": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz",
+      "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz",
+      "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/compat-data": "^7.25.9",
+        "@babel/helper-validator-option": "^7.25.9",
+        "browserslist": "^4.24.0",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/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/@babel/helper-create-class-features-plugin": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz",
+      "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.25.9",
+        "@babel/helper-member-expression-to-functions": "^7.25.9",
+        "@babel/helper-optimise-call-expression": "^7.25.9",
+        "@babel/helper-replace-supers": "^7.25.9",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
+        "@babel/traverse": "^7.25.9",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-create-class-features-plugin/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/@babel/helper-member-expression-to-functions": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz",
+      "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.25.9",
+        "@babel/types": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
+      "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.25.9",
+        "@babel/types": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.26.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz",
+      "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.25.9",
+        "@babel/helper-validator-identifier": "^7.25.9",
+        "@babel/traverse": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-optimise-call-expression": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz",
+      "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-plugin-utils": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz",
+      "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-replace-supers": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz",
+      "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-member-expression-to-functions": "^7.25.9",
+        "@babel/helper-optimise-call-expression": "^7.25.9",
+        "@babel/traverse": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz",
+      "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.25.9",
+        "@babel/types": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
+      "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
+      "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz",
+      "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.26.0",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz",
+      "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/template": "^7.25.9",
+        "@babel/types": "^7.26.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.26.3",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz",
+      "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.26.3"
+      },
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-decorators": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz",
+      "integrity": "sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-jsx": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz",
+      "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-typescript": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz",
+      "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-modules-commonjs": {
+      "version": "7.26.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz",
+      "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-module-transforms": "^7.26.0",
+        "@babel/helper-plugin-utils": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-typescript": {
+      "version": "7.26.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.3.tgz",
+      "integrity": "sha512-6+5hpdr6mETwSKjmJUdYw0EIkATiQhnELWlE3kJFBwSg/BGIVwVaVbX+gOXBCdc7Ln1RXZxyWGecIXhUfnl7oA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.25.9",
+        "@babel/helper-create-class-features-plugin": "^7.25.9",
+        "@babel/helper-plugin-utils": "^7.25.9",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
+        "@babel/plugin-syntax-typescript": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/preset-typescript": {
+      "version": "7.26.0",
+      "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz",
+      "integrity": "sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.25.9",
+        "@babel/helper-validator-option": "^7.25.9",
+        "@babel/plugin-syntax-jsx": "^7.25.9",
+        "@babel/plugin-transform-modules-commonjs": "^7.25.9",
+        "@babel/plugin-transform-typescript": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/template": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz",
+      "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.25.9",
+        "@babel/parser": "^7.25.9",
+        "@babel/types": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.26.4",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz",
+      "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.26.2",
+        "@babel/generator": "^7.26.3",
+        "@babel/parser": "^7.26.3",
+        "@babel/template": "^7.25.9",
+        "@babel/types": "^7.26.3",
+        "debug": "^4.3.1",
+        "globals": "^11.1.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.26.3",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz",
+      "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.25.9",
+        "@babel/helper-validator-identifier": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@clickhouse/client": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/@clickhouse/client/-/client-1.10.0.tgz",
+      "integrity": "sha512-vyLkrE7iqWw3QPTet7no5Rd3qZFV4ujyo01FbspaTpME04F07AkBkRFJ/haUpf6GbZr/LsGIH5I4jy1vzGoRbQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@clickhouse/client-common": "1.10.0"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/@clickhouse/client-common": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/@clickhouse/client-common/-/client-common-1.10.0.tgz",
+      "integrity": "sha512-dxXgJEGxwhOclflDH+GI8z7fQMh7KjJ/r0kSGE7yLKJlW0YHgbfxVufOkrEVg2QJMOmqi+YynkO4w1rXhetC0w==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@esbuild/aix-ppc64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+      "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+      "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+      "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+      "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+      "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+      "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+      "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+      "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+      "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+      "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+      "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+      "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+      "cpu": [
+        "loong64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+      "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+      "cpu": [
+        "mips64el"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+      "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+      "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+      "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+      "cpu": [
+        "s390x"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+      "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+      "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+      "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+      "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+      "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+      "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+      "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@eslint-community/eslint-utils": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz",
+      "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==",
+      "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==",
+      "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.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+      "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+      "license": "MIT",
+      "engines": {
+        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@eslint/config-array": {
+      "version": "0.19.1",
+      "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz",
+      "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "@eslint/object-schema": "^2.1.5",
+        "debug": "^4.3.1",
+        "minimatch": "^3.1.2"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/core": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz",
+      "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "@types/json-schema": "^7.0.15"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/eslintrc": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz",
+      "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^10.0.1",
+        "globals": "^14.0.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "license": "MIT",
+      "peer": true,
+      "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/@eslint/eslintrc/node_modules/globals": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+      "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@eslint/eslintrc/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==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/@eslint/js": {
+      "version": "9.17.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz",
+      "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==",
+      "license": "MIT",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/object-schema": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz",
+      "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/plugin-kit": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz",
+      "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "levn": "^0.4.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@floating-ui/core": {
+      "version": "1.6.8",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz",
+      "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/utils": "^0.2.8"
+      }
+    },
+    "node_modules/@floating-ui/dom": {
+      "version": "1.6.12",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz",
+      "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/core": "^1.6.0",
+        "@floating-ui/utils": "^0.2.8"
+      }
+    },
+    "node_modules/@floating-ui/react-dom": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz",
+      "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/dom": "^1.0.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.8.0",
+        "react-dom": ">=16.8.0"
+      }
+    },
+    "node_modules/@floating-ui/utils": {
+      "version": "0.2.8",
+      "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz",
+      "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==",
+      "license": "MIT"
+    },
+    "node_modules/@hookform/resolvers": {
+      "version": "3.9.1",
+      "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.1.tgz",
+      "integrity": "sha512-ud2HqmGBM0P0IABqoskKWI6PEf6ZDDBZkFqe2Vnl+mTHCEHzr3ISjjZyCwTjC/qpL25JC9aIDkloQejvMeq0ug==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react-hook-form": "^7.0.0"
+      }
+    },
+    "node_modules/@humanfs/core": {
+      "version": "0.19.1",
+      "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+      "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node": {
+      "version": "0.16.6",
+      "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
+      "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "@humanfs/core": "^0.19.1",
+        "@humanwhocodes/retry": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
+      "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": ">=18.18"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "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==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": ">=12.22"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@humanwhocodes/retry": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz",
+      "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==",
+      "license": "Apache-2.0",
+      "peer": true,
+      "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==",
+      "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.8",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
+      "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/set-array": "^1.2.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/set-array": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+      "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+      "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.25",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+      "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@mjackson/node-fetch-server": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/@mjackson/node-fetch-server/-/node-fetch-server-0.2.0.tgz",
+      "integrity": "sha512-EMlH1e30yzmTpGLQjlFmaDAjyOeZhng1/XCd7DExR8PNAnG/G1tyruZxEoUe11ClnwGhGrtsdnyyUx1frSzjng==",
+      "license": "MIT"
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@npmcli/git": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz",
+      "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@npmcli/promise-spawn": "^6.0.0",
+        "lru-cache": "^7.4.4",
+        "npm-pick-manifest": "^8.0.0",
+        "proc-log": "^3.0.0",
+        "promise-inflight": "^1.0.1",
+        "promise-retry": "^2.0.1",
+        "semver": "^7.3.5",
+        "which": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@npmcli/git/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/@npmcli/package-json": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-4.0.1.tgz",
+      "integrity": "sha512-lRCEGdHZomFsURroh522YvA/2cVb9oPIJrjHanCJZkiasz1BzcnLr3tBJhlV7S86MBJBuAQ33is2D60YitZL2Q==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@npmcli/git": "^4.1.0",
+        "glob": "^10.2.2",
+        "hosted-git-info": "^6.1.1",
+        "json-parse-even-better-errors": "^3.0.0",
+        "normalize-package-data": "^5.0.0",
+        "proc-log": "^3.0.0",
+        "semver": "^7.5.3"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@npmcli/promise-spawn": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz",
+      "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "which": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@radix-ui/number": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz",
+      "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==",
+      "license": "MIT"
+    },
+    "node_modules/@radix-ui/primitive": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
+      "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==",
+      "license": "MIT"
+    },
+    "node_modules/@radix-ui/react-accordion": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.2.tgz",
+      "integrity": "sha512-b1oh54x4DMCdGsB4/7ahiSrViXxaBwRPotiZNnYXjLha9vfuURSAZErki6qjDoSIV0eXx5v57XnTGVtGwnfp2g==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.1",
+        "@radix-ui/react-collapsible": "1.1.2",
+        "@radix-ui/react-collection": "1.1.1",
+        "@radix-ui/react-compose-refs": "1.1.1",
+        "@radix-ui/react-context": "1.1.1",
+        "@radix-ui/react-direction": "1.1.0",
+        "@radix-ui/react-id": "1.1.0",
+        "@radix-ui/react-primitive": "2.0.1",
+        "@radix-ui/react-use-controllable-state": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-arrow": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.1.tgz",
+      "integrity": "sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-primitive": "2.0.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-collapsible": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.2.tgz",
+      "integrity": "sha512-PliMB63vxz7vggcyq0IxNYk8vGDrLXVWw4+W4B8YnwI1s18x7YZYqlG9PLX7XxAJUi0g2DxP4XKJMFHh/iVh9A==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.1",
+        "@radix-ui/react-compose-refs": "1.1.1",
+        "@radix-ui/react-context": "1.1.1",
+        "@radix-ui/react-id": "1.1.0",
+        "@radix-ui/react-presence": "1.1.2",
+        "@radix-ui/react-primitive": "2.0.1",
+        "@radix-ui/react-use-controllable-state": "1.1.0",
+        "@radix-ui/react-use-layout-effect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-collection": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz",
+      "integrity": "sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.1",
+        "@radix-ui/react-context": "1.1.1",
+        "@radix-ui/react-primitive": "2.0.1",
+        "@radix-ui/react-slot": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-compose-refs": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
+      "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-context": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz",
+      "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-dialog": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.4.tgz",
+      "integrity": "sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.1",
+        "@radix-ui/react-compose-refs": "1.1.1",
+        "@radix-ui/react-context": "1.1.1",
+        "@radix-ui/react-dismissable-layer": "1.1.3",
+        "@radix-ui/react-focus-guards": "1.1.1",
+        "@radix-ui/react-focus-scope": "1.1.1",
+        "@radix-ui/react-id": "1.1.0",
+        "@radix-ui/react-portal": "1.1.3",
+        "@radix-ui/react-presence": "1.1.2",
+        "@radix-ui/react-primitive": "2.0.1",
+        "@radix-ui/react-slot": "1.1.1",
+        "@radix-ui/react-use-controllable-state": "1.1.0",
+        "aria-hidden": "^1.1.1",
+        "react-remove-scroll": "^2.6.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-direction": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
+      "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-dismissable-layer": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz",
+      "integrity": "sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.1",
+        "@radix-ui/react-compose-refs": "1.1.1",
+        "@radix-ui/react-primitive": "2.0.1",
+        "@radix-ui/react-use-callback-ref": "1.1.0",
+        "@radix-ui/react-use-escape-keydown": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-focus-guards": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz",
+      "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-focus-scope": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz",
+      "integrity": "sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.1",
+        "@radix-ui/react-primitive": "2.0.1",
+        "@radix-ui/react-use-callback-ref": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-id": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz",
+      "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-use-layout-effect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-label": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.1.tgz",
+      "integrity": "sha512-UUw5E4e/2+4kFMH7+YxORXGWggtY6sM8WIwh5RZchhLuUg2H1hc98Py+pr8HMz6rdaYrK2t296ZEjYLOCO5uUw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-primitive": "2.0.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-popper": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.1.tgz",
+      "integrity": "sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/react-dom": "^2.0.0",
+        "@radix-ui/react-arrow": "1.1.1",
+        "@radix-ui/react-compose-refs": "1.1.1",
+        "@radix-ui/react-context": "1.1.1",
+        "@radix-ui/react-primitive": "2.0.1",
+        "@radix-ui/react-use-callback-ref": "1.1.0",
+        "@radix-ui/react-use-layout-effect": "1.1.0",
+        "@radix-ui/react-use-rect": "1.1.0",
+        "@radix-ui/react-use-size": "1.1.0",
+        "@radix-ui/rect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-portal": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz",
+      "integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-primitive": "2.0.1",
+        "@radix-ui/react-use-layout-effect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-presence": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
+      "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.1",
+        "@radix-ui/react-use-layout-effect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-primitive": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz",
+      "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-slot": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-select": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.4.tgz",
+      "integrity": "sha512-pOkb2u8KgO47j/h7AylCj7dJsm69BXcjkrvTqMptFqsE2i0p8lHkfgneXKjAgPzBMivnoMyt8o4KiV4wYzDdyQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/number": "1.1.0",
+        "@radix-ui/primitive": "1.1.1",
+        "@radix-ui/react-collection": "1.1.1",
+        "@radix-ui/react-compose-refs": "1.1.1",
+        "@radix-ui/react-context": "1.1.1",
+        "@radix-ui/react-direction": "1.1.0",
+        "@radix-ui/react-dismissable-layer": "1.1.3",
+        "@radix-ui/react-focus-guards": "1.1.1",
+        "@radix-ui/react-focus-scope": "1.1.1",
+        "@radix-ui/react-id": "1.1.0",
+        "@radix-ui/react-popper": "1.2.1",
+        "@radix-ui/react-portal": "1.1.3",
+        "@radix-ui/react-primitive": "2.0.1",
+        "@radix-ui/react-slot": "1.1.1",
+        "@radix-ui/react-use-callback-ref": "1.1.0",
+        "@radix-ui/react-use-controllable-state": "1.1.0",
+        "@radix-ui/react-use-layout-effect": "1.1.0",
+        "@radix-ui/react-use-previous": "1.1.0",
+        "@radix-ui/react-visually-hidden": "1.1.1",
+        "aria-hidden": "^1.1.1",
+        "react-remove-scroll": "^2.6.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-slot": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz",
+      "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-callback-ref": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
+      "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-controllable-state": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz",
+      "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-use-callback-ref": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-escape-keydown": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz",
+      "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-use-callback-ref": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-layout-effect": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz",
+      "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-previous": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz",
+      "integrity": "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-rect": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz",
+      "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/rect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-size": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz",
+      "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-use-layout-effect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-visually-hidden": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.1.tgz",
+      "integrity": "sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/react-primitive": "2.0.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/rect": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz",
+      "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==",
+      "license": "MIT"
+    },
+    "node_modules/@react-router/dev": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/@react-router/dev/-/dev-7.1.0.tgz",
+      "integrity": "sha512-bIv0g5HKfDwXMfXrJuhCGXE8sET50vj6ubFlAdZ52SkCUN+mLZaQEChPsx+icSl2QJgotTjJp35t75QA7gOQkg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "^7.21.8",
+        "@babel/generator": "^7.21.5",
+        "@babel/parser": "^7.21.8",
+        "@babel/plugin-syntax-decorators": "^7.22.10",
+        "@babel/plugin-syntax-jsx": "^7.21.4",
+        "@babel/preset-typescript": "^7.21.5",
+        "@babel/traverse": "^7.23.2",
+        "@babel/types": "^7.22.5",
+        "@npmcli/package-json": "^4.0.1",
+        "@react-router/node": "7.1.0",
+        "arg": "^5.0.1",
+        "babel-dead-code-elimination": "^1.0.6",
+        "chokidar": "^4.0.0",
+        "dedent": "^1.5.3",
+        "es-module-lexer": "^1.3.1",
+        "exit-hook": "2.2.1",
+        "fs-extra": "^10.0.0",
+        "gunzip-maybe": "^1.4.2",
+        "jsesc": "3.0.2",
+        "lodash": "^4.17.21",
+        "pathe": "^1.1.2",
+        "picocolors": "^1.1.1",
+        "picomatch": "^2.3.1",
+        "prettier": "^2.7.1",
+        "react-refresh": "^0.14.0",
+        "semver": "^7.3.7",
+        "set-cookie-parser": "^2.6.0",
+        "valibot": "^0.41.0",
+        "vite-node": "3.0.0-beta.2"
+      },
+      "bin": {
+        "react-router": "bin.js"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      },
+      "peerDependencies": {
+        "@react-router/serve": "^7.1.0",
+        "react-router": "^7.1.0",
+        "typescript": "^5.1.0",
+        "vite": "^5.1.0 || ^6.0.0",
+        "wrangler": "^3.28.2"
+      },
+      "peerDependenciesMeta": {
+        "@react-router/serve": {
+          "optional": true
+        },
+        "typescript": {
+          "optional": true
+        },
+        "wrangler": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@react-router/express": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/@react-router/express/-/express-7.1.0.tgz",
+      "integrity": "sha512-VZs3ngM87L3/Y16uTgknMYWRV3LwEJzvLH2u5JDxSbtJOKCboRl8JDj9Qn2j2NPalqmWNYSnHWAoxEQYDDratw==",
+      "license": "MIT",
+      "dependencies": {
+        "@react-router/node": "7.1.0"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      },
+      "peerDependencies": {
+        "express": "^4.17.1",
+        "react-router": "7.1.0",
+        "typescript": "^5.1.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@react-router/node": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/@react-router/node/-/node-7.1.0.tgz",
+      "integrity": "sha512-jVGZGU7Jg8+irv61fwExWKKrZpnoMWH2Mce7RwZriFZx4Kx4pOmvGKdniLRBmo3t5GWT63okBfBIhMLgxJBpyA==",
+      "license": "MIT",
+      "dependencies": {
+        "@mjackson/node-fetch-server": "^0.2.0",
+        "source-map-support": "^0.5.21",
+        "stream-slice": "^0.1.2",
+        "undici": "^6.19.2"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      },
+      "peerDependencies": {
+        "react-router": "7.1.0",
+        "typescript": "^5.1.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@react-router/serve": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/@react-router/serve/-/serve-7.1.0.tgz",
+      "integrity": "sha512-RRYRRboHfBhrJxy71T1l9l3h6JZOcZiIH3qHyC/neT90sqyLjcNAVk8LOrF1W86mrMi2px02Y1qL9YTMx3Ykxg==",
+      "license": "MIT",
+      "dependencies": {
+        "@react-router/express": "7.1.0",
+        "@react-router/node": "7.1.0",
+        "compression": "^1.7.4",
+        "express": "^4.19.2",
+        "get-port": "5.1.1",
+        "morgan": "^1.10.0",
+        "source-map-support": "^0.5.21"
+      },
+      "bin": {
+        "react-router-serve": "bin.js"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      },
+      "peerDependencies": {
+        "react-router": "7.1.0"
+      }
+    },
+    "node_modules/@rollup/plugin-virtual": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz",
+      "integrity": "sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "peerDependencies": {
+        "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rollup/rollup-android-arm-eabi": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.0.tgz",
+      "integrity": "sha512-TnF0md3qWSRDlU96y9+0dd5RNrlXiQUp1K2pK1UpNmjeND+o9ts9Jxv3G6ntagkt8jVh0KAT1VYgU0nCz5gt2w==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-android-arm64": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.29.0.tgz",
+      "integrity": "sha512-L/7oX07eY6ACt2NXDrku1JIPdf9VGV/DI92EjAd8FRDzMMub5hXFpT1OegBqimJh9xy9Vv+nToaVtZp4Ku9SEA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-arm64": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.29.0.tgz",
+      "integrity": "sha512-I1ZucWPVS96hjAsMSJiGosHTqMulMynrmTN+Xde5OsLcU5SjE0xylBmQ/DbB2psJ+HasINrJYz8HQpojtAw2eA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-x64": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.29.0.tgz",
+      "integrity": "sha512-CTZ+lHMsTbH1q/XLKzmnJWxl2r/1xdv7cnjwbi5v+95nVA1syikxWLvqur4nDoGDHjC8oNMBGurnQptpuFJHXA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-arm64": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.29.0.tgz",
+      "integrity": "sha512-BB8+4OMzk2JiKL5+aK8A0pi9DPB5pkIBZWXr19+grdez9b0VKihvV432uSwuZLO0sI6zCyxak8NO3mZ1yjM1jA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-x64": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.29.0.tgz",
+      "integrity": "sha512-Udz9Uh26uEE6phGMG2++TfpsLK/z4cYJqrIOyVhig/PMoWiZLghpjZUQvsAylsoztbpg0/QmplkDAyyVq0x6Jg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.29.0.tgz",
+      "integrity": "sha512-IPSCTzP8GRYzY+siSnggIKrckC2U+kVXoen6eSHRDgU9a4EZCHHWWOiKio1EkieOOk2j6EvZaaHfQUCmt8UJBg==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.29.0.tgz",
+      "integrity": "sha512-GvHPu0UIDx+ohyS8vTYnwoSVMM5BH3NO+JwQs6GWNCuQVlC5rKxnH2WClTGu3NxiIfhKLai08IKUwn3QbzX1UQ==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-gnu": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.29.0.tgz",
+      "integrity": "sha512-Pnnn/2CAZWcH9GQoj1nnr85Ejh7aNDe5MsEV0xhuFNUPF0SdnutJ7b2muOI5Kx12T0/i2ol5B/tlhMviZQDL3g==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-musl": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.29.0.tgz",
+      "integrity": "sha512-AP+DLj4q9FT22ZL43ssA3gizEn7/MfJcZ1BOuyEPqoriuH3a8VRuDddN0MtpUwEtiZL6jc1GY5/eL99hkloQ1Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.29.0.tgz",
+      "integrity": "sha512-1+jPFClHmDATqbk0Cwi74KEOymVcs09Vbqe/CTKqLwCP0TeP2CACfnMnjYBs5CJgO20e/4bxFtmbR/9fKE1gug==",
+      "cpu": [
+        "loong64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.29.0.tgz",
+      "integrity": "sha512-Nmt5Us5w2dL8eh7QVyAIDVVwBv4wk8ljrBQe7lWkLaOcwABDaFQ3K4sAAC6IsOdJwaXXW+d85zVaMN+Xl8Co2w==",
+      "cpu": [
+        "ppc64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.29.0.tgz",
+      "integrity": "sha512-KGuQ8WGhnq09LR7eOru7P9jfBSYXTMhq6TyavWfmEo+TxvkvuRwOCee5lPIa6HYjblOuFr4GeOxSE0c8iyw2Fg==",
+      "cpu": [
+        "riscv64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-s390x-gnu": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.29.0.tgz",
+      "integrity": "sha512-lSQtvrYIONme7a4gbf4O9d3zbZat3/5covIeoqk27ZIkTgBeL/67x+wq2bZfpLjkqQQp5SjBPQ/n0sg8iArzTg==",
+      "cpu": [
+        "s390x"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-gnu": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.29.0.tgz",
+      "integrity": "sha512-qh0ussrXBwnF4L07M9t1+jpHRhiGSae+wpNQDbmlXHXciT7pqpZ5zpk4dyGZPtDGB2l2clDiufE16BufXPGRWQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-musl": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.0.tgz",
+      "integrity": "sha512-YEABzSaRS7+v14yw6MVBZoMqLoUyTX1/sJoGeC0euvgMrzvw0i+jHo4keDZgYeOblfwdseVAf6ylxWSvcBAKTA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-arm64-msvc": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.29.0.tgz",
+      "integrity": "sha512-jA4+oxG7QTTtSQxwSHzFVwShcppHO2DpkbAM59pfD5WMG/da79yQaeBtXAfGTI+ciUx8hqK3RF3H2KWByITXtQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-ia32-msvc": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.29.0.tgz",
+      "integrity": "sha512-4TQbLoAQVu9uE+cvh47JnjRZylXVdRCoOkRSVF2Rr2T0U1YwphGRjR0sHyRPEt95y3ETT4YFTTzQPq1O4bcjmw==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-x64-msvc": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.29.0.tgz",
+      "integrity": "sha512-GsFvcTZ7Yj9k94Qm0qgav7pxmQ7lQDR9NjoelRaxeV1UF6JSDfanR/2tHZ8hS7Ps4KPIVf5AElYPRPmN/Q0ZkQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@swc/core": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.10.1.tgz",
+      "integrity": "sha512-rQ4dS6GAdmtzKiCRt3LFVxl37FaY1cgL9kSUTnhQ2xc3fmHOd7jdJK/V4pSZMG1ruGTd0bsi34O2R0Olg9Zo/w==",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@swc/counter": "^0.1.3",
+        "@swc/types": "^0.1.17"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/swc"
+      },
+      "optionalDependencies": {
+        "@swc/core-darwin-arm64": "1.10.1",
+        "@swc/core-darwin-x64": "1.10.1",
+        "@swc/core-linux-arm-gnueabihf": "1.10.1",
+        "@swc/core-linux-arm64-gnu": "1.10.1",
+        "@swc/core-linux-arm64-musl": "1.10.1",
+        "@swc/core-linux-x64-gnu": "1.10.1",
+        "@swc/core-linux-x64-musl": "1.10.1",
+        "@swc/core-win32-arm64-msvc": "1.10.1",
+        "@swc/core-win32-ia32-msvc": "1.10.1",
+        "@swc/core-win32-x64-msvc": "1.10.1"
+      },
+      "peerDependencies": {
+        "@swc/helpers": "*"
+      },
+      "peerDependenciesMeta": {
+        "@swc/helpers": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@swc/core-darwin-arm64": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.10.1.tgz",
+      "integrity": "sha512-NyELPp8EsVZtxH/mEqvzSyWpfPJ1lugpTQcSlMduZLj1EASLO4sC8wt8hmL1aizRlsbjCX+r0PyL+l0xQ64/6Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-darwin-x64": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.10.1.tgz",
+      "integrity": "sha512-L4BNt1fdQ5ZZhAk5qoDfUnXRabDOXKnXBxMDJ+PWLSxOGBbWE6aJTnu4zbGjJvtot0KM46m2LPAPY8ttknqaZA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-arm-gnueabihf": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.10.1.tgz",
+      "integrity": "sha512-Y1u9OqCHgvVp2tYQAJ7hcU9qO5brDMIrA5R31rwWQIAKDkJKtv3IlTHF0hrbWk1wPR0ZdngkQSJZple7G+Grvw==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "Apache-2.0",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-arm64-gnu": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.10.1.tgz",
+      "integrity": "sha512-tNQHO/UKdtnqjc7o04iRXng1wTUXPgVd8Y6LI4qIbHVoVPwksZydISjMcilKNLKIwOoUQAkxyJ16SlOAeADzhQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-arm64-musl": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.10.1.tgz",
+      "integrity": "sha512-x0L2Pd9weQ6n8dI1z1Isq00VHFvpBClwQJvrt3NHzmR+1wCT/gcYl1tp9P5xHh3ldM8Cn4UjWCw+7PaUgg8FcQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-x64-gnu": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.10.1.tgz",
+      "integrity": "sha512-yyYEwQcObV3AUsC79rSzN9z6kiWxKAVJ6Ntwq2N9YoZqSPYph+4/Am5fM1xEQYf/kb99csj0FgOelomJSobxQA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-linux-x64-musl": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.10.1.tgz",
+      "integrity": "sha512-tcaS43Ydd7Fk7sW5ROpaf2Kq1zR+sI5K0RM+0qYLYYurvsJruj3GhBCaiN3gkzd8m/8wkqNqtVklWaQYSDsyqA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-win32-arm64-msvc": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.10.1.tgz",
+      "integrity": "sha512-D3Qo1voA7AkbOzQ2UGuKNHfYGKL6eejN8VWOoQYtGHHQi1p5KK/Q7V1ku55oxXBsj79Ny5FRMqiRJpVGad7bjQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-win32-ia32-msvc": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.10.1.tgz",
+      "integrity": "sha512-WalYdFoU3454Og+sDKHM1MrjvxUGwA2oralknXkXL8S0I/8RkWZOB++p3pLaGbTvOO++T+6znFbQdR8KRaa7DA==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/core-win32-x64-msvc": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.10.1.tgz",
+      "integrity": "sha512-JWobfQDbTnoqaIwPKQ3DVSywihVXlQMbDuwik/dDWlj33A8oEHcjPOGs4OqcA3RHv24i+lfCQpM3Mn4FAMfacA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "Apache-2.0 AND MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@swc/counter": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
+      "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@swc/types": {
+      "version": "0.1.17",
+      "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.17.tgz",
+      "integrity": "sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@swc/counter": "^0.1.3"
+      }
+    },
+    "node_modules/@types/cookie": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
+      "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
+      "license": "MIT"
+    },
+    "node_modules/@types/estree": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+      "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+      "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==",
+      "license": "MIT"
+    },
+    "node_modules/@types/node": {
+      "version": "20.17.10",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.10.tgz",
+      "integrity": "sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==",
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~6.19.2"
+      }
+    },
+    "node_modules/@types/node-fetch": {
+      "version": "2.6.12",
+      "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz",
+      "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*",
+        "form-data": "^4.0.0"
+      }
+    },
+    "node_modules/@types/react": {
+      "version": "19.0.2",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.2.tgz",
+      "integrity": "sha512-USU8ZI/xyKJwFTpjSVIrSeHBVAGagkHQKPNbxeWwql/vDmnTIBgx+TJnhFnj1NXgz8XfprU0egV2dROLGpsBEg==",
+      "devOptional": true,
+      "license": "MIT",
+      "dependencies": {
+        "csstype": "^3.0.2"
+      }
+    },
+    "node_modules/@types/react-dom": {
+      "version": "19.0.2",
+      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.2.tgz",
+      "integrity": "sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==",
+      "devOptional": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "^19.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/eslint-plugin": {
+      "version": "8.18.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.1.tgz",
+      "integrity": "sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/regexpp": "^4.10.0",
+        "@typescript-eslint/scope-manager": "8.18.1",
+        "@typescript-eslint/type-utils": "8.18.1",
+        "@typescript-eslint/utils": "8.18.1",
+        "@typescript-eslint/visitor-keys": "8.18.1",
+        "graphemer": "^1.4.0",
+        "ignore": "^5.3.1",
+        "natural-compare": "^1.4.0",
+        "ts-api-utils": "^1.3.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.0.0 || ^8.0.0-alpha.0",
+        "eslint": "^8.57.0 || ^9.0.0",
+        "typescript": ">=4.8.4 <5.8.0"
+      }
+    },
+    "node_modules/@typescript-eslint/parser": {
+      "version": "8.18.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.1.tgz",
+      "integrity": "sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==",
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/scope-manager": "8.18.1",
+        "@typescript-eslint/types": "8.18.1",
+        "@typescript-eslint/typescript-estree": "8.18.1",
+        "@typescript-eslint/visitor-keys": "8.18.1",
+        "debug": "^4.3.4"
+      },
+      "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",
+        "typescript": ">=4.8.4 <5.8.0"
+      }
+    },
+    "node_modules/@typescript-eslint/scope-manager": {
+      "version": "8.18.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.1.tgz",
+      "integrity": "sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.18.1",
+        "@typescript-eslint/visitor-keys": "8.18.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/type-utils": {
+      "version": "8.18.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.1.tgz",
+      "integrity": "sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/typescript-estree": "8.18.1",
+        "@typescript-eslint/utils": "8.18.1",
+        "debug": "^4.3.4",
+        "ts-api-utils": "^1.3.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",
+        "typescript": ">=4.8.4 <5.8.0"
+      }
+    },
+    "node_modules/@typescript-eslint/types": {
+      "version": "8.18.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.1.tgz",
+      "integrity": "sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw==",
+      "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.18.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.1.tgz",
+      "integrity": "sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg==",
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.18.1",
+        "@typescript-eslint/visitor-keys": "8.18.1",
+        "debug": "^4.3.4",
+        "fast-glob": "^3.3.2",
+        "is-glob": "^4.0.3",
+        "minimatch": "^9.0.4",
+        "semver": "^7.6.0",
+        "ts-api-utils": "^1.3.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 <5.8.0"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@typescript-eslint/utils": {
+      "version": "8.18.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.1.tgz",
+      "integrity": "sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.4.0",
+        "@typescript-eslint/scope-manager": "8.18.1",
+        "@typescript-eslint/types": "8.18.1",
+        "@typescript-eslint/typescript-estree": "8.18.1"
+      },
+      "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",
+        "typescript": ">=4.8.4 <5.8.0"
+      }
+    },
+    "node_modules/@typescript-eslint/visitor-keys": {
+      "version": "8.18.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.1.tgz",
+      "integrity": "sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.18.1",
+        "eslint-visitor-keys": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@vitest/expect": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.8.tgz",
+      "integrity": "sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/spy": "2.1.8",
+        "@vitest/utils": "2.1.8",
+        "chai": "^5.1.2",
+        "tinyrainbow": "^1.2.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/mocker": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.8.tgz",
+      "integrity": "sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/spy": "2.1.8",
+        "estree-walker": "^3.0.3",
+        "magic-string": "^0.30.12"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      },
+      "peerDependencies": {
+        "msw": "^2.4.9",
+        "vite": "^5.0.0"
+      },
+      "peerDependenciesMeta": {
+        "msw": {
+          "optional": true
+        },
+        "vite": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vitest/pretty-format": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.8.tgz",
+      "integrity": "sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tinyrainbow": "^1.2.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/runner": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.8.tgz",
+      "integrity": "sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/utils": "2.1.8",
+        "pathe": "^1.1.2"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/snapshot": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.8.tgz",
+      "integrity": "sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/pretty-format": "2.1.8",
+        "magic-string": "^0.30.12",
+        "pathe": "^1.1.2"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/spy": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.8.tgz",
+      "integrity": "sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tinyspy": "^3.0.2"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/utils": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz",
+      "integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/pretty-format": "2.1.8",
+        "loupe": "^3.1.2",
+        "tinyrainbow": "^1.2.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/abort-controller": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+      "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+      "license": "MIT",
+      "dependencies": {
+        "event-target-shim": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=6.5"
+      }
+    },
+    "node_modules/accepts": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+      "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+      "license": "MIT",
+      "dependencies": {
+        "mime-types": "~2.1.34",
+        "negotiator": "0.6.3"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/accepts/node_modules/negotiator": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+      "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/acorn": {
+      "version": "8.14.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
+      "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+      "license": "MIT",
+      "peer": true,
+      "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==",
+      "license": "MIT",
+      "peer": true,
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/agentkeepalive": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz",
+      "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==",
+      "license": "MIT",
+      "dependencies": {
+        "humanize-ms": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 8.0.0"
+      }
+    },
+    "node_modules/ajv": {
+      "version": "8.17.1",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+      "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+      "license": "MIT",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3",
+        "fast-uri": "^3.0.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+      "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/any-promise": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+      "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+      "license": "MIT"
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "license": "ISC",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/arg": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+      "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
+      "license": "MIT"
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "license": "Python-2.0",
+      "peer": true
+    },
+    "node_modules/aria-hidden": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz",
+      "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/array-buffer-byte-length": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
+      "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "is-array-buffer": "^3.0.5"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array-flatten": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+      "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
+      "license": "MIT"
+    },
+    "node_modules/array-includes": {
+      "version": "3.1.8",
+      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
+      "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-object-atoms": "^1.0.0",
+        "get-intrinsic": "^1.2.4",
+        "is-string": "^1.0.7"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array.prototype.findlast": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
+      "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
+        "es-shim-unscopables": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array.prototype.flat": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
+      "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.5",
+        "es-shim-unscopables": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array.prototype.flatmap": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
+      "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.5",
+        "es-shim-unscopables": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/array.prototype.tosorted": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz",
+      "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.3",
+        "es-errors": "^1.3.0",
+        "es-shim-unscopables": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/arraybuffer.prototype.slice": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
+      "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
+      "license": "MIT",
+      "dependencies": {
+        "array-buffer-byte-length": "^1.0.1",
+        "call-bind": "^1.0.8",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.5",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.6",
+        "is-array-buffer": "^3.0.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "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/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+      "license": "MIT"
+    },
+    "node_modules/autoprefixer": {
+      "version": "10.4.20",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
+      "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "browserslist": "^4.23.3",
+        "caniuse-lite": "^1.0.30001646",
+        "fraction.js": "^4.3.7",
+        "normalize-range": "^0.1.2",
+        "picocolors": "^1.0.1",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "bin": {
+        "autoprefixer": "bin/autoprefixer"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/available-typed-arrays": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+      "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+      "license": "MIT",
+      "dependencies": {
+        "possible-typed-array-names": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/babel-dead-code-elimination": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.8.tgz",
+      "integrity": "sha512-og6HQERk0Cmm+nTT4Od2wbPtgABXFMPaHACjbKLulZIFMkYyXZLkUGuAxdgpMJBrxyt/XFpSz++lNzjbcMnPkQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "^7.23.7",
+        "@babel/parser": "^7.23.6",
+        "@babel/traverse": "^7.23.7",
+        "@babel/types": "^7.23.6"
+      }
+    },
+    "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==",
+      "license": "MIT"
+    },
+    "node_modules/basic-auth": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+      "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "5.1.2"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/basic-auth/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "license": "MIT"
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+      "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/body-parser": {
+      "version": "1.20.3",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+      "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
+      "license": "MIT",
+      "dependencies": {
+        "bytes": "3.1.2",
+        "content-type": "~1.0.5",
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "destroy": "1.2.0",
+        "http-errors": "2.0.0",
+        "iconv-lite": "0.4.24",
+        "on-finished": "2.4.1",
+        "qs": "6.13.0",
+        "raw-body": "2.5.2",
+        "type-is": "~1.6.18",
+        "unpipe": "1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8",
+        "npm": "1.2.8000 || >= 1.4.16"
+      }
+    },
+    "node_modules/body-parser/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/body-parser/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "license": "MIT"
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browserify-zlib": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
+      "integrity": "sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "pako": "~0.2.0"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.24.3",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz",
+      "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==",
+      "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": {
+        "caniuse-lite": "^1.0.30001688",
+        "electron-to-chromium": "^1.5.73",
+        "node-releases": "^2.0.19",
+        "update-browserslist-db": "^1.1.1"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "license": "MIT"
+    },
+    "node_modules/bytes": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/cac": {
+      "version": "6.7.14",
+      "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+      "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/call-bind": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
+      "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.0",
+        "es-define-property": "^1.0.0",
+        "get-intrinsic": "^1.2.4",
+        "set-function-length": "^1.2.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/call-bind-apply-helpers": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz",
+      "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/call-bound": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz",
+      "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.1",
+        "get-intrinsic": "^1.2.6"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/camelcase-css": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+      "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001690",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz",
+      "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==",
+      "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": "5.1.2",
+      "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz",
+      "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "assertion-error": "^2.0.1",
+        "check-error": "^2.1.1",
+        "deep-eql": "^5.0.1",
+        "loupe": "^3.1.0",
+        "pathval": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "license": "MIT",
+      "peer": true,
+      "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/check-error": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
+      "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 16"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/class-variance-authority": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
+      "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "clsx": "^2.1.1"
+      },
+      "funding": {
+        "url": "https://polar.sh/cva"
+      }
+    },
+    "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==",
+      "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==",
+      "license": "MIT"
+    },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "license": "MIT",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/commander": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+      "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/compressible": {
+      "version": "2.0.18",
+      "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
+      "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": ">= 1.43.0 < 2"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/compression": {
+      "version": "1.7.5",
+      "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz",
+      "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==",
+      "license": "MIT",
+      "dependencies": {
+        "bytes": "3.1.2",
+        "compressible": "~2.0.18",
+        "debug": "2.6.9",
+        "negotiator": "~0.6.4",
+        "on-headers": "~1.0.2",
+        "safe-buffer": "5.2.1",
+        "vary": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/compression/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/compression/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "license": "MIT"
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "license": "MIT"
+    },
+    "node_modules/content-disposition": {
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+      "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "5.2.1"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/content-type": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+      "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "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/cookie": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
+      "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/cookie-signature": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+      "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
+      "license": "MIT"
+    },
+    "node_modules/core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/cross-env": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
+      "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cross-spawn": "^7.0.1"
+      },
+      "bin": {
+        "cross-env": "src/bin/cross-env.js",
+        "cross-env-shell": "src/bin/cross-env-shell.js"
+      },
+      "engines": {
+        "node": ">=10.14",
+        "npm": ">=6",
+        "yarn": ">=1"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/cross-spawn/node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "license": "MIT",
+      "bin": {
+        "cssesc": "bin/cssesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/csstype": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+      "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+      "devOptional": true,
+      "license": "MIT"
+    },
+    "node_modules/data-view-buffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
+      "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/data-view-byte-length": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
+      "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/inspect-js"
+      }
+    },
+    "node_modules/data-view-byte-offset": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
+      "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "is-data-view": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+      "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/dedent": {
+      "version": "1.5.3",
+      "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz",
+      "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "babel-plugin-macros": "^3.1.0"
+      },
+      "peerDependenciesMeta": {
+        "babel-plugin-macros": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/deep-eql": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
+      "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/define-data-property": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+      "license": "MIT",
+      "dependencies": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/define-properties": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+      "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+      "license": "MIT",
+      "dependencies": {
+        "define-data-property": "^1.0.1",
+        "has-property-descriptors": "^1.0.0",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/destroy": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+      "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8",
+        "npm": "1.2.8000 || >= 1.4.16"
+      }
+    },
+    "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/didyoumean": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+      "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/dlv": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+      "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+      "license": "MIT"
+    },
+    "node_modules/doctrine": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+      "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "esutils": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/dunder-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+      "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.2.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/duplexify": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
+      "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "end-of-stream": "^1.0.0",
+        "inherits": "^2.0.1",
+        "readable-stream": "^2.0.0",
+        "stream-shift": "^1.0.0"
+      }
+    },
+    "node_modules/eastasianwidth": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+      "license": "MIT"
+    },
+    "node_modules/ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+      "license": "MIT"
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.5.75",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.75.tgz",
+      "integrity": "sha512-Lf3++DumRE/QmweGjU+ZcKqQ+3bKkU/qjaKYhIJKEOhgIO9Xs6IiAQFkfFoj+RhgDk4LUeNsLo6plExHqSyu6Q==",
+      "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==",
+      "license": "MIT"
+    },
+    "node_modules/encodeurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+      "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "once": "^1.4.0"
+      }
+    },
+    "node_modules/err-code": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
+      "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/es-abstract": {
+      "version": "1.23.7",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.7.tgz",
+      "integrity": "sha512-OygGC8kIcDhXX+6yAZRGLqwi2CmEXCbLQixeGUgYeR+Qwlppqmo7DIDr8XibtEBZp+fJcoYpoatp5qwLMEdcqQ==",
+      "license": "MIT",
+      "dependencies": {
+        "array-buffer-byte-length": "^1.0.2",
+        "arraybuffer.prototype.slice": "^1.0.4",
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "data-view-buffer": "^1.0.2",
+        "data-view-byte-length": "^1.0.2",
+        "data-view-byte-offset": "^1.0.1",
+        "es-define-property": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
+        "es-set-tostringtag": "^2.0.3",
+        "es-to-primitive": "^1.3.0",
+        "function.prototype.name": "^1.1.8",
+        "get-intrinsic": "^1.2.6",
+        "get-symbol-description": "^1.1.0",
+        "globalthis": "^1.0.4",
+        "gopd": "^1.2.0",
+        "has-property-descriptors": "^1.0.2",
+        "has-proto": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "hasown": "^2.0.2",
+        "internal-slot": "^1.1.0",
+        "is-array-buffer": "^3.0.5",
+        "is-callable": "^1.2.7",
+        "is-data-view": "^1.0.2",
+        "is-regex": "^1.2.1",
+        "is-shared-array-buffer": "^1.0.4",
+        "is-string": "^1.1.1",
+        "is-typed-array": "^1.1.15",
+        "is-weakref": "^1.1.0",
+        "math-intrinsics": "^1.1.0",
+        "object-inspect": "^1.13.3",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.7",
+        "regexp.prototype.flags": "^1.5.3",
+        "safe-array-concat": "^1.1.3",
+        "safe-regex-test": "^1.1.0",
+        "string.prototype.trim": "^1.2.10",
+        "string.prototype.trimend": "^1.0.9",
+        "string.prototype.trimstart": "^1.0.8",
+        "typed-array-buffer": "^1.0.3",
+        "typed-array-byte-length": "^1.0.3",
+        "typed-array-byte-offset": "^1.0.4",
+        "typed-array-length": "^1.0.7",
+        "unbox-primitive": "^1.1.0",
+        "which-typed-array": "^1.1.18"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/es-define-property": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-iterator-helpers": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz",
+      "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.6",
+        "es-errors": "^1.3.0",
+        "es-set-tostringtag": "^2.0.3",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.6",
+        "globalthis": "^1.0.4",
+        "gopd": "^1.2.0",
+        "has-property-descriptors": "^1.0.2",
+        "has-proto": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "internal-slot": "^1.1.0",
+        "iterator.prototype": "^1.1.4",
+        "safe-array-concat": "^1.1.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-module-lexer": {
+      "version": "1.5.4",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz",
+      "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/es-object-atoms": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
+      "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-set-tostringtag": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
+      "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
+      "license": "MIT",
+      "dependencies": {
+        "get-intrinsic": "^1.2.4",
+        "has-tostringtag": "^1.0.2",
+        "hasown": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-shim-unscopables": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz",
+      "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==",
+      "license": "MIT",
+      "dependencies": {
+        "hasown": "^2.0.0"
+      }
+    },
+    "node_modules/es-to-primitive": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
+      "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
+      "license": "MIT",
+      "dependencies": {
+        "is-callable": "^1.2.7",
+        "is-date-object": "^1.0.5",
+        "is-symbol": "^1.0.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/esbuild": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+      "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.21.5",
+        "@esbuild/android-arm": "0.21.5",
+        "@esbuild/android-arm64": "0.21.5",
+        "@esbuild/android-x64": "0.21.5",
+        "@esbuild/darwin-arm64": "0.21.5",
+        "@esbuild/darwin-x64": "0.21.5",
+        "@esbuild/freebsd-arm64": "0.21.5",
+        "@esbuild/freebsd-x64": "0.21.5",
+        "@esbuild/linux-arm": "0.21.5",
+        "@esbuild/linux-arm64": "0.21.5",
+        "@esbuild/linux-ia32": "0.21.5",
+        "@esbuild/linux-loong64": "0.21.5",
+        "@esbuild/linux-mips64el": "0.21.5",
+        "@esbuild/linux-ppc64": "0.21.5",
+        "@esbuild/linux-riscv64": "0.21.5",
+        "@esbuild/linux-s390x": "0.21.5",
+        "@esbuild/linux-x64": "0.21.5",
+        "@esbuild/netbsd-x64": "0.21.5",
+        "@esbuild/openbsd-x64": "0.21.5",
+        "@esbuild/sunos-x64": "0.21.5",
+        "@esbuild/win32-arm64": "0.21.5",
+        "@esbuild/win32-ia32": "0.21.5",
+        "@esbuild/win32-x64": "0.21.5"
+      }
+    },
+    "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-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+      "license": "MIT"
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint": {
+      "version": "9.17.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz",
+      "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@eslint-community/regexpp": "^4.12.1",
+        "@eslint/config-array": "^0.19.0",
+        "@eslint/core": "^0.9.0",
+        "@eslint/eslintrc": "^3.2.0",
+        "@eslint/js": "9.17.0",
+        "@eslint/plugin-kit": "^0.2.3",
+        "@humanfs/node": "^0.16.6",
+        "@humanwhocodes/module-importer": "^1.0.1",
+        "@humanwhocodes/retry": "^0.4.1",
+        "@types/estree": "^1.0.6",
+        "@types/json-schema": "^7.0.15",
+        "ajv": "^6.12.4",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.6",
+        "debug": "^4.3.2",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^8.2.0",
+        "eslint-visitor-keys": "^4.2.0",
+        "espree": "^10.3.0",
+        "esquery": "^1.5.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",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.3"
+      },
+      "bin": {
+        "eslint": "bin/eslint.js"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://eslint.org/donate"
+      },
+      "peerDependencies": {
+        "jiti": "*"
+      },
+      "peerDependenciesMeta": {
+        "jiti": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/eslint-plugin-react": {
+      "version": "7.37.2",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz",
+      "integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==",
+      "license": "MIT",
+      "dependencies": {
+        "array-includes": "^3.1.8",
+        "array.prototype.findlast": "^1.2.5",
+        "array.prototype.flatmap": "^1.3.2",
+        "array.prototype.tosorted": "^1.1.4",
+        "doctrine": "^2.1.0",
+        "es-iterator-helpers": "^1.1.0",
+        "estraverse": "^5.3.0",
+        "hasown": "^2.0.2",
+        "jsx-ast-utils": "^2.4.1 || ^3.0.0",
+        "minimatch": "^3.1.2",
+        "object.entries": "^1.1.8",
+        "object.fromentries": "^2.0.8",
+        "object.values": "^1.2.0",
+        "prop-types": "^15.8.1",
+        "resolve": "^2.0.0-next.5",
+        "semver": "^6.3.1",
+        "string.prototype.matchall": "^4.0.11",
+        "string.prototype.repeat": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      },
+      "peerDependencies": {
+        "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
+      }
+    },
+    "node_modules/eslint-plugin-react/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/eslint-scope": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz",
+      "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==",
+      "license": "BSD-2-Clause",
+      "peer": true,
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint-visitor-keys": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+      "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint/node_modules/ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "license": "MIT",
+      "peer": true,
+      "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/eslint/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==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/espree": {
+      "version": "10.3.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
+      "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
+      "license": "BSD-2-Clause",
+      "peer": true,
+      "dependencies": {
+        "acorn": "^8.14.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/esquery": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+      "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+      "license": "BSD-3-Clause",
+      "peer": true,
+      "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==",
+      "license": "BSD-2-Clause",
+      "peer": true,
+      "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==",
+      "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==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/event-target-shim": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+      "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/exit-hook": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz",
+      "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/expect-type": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz",
+      "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/express": {
+      "version": "4.21.2",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
+      "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
+      "license": "MIT",
+      "dependencies": {
+        "accepts": "~1.3.8",
+        "array-flatten": "1.1.1",
+        "body-parser": "1.20.3",
+        "content-disposition": "0.5.4",
+        "content-type": "~1.0.4",
+        "cookie": "0.7.1",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "encodeurl": "~2.0.0",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "finalhandler": "1.3.1",
+        "fresh": "0.5.2",
+        "http-errors": "2.0.0",
+        "merge-descriptors": "1.0.3",
+        "methods": "~1.1.2",
+        "on-finished": "2.4.1",
+        "parseurl": "~1.3.3",
+        "path-to-regexp": "0.1.12",
+        "proxy-addr": "~2.0.7",
+        "qs": "6.13.0",
+        "range-parser": "~1.2.1",
+        "safe-buffer": "5.2.1",
+        "send": "0.19.0",
+        "serve-static": "1.16.2",
+        "setprototypeof": "1.2.0",
+        "statuses": "2.0.1",
+        "type-is": "~1.6.18",
+        "utils-merge": "1.0.1",
+        "vary": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/express/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/express/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "license": "MIT"
+    },
+    "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==",
+      "license": "MIT"
+    },
+    "node_modules/fast-glob": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+      "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-glob/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/fast-uri": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz",
+      "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/fastq": {
+      "version": "1.17.1",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+      "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+      "license": "ISC",
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "flat-cache": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/finalhandler": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+      "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
+      "license": "MIT",
+      "dependencies": {
+        "debug": "2.6.9",
+        "encodeurl": "~2.0.0",
+        "escape-html": "~1.0.3",
+        "on-finished": "2.4.1",
+        "parseurl": "~1.3.3",
+        "statuses": "2.0.1",
+        "unpipe": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/finalhandler/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/finalhandler/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "license": "MIT"
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true,
+      "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==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "flatted": "^3.2.9",
+        "keyv": "^4.5.4"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/flatted": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz",
+      "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==",
+      "license": "ISC",
+      "peer": true
+    },
+    "node_modules/for-each": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+      "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+      "license": "MIT",
+      "dependencies": {
+        "is-callable": "^1.1.3"
+      }
+    },
+    "node_modules/foreground-child": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
+      "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
+      "license": "ISC",
+      "dependencies": {
+        "cross-spawn": "^7.0.0",
+        "signal-exit": "^4.0.1"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/form-data": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
+      "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
+      "license": "MIT",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/form-data-encoder": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz",
+      "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==",
+      "license": "MIT"
+    },
+    "node_modules/formdata-node": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz",
+      "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==",
+      "license": "MIT",
+      "dependencies": {
+        "node-domexception": "1.0.0",
+        "web-streams-polyfill": "4.0.0-beta.3"
+      },
+      "engines": {
+        "node": ">= 12.20"
+      }
+    },
+    "node_modules/forwarded": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/fraction.js": {
+      "version": "4.3.7",
+      "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
+      "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "type": "patreon",
+        "url": "https://github.com/sponsors/rawify"
+      }
+    },
+    "node_modules/fresh": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+      "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/fs-extra": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+      "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "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==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/function.prototype.name": {
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
+      "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "define-properties": "^1.2.1",
+        "functions-have-names": "^1.2.3",
+        "hasown": "^2.0.2",
+        "is-callable": "^1.2.7"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/functions-have-names": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+      "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-intrinsic": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz",
+      "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.1",
+        "dunder-proto": "^1.0.0",
+        "es-define-property": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
+        "function-bind": "^1.1.2",
+        "gopd": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "hasown": "^2.0.2",
+        "math-intrinsics": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "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/get-port": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz",
+      "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/get-symbol-description": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
+      "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.6"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/glob": {
+      "version": "10.4.5",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+      "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+      "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==",
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/glob/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/glob/node_modules/minimatch": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/globals": {
+      "version": "11.12.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/globalthis": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+      "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+      "license": "MIT",
+      "dependencies": {
+        "define-properties": "^1.2.1",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/globrex": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
+      "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/gopd": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "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"
+    },
+    "node_modules/graphemer": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+      "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+      "license": "MIT"
+    },
+    "node_modules/gunzip-maybe": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz",
+      "integrity": "sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "browserify-zlib": "^0.1.4",
+        "is-deflate": "^1.0.0",
+        "is-gzip": "^1.0.0",
+        "peek-stream": "^1.1.0",
+        "pumpify": "^1.3.3",
+        "through2": "^2.0.3"
+      },
+      "bin": {
+        "gunzip-maybe": "bin.js"
+      }
+    },
+    "node_modules/has-bigints": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
+      "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/has-property-descriptors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+      "license": "MIT",
+      "dependencies": {
+        "es-define-property": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-proto": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
+      "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
+      "license": "MIT",
+      "dependencies": {
+        "dunder-proto": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-tostringtag": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+      "license": "MIT",
+      "dependencies": {
+        "has-symbols": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/hasown": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+      "license": "MIT",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "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/http-errors": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+      "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+      "license": "MIT",
+      "dependencies": {
+        "depd": "2.0.0",
+        "inherits": "2.0.4",
+        "setprototypeof": "1.2.0",
+        "statuses": "2.0.1",
+        "toidentifier": "1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/humanize-ms": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+      "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.0.0"
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "license": "MIT",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      },
+      "engines": {
+        "node": ">=0.10.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==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=0.8.19"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "license": "ISC"
+    },
+    "node_modules/internal-slot": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
+      "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "hasown": "^2.0.2",
+        "side-channel": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/ipaddr.js": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/is-array-buffer": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
+      "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "get-intrinsic": "^1.2.6"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-async-function": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
+      "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==",
+      "license": "MIT",
+      "dependencies": {
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-bigint": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
+      "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
+      "license": "MIT",
+      "dependencies": {
+        "has-bigints": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "license": "MIT",
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-boolean-object": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.1.tgz",
+      "integrity": "sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-callable": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+      "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-core-module": {
+      "version": "2.16.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.0.tgz",
+      "integrity": "sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g==",
+      "license": "MIT",
+      "dependencies": {
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-data-view": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
+      "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "get-intrinsic": "^1.2.6",
+        "is-typed-array": "^1.1.13"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-date-object": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
+      "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-deflate": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-deflate/-/is-deflate-1.0.0.tgz",
+      "integrity": "sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-finalizationregistry": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
+      "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-generator-function": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
+      "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
+      "license": "MIT",
+      "dependencies": {
+        "has-tostringtag": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-gzip": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz",
+      "integrity": "sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-map": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
+      "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-number-object": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
+      "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-regex": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
+      "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "gopd": "^1.2.0",
+        "has-tostringtag": "^1.0.2",
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-set": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
+      "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-shared-array-buffer": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
+      "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-string": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
+      "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-symbol": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
+      "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "has-symbols": "^1.1.0",
+        "safe-regex-test": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-typed-array": {
+      "version": "1.1.15",
+      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
+      "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+      "license": "MIT",
+      "dependencies": {
+        "which-typed-array": "^1.1.16"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakmap": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
+      "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakref": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.0.tgz",
+      "integrity": "sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-weakset": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
+      "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "get-intrinsic": "^1.2.6"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/isbot": {
+      "version": "5.1.18",
+      "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.18.tgz",
+      "integrity": "sha512-df9RdChv1DheItzN5pNKtblc9/otzJYmxjf9GhCZG/f0TCcGCbQFmtM3e+SD0e8EI3/O2tIXPYVaG4FUaIIa6Q==",
+      "license": "Unlicense",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "license": "ISC"
+    },
+    "node_modules/iterator.prototype": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.4.tgz",
+      "integrity": "sha512-x4WH0BWmrMmg4oHHl+duwubhrvczGlyuGAZu3nvrf0UXOfPu8IhZObFEr7DE/iv01YgVZrsOiRcqw2srkKEDIA==",
+      "license": "MIT",
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-object-atoms": "^1.0.0",
+        "get-intrinsic": "^1.2.6",
+        "has-symbols": "^1.1.0",
+        "reflect.getprototypeof": "^1.0.8",
+        "set-function-name": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "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==",
+      "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/jiti": {
+      "version": "1.21.7",
+      "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
+      "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
+      "license": "MIT",
+      "bin": {
+        "jiti": "bin/jiti.js"
+      }
+    },
+    "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==",
+      "license": "MIT"
+    },
+    "node_modules/js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jsesc": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
+      "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
+      "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==",
+      "license": "MIT",
+      "peer": true
+    },
+    "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": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+      "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
+      "license": "(AFL-2.1 OR BSD-3-Clause)"
+    },
+    "node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "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==",
+      "license": "MIT",
+      "peer": true
+    },
+    "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/jsonfile": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+      "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "universalify": "^2.0.0"
+      },
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/jsx-ast-utils": {
+      "version": "3.3.5",
+      "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
+      "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
+      "license": "MIT",
+      "dependencies": {
+        "array-includes": "^3.1.6",
+        "array.prototype.flat": "^1.3.1",
+        "object.assign": "^4.1.4",
+        "object.values": "^1.1.6"
+      },
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true,
+      "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==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/lilconfig": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+      "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antonk52"
+      }
+    },
+    "node_modules/lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+      "license": "MIT"
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/loose-envify": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+      "license": "MIT",
+      "dependencies": {
+        "js-tokens": "^3.0.0 || ^4.0.0"
+      },
+      "bin": {
+        "loose-envify": "cli.js"
+      }
+    },
+    "node_modules/loupe": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz",
+      "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==",
+      "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/lucide-react": {
+      "version": "0.469.0",
+      "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.469.0.tgz",
+      "integrity": "sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==",
+      "license": "ISC",
+      "peerDependencies": {
+        "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+      }
+    },
+    "node_modules/magic-string": {
+      "version": "0.30.17",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
+      "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.0"
+      }
+    },
+    "node_modules/math-intrinsics": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+      "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/merge-descriptors": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+      "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+      "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+      "license": "MIT",
+      "dependencies": {
+        "braces": "^3.0.3",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+      "license": "MIT",
+      "bin": {
+        "mime": "cli.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.53.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz",
+      "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types/node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minipass": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+      "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/morgan": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
+      "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
+      "license": "MIT",
+      "dependencies": {
+        "basic-auth": "~2.0.1",
+        "debug": "2.6.9",
+        "depd": "~2.0.0",
+        "on-finished": "~2.3.0",
+        "on-headers": "~1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/morgan/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/morgan/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "license": "MIT"
+    },
+    "node_modules/morgan/node_modules/on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
+      "license": "MIT",
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "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==",
+      "license": "MIT"
+    },
+    "node_modules/mz": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+      "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+      "license": "MIT",
+      "dependencies": {
+        "any-promise": "^1.0.0",
+        "object-assign": "^4.0.1",
+        "thenify-all": "^1.0.0"
+      }
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.8",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
+      "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
+      "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==",
+      "license": "MIT"
+    },
+    "node_modules/negotiator": {
+      "version": "0.6.4",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz",
+      "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/node-domexception": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+      "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/jimmywarting"
+        },
+        {
+          "type": "github",
+          "url": "https://paypal.me/jimmywarting"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.5.0"
+      }
+    },
+    "node_modules/node-fetch": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+      "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+      "license": "MIT",
+      "dependencies": {
+        "whatwg-url": "^5.0.0"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.19",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+      "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "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-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/normalize-range": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+      "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/npm-install-checks": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz",
+      "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "semver": "^7.1.1"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "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/npm-package-arg": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz",
+      "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "hosted-git-info": "^6.0.0",
+        "proc-log": "^3.0.0",
+        "semver": "^7.3.5",
+        "validate-npm-package-name": "^5.0.0"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/npm-pick-manifest": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.2.tgz",
+      "integrity": "sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "npm-install-checks": "^6.0.0",
+        "npm-normalize-package-bin": "^3.0.0",
+        "npm-package-arg": "^10.0.0",
+        "semver": "^7.3.5"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-hash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+      "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.13.3",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
+      "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/object.assign": {
+      "version": "4.1.7",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
+      "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0",
+        "has-symbols": "^1.1.0",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object.entries": {
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
+      "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/object.fromentries": {
+      "version": "2.0.8",
+      "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
+      "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.2",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object.values": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
+      "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/on-finished": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+      "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+      "license": "MIT",
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/on-headers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+      "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/openai": {
+      "version": "4.77.0",
+      "resolved": "https://registry.npmjs.org/openai/-/openai-4.77.0.tgz",
+      "integrity": "sha512-WWacavtns/7pCUkOWvQIjyOfcdr9X+9n9Vvb0zFeKVDAqwCMDHB+iSr24SVaBAhplvSG6JrRXFpcNM9gWhOGIw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@types/node": "^18.11.18",
+        "@types/node-fetch": "^2.6.4",
+        "abort-controller": "^3.0.0",
+        "agentkeepalive": "^4.2.1",
+        "form-data-encoder": "1.7.2",
+        "formdata-node": "^4.3.2",
+        "node-fetch": "^2.6.7"
+      },
+      "bin": {
+        "openai": "bin/cli"
+      },
+      "peerDependencies": {
+        "zod": "^3.23.8"
+      },
+      "peerDependenciesMeta": {
+        "zod": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/openai/node_modules/@types/node": {
+      "version": "18.19.68",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.68.tgz",
+      "integrity": "sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw==",
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~5.26.4"
+      }
+    },
+    "node_modules/openai/node_modules/undici-types": {
+      "version": "5.26.5",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+      "license": "MIT"
+    },
+    "node_modules/optionator": {
+      "version": "0.9.4",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+      "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+      "license": "MIT",
+      "peer": true,
+      "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==",
+      "license": "MIT",
+      "peer": true,
+      "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==",
+      "license": "MIT",
+      "peer": true,
+      "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==",
+      "license": "BlueOak-1.0.0"
+    },
+    "node_modules/pako": {
+      "version": "0.2.9",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
+      "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true,
+      "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==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "license": "MIT"
+    },
+    "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==",
+      "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==",
+      "license": "ISC"
+    },
+    "node_modules/path-to-regexp": {
+      "version": "0.1.12",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+      "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
+      "license": "MIT"
+    },
+    "node_modules/pathe": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+      "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/pathval": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz",
+      "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.16"
+      }
+    },
+    "node_modules/peek-stream": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/peek-stream/-/peek-stream-1.1.3.tgz",
+      "integrity": "sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "duplexify": "^3.5.0",
+        "through2": "^2.0.3"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pify": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/pirates": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
+      "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/possible-typed-array-names": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
+      "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.4.49",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
+      "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
+      "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.7",
+        "picocolors": "^1.1.1",
+        "source-map-js": "^1.2.1"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/postcss-import": {
+      "version": "15.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+      "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+      "license": "MIT",
+      "dependencies": {
+        "postcss-value-parser": "^4.0.0",
+        "read-cache": "^1.0.0",
+        "resolve": "^1.1.7"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.0.0"
+      }
+    },
+    "node_modules/postcss-import/node_modules/resolve": {
+      "version": "1.22.10",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+      "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+      "license": "MIT",
+      "dependencies": {
+        "is-core-module": "^2.16.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/postcss-js": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
+      "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
+      "license": "MIT",
+      "dependencies": {
+        "camelcase-css": "^2.0.1"
+      },
+      "engines": {
+        "node": "^12 || ^14 || >= 16"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      },
+      "peerDependencies": {
+        "postcss": "^8.4.21"
+      }
+    },
+    "node_modules/postcss-load-config": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
+      "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "lilconfig": "^3.0.0",
+        "yaml": "^2.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      },
+      "peerDependencies": {
+        "postcss": ">=8.0.9",
+        "ts-node": ">=9.0.0"
+      },
+      "peerDependenciesMeta": {
+        "postcss": {
+          "optional": true
+        },
+        "ts-node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/postcss-nested": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
+      "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "postcss-selector-parser": "^6.1.1"
+      },
+      "engines": {
+        "node": ">=12.0"
+      },
+      "peerDependencies": {
+        "postcss": "^8.2.14"
+      }
+    },
+    "node_modules/postcss-selector-parser": {
+      "version": "6.1.2",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+      "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+      "license": "MIT",
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-value-parser": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+      "license": "MIT"
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/prettier": {
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+      "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "prettier": "bin-prettier.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
+      }
+    },
+    "node_modules/proc-log": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz",
+      "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/promise-inflight": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
+      "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/promise-retry": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
+      "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "err-code": "^2.0.2",
+        "retry": "^0.12.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/prop-types": {
+      "version": "15.8.1",
+      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+      "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+      "license": "MIT",
+      "dependencies": {
+        "loose-envify": "^1.4.0",
+        "object-assign": "^4.1.1",
+        "react-is": "^16.13.1"
+      }
+    },
+    "node_modules/proxy-addr": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+      "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+      "license": "MIT",
+      "dependencies": {
+        "forwarded": "0.2.0",
+        "ipaddr.js": "1.9.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/pump": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+      "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "node_modules/pumpify": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+      "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "duplexify": "^3.6.0",
+        "inherits": "^2.0.3",
+        "pump": "^2.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==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/qs": {
+      "version": "6.13.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+      "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "side-channel": "^1.0.6"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/range-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/raw-body": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+      "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+      "license": "MIT",
+      "dependencies": {
+        "bytes": "3.1.2",
+        "http-errors": "2.0.0",
+        "iconv-lite": "0.4.24",
+        "unpipe": "1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/react": {
+      "version": "19.0.0",
+      "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
+      "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/react-dom": {
+      "version": "19.0.0",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
+      "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==",
+      "license": "MIT",
+      "dependencies": {
+        "scheduler": "^0.25.0"
+      },
+      "peerDependencies": {
+        "react": "^19.0.0"
+      }
+    },
+    "node_modules/react-hook-form": {
+      "version": "7.54.2",
+      "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.54.2.tgz",
+      "integrity": "sha512-eHpAUgUjWbZocoQYUHposymRb4ZP6d0uwUnooL2uOybA9/3tPUvoAKqEWK1WaSiTxxOfTpffNZP7QwlnM3/gEg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/react-hook-form"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17 || ^18 || ^19"
+      }
+    },
+    "node_modules/react-is": {
+      "version": "16.13.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+      "license": "MIT"
+    },
+    "node_modules/react-refresh": {
+      "version": "0.14.2",
+      "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
+      "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/react-remove-scroll": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz",
+      "integrity": "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==",
+      "license": "MIT",
+      "dependencies": {
+        "react-remove-scroll-bar": "^2.3.7",
+        "react-style-singleton": "^2.2.1",
+        "tslib": "^2.1.0",
+        "use-callback-ref": "^1.3.3",
+        "use-sidecar": "^1.1.2"
+      },
+      "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-router": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.0.tgz",
+      "integrity": "sha512-VcFhWqkNIcojDRYaUO8qV0Jib52s9ULpCp3nkBbmrvtoCVFRp6tmk3tJ2w9BZauVctA1YRnJlFYDn9iJRuCpGA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/cookie": "^0.6.0",
+        "cookie": "^1.0.1",
+        "set-cookie-parser": "^2.6.0",
+        "turbo-stream": "2.4.0"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      },
+      "peerDependencies": {
+        "react": ">=18",
+        "react-dom": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/react-router-dom": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.1.1.tgz",
+      "integrity": "sha512-vSrQHWlJ5DCfyrhgo0k6zViOe9ToK8uT5XGSmnuC2R3/g261IdIMpZVqfjD6vWSXdnf5Czs4VA/V60oVR6/jnA==",
+      "license": "MIT",
+      "dependencies": {
+        "react-router": "7.1.1"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      },
+      "peerDependencies": {
+        "react": ">=18",
+        "react-dom": ">=18"
+      }
+    },
+    "node_modules/react-router-dom/node_modules/cookie": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+      "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/react-router-dom/node_modules/react-router": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.1.tgz",
+      "integrity": "sha512-39sXJkftkKWRZ2oJtHhCxmoCrBCULr/HAH4IT5DHlgu/Q0FCPV0S4Lx+abjDTx/74xoZzNYDYbOZWlJjruyuDQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/cookie": "^0.6.0",
+        "cookie": "^1.0.1",
+        "set-cookie-parser": "^2.6.0",
+        "turbo-stream": "2.4.0"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      },
+      "peerDependencies": {
+        "react": ">=18",
+        "react-dom": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/react-router/node_modules/cookie": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+      "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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-cache": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+      "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+      "license": "MIT",
+      "dependencies": {
+        "pify": "^2.3.0"
+      }
+    },
+    "node_modules/readable-stream": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "node_modules/readable-stream/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/readdirp": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
+      "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/reflect.getprototypeof": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.9.tgz",
+      "integrity": "sha512-r0Ay04Snci87djAsI4U+WNRcSw5S4pOH7qFjd/veA5gC7TbqESR3tcj28ia95L/fYUDw11JKP7uqUKUAfVvV5Q==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "define-properties": "^1.2.1",
+        "dunder-proto": "^1.0.1",
+        "es-abstract": "^1.23.6",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.6",
+        "gopd": "^1.2.0",
+        "which-builtin-type": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/regexp.prototype.flags": {
+      "version": "1.5.3",
+      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz",
+      "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-errors": "^1.3.0",
+        "set-function-name": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/resolve": {
+      "version": "2.0.0-next.5",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
+      "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
+      "license": "MIT",
+      "dependencies": {
+        "is-core-module": "^2.13.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/retry": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+      "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "license": "MIT",
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rollup": {
+      "version": "4.29.0",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.29.0.tgz",
+      "integrity": "sha512-pdftUn12oB9Qlka+Vpyc39R28D4NsP9Sz6neepSrekofJmWzPD1sxcSO9hEOxFF8+7Kz3sHvwSkkRREI28M1/w==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "1.0.6"
+      },
+      "bin": {
+        "rollup": "dist/bin/rollup"
+      },
+      "engines": {
+        "node": ">=18.0.0",
+        "npm": ">=8.0.0"
+      },
+      "optionalDependencies": {
+        "@rollup/rollup-android-arm-eabi": "4.29.0",
+        "@rollup/rollup-android-arm64": "4.29.0",
+        "@rollup/rollup-darwin-arm64": "4.29.0",
+        "@rollup/rollup-darwin-x64": "4.29.0",
+        "@rollup/rollup-freebsd-arm64": "4.29.0",
+        "@rollup/rollup-freebsd-x64": "4.29.0",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.29.0",
+        "@rollup/rollup-linux-arm-musleabihf": "4.29.0",
+        "@rollup/rollup-linux-arm64-gnu": "4.29.0",
+        "@rollup/rollup-linux-arm64-musl": "4.29.0",
+        "@rollup/rollup-linux-loongarch64-gnu": "4.29.0",
+        "@rollup/rollup-linux-powerpc64le-gnu": "4.29.0",
+        "@rollup/rollup-linux-riscv64-gnu": "4.29.0",
+        "@rollup/rollup-linux-s390x-gnu": "4.29.0",
+        "@rollup/rollup-linux-x64-gnu": "4.29.0",
+        "@rollup/rollup-linux-x64-musl": "4.29.0",
+        "@rollup/rollup-win32-arm64-msvc": "4.29.0",
+        "@rollup/rollup-win32-ia32-msvc": "4.29.0",
+        "@rollup/rollup-win32-x64-msvc": "4.29.0",
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/safe-array-concat": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
+      "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.2",
+        "get-intrinsic": "^1.2.6",
+        "has-symbols": "^1.1.0",
+        "isarray": "^2.0.5"
+      },
+      "engines": {
+        "node": ">=0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/safe-array-concat/node_modules/isarray": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+      "license": "MIT"
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/safe-regex-test": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
+      "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "is-regex": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "license": "MIT"
+    },
+    "node_modules/scheduler": {
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz",
+      "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==",
+      "license": "MIT"
+    },
+    "node_modules/semver": {
+      "version": "7.6.3",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+      "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/send": {
+      "version": "0.19.0",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+      "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
+      "license": "MIT",
+      "dependencies": {
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "destroy": "1.2.0",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "fresh": "0.5.2",
+        "http-errors": "2.0.0",
+        "mime": "1.6.0",
+        "ms": "2.1.3",
+        "on-finished": "2.4.1",
+        "range-parser": "~1.2.1",
+        "statuses": "2.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/send/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "license": "MIT",
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/send/node_modules/debug/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "license": "MIT"
+    },
+    "node_modules/send/node_modules/encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/serve-static": {
+      "version": "1.16.2",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+      "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
+      "license": "MIT",
+      "dependencies": {
+        "encodeurl": "~2.0.0",
+        "escape-html": "~1.0.3",
+        "parseurl": "~1.3.3",
+        "send": "0.19.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/set-cookie-parser": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
+      "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
+      "license": "MIT"
+    },
+    "node_modules/set-function-length": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+      "license": "MIT",
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/set-function-name": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+      "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+      "license": "MIT",
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "functions-have-names": "^1.2.3",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/setprototypeof": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+      "license": "ISC"
+    },
+    "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==",
+      "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==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/side-channel": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+      "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.3",
+        "side-channel-list": "^1.0.0",
+        "side-channel-map": "^1.0.1",
+        "side-channel-weakmap": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-list": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+      "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-map": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+      "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-weakmap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+      "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3",
+        "side-channel-map": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "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==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/smol-toml": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.1.tgz",
+      "integrity": "sha512-tEYNll18pPKHroYSmLLrksq233j021G0giwW7P3D24jC54pQ5W5BXMsQ/Mvw1OJCmEYDgY+lrzT+3nNUtoNfXQ==",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">= 18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/cyyynthia"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "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==",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-support": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+      "license": "MIT",
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.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.20",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz",
+      "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==",
+      "dev": true,
+      "license": "CC0-1.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/statuses": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+      "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/std-env": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz",
+      "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/stream-shift": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz",
+      "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/stream-slice": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/stream-slice/-/stream-slice-0.1.2.tgz",
+      "integrity": "sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA==",
+      "license": "MIT"
+    },
+    "node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/string_decoder/node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "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==",
+      "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==",
+      "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/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "license": "MIT",
+      "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==",
+      "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==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string.prototype.matchall": {
+      "version": "4.0.12",
+      "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz",
+      "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.6",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.0.0",
+        "get-intrinsic": "^1.2.6",
+        "gopd": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "internal-slot": "^1.1.0",
+        "regexp.prototype.flags": "^1.5.3",
+        "set-function-name": "^2.0.2",
+        "side-channel": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string.prototype.repeat": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
+      "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
+      "license": "MIT",
+      "dependencies": {
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.17.5"
+      }
+    },
+    "node_modules/string.prototype.trim": {
+      "version": "1.2.10",
+      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
+      "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.2",
+        "define-data-property": "^1.1.4",
+        "define-properties": "^1.2.1",
+        "es-abstract": "^1.23.5",
+        "es-object-atoms": "^1.0.0",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string.prototype.trimend": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
+      "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.2",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string.prototype.trimstart": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+      "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "define-properties": "^1.2.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+      "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^6.0.1"
+      },
+      "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==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi-cjs/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==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/sucrase": {
+      "version": "3.35.0",
+      "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
+      "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.2",
+        "commander": "^4.0.0",
+        "glob": "^10.3.10",
+        "lines-and-columns": "^1.1.6",
+        "mz": "^2.7.0",
+        "pirates": "^4.0.1",
+        "ts-interface-checker": "^0.1.9"
+      },
+      "bin": {
+        "sucrase": "bin/sucrase",
+        "sucrase-node": "bin/sucrase-node"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/tailwind-merge": {
+      "version": "2.5.5",
+      "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.5.tgz",
+      "integrity": "sha512-0LXunzzAZzo0tEPxV3I297ffKZPlKDrjj7NXphC8V5ak9yHC5zRmxnOe2m/Rd/7ivsOMJe3JZ2JVocoDdQTRBA==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/dcastil"
+      }
+    },
+    "node_modules/tailwindcss": {
+      "version": "3.4.17",
+      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
+      "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
+      "license": "MIT",
+      "dependencies": {
+        "@alloc/quick-lru": "^5.2.0",
+        "arg": "^5.0.2",
+        "chokidar": "^3.6.0",
+        "didyoumean": "^1.2.2",
+        "dlv": "^1.1.3",
+        "fast-glob": "^3.3.2",
+        "glob-parent": "^6.0.2",
+        "is-glob": "^4.0.3",
+        "jiti": "^1.21.6",
+        "lilconfig": "^3.1.3",
+        "micromatch": "^4.0.8",
+        "normalize-path": "^3.0.0",
+        "object-hash": "^3.0.0",
+        "picocolors": "^1.1.1",
+        "postcss": "^8.4.47",
+        "postcss-import": "^15.1.0",
+        "postcss-js": "^4.0.1",
+        "postcss-load-config": "^4.0.2",
+        "postcss-nested": "^6.2.0",
+        "postcss-selector-parser": "^6.1.2",
+        "resolve": "^1.22.8",
+        "sucrase": "^3.35.0"
+      },
+      "bin": {
+        "tailwind": "lib/cli.js",
+        "tailwindcss": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/tailwindcss-animate": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz",
+      "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==",
+      "license": "MIT",
+      "peerDependencies": {
+        "tailwindcss": ">=3.0.0 || insiders"
+      }
+    },
+    "node_modules/tailwindcss/node_modules/chokidar": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+      "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+      "license": "MIT",
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/tailwindcss/node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "license": "MIT",
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/tailwindcss/node_modules/resolve": {
+      "version": "1.22.10",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+      "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+      "license": "MIT",
+      "dependencies": {
+        "is-core-module": "^2.16.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/thenify": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+      "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+      "license": "MIT",
+      "dependencies": {
+        "any-promise": "^1.0.0"
+      }
+    },
+    "node_modules/thenify-all": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+      "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+      "license": "MIT",
+      "dependencies": {
+        "thenify": ">= 3.1.0 < 4"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/through2": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+      "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "readable-stream": "~2.3.6",
+        "xtend": "~4.0.1"
+      }
+    },
+    "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": "0.3.1",
+      "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz",
+      "integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/tinypool": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz",
+      "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.0.0 || >=20.0.0"
+      }
+    },
+    "node_modules/tinyrainbow": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz",
+      "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/tinyspy": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz",
+      "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/toidentifier": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+      "license": "MIT"
+    },
+    "node_modules/ts-api-utils": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz",
+      "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=16"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.2.0"
+      }
+    },
+    "node_modules/ts-interface-checker": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
+      "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/tsconfck": {
+      "version": "3.1.4",
+      "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.4.tgz",
+      "integrity": "sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "tsconfck": "bin/tsconfck.js"
+      },
+      "engines": {
+        "node": "^18 || >=20"
+      },
+      "peerDependencies": {
+        "typescript": "^5.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "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/turbo-stream": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",
+      "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==",
+      "license": "ISC"
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "prelude-ls": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+      "license": "MIT",
+      "dependencies": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/typed-array-buffer": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
+      "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "is-typed-array": "^1.1.14"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/typed-array-byte-length": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
+      "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "for-each": "^0.3.3",
+        "gopd": "^1.2.0",
+        "has-proto": "^1.2.0",
+        "is-typed-array": "^1.1.14"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/typed-array-byte-offset": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
+      "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
+      "license": "MIT",
+      "dependencies": {
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.8",
+        "for-each": "^0.3.3",
+        "gopd": "^1.2.0",
+        "has-proto": "^1.2.0",
+        "is-typed-array": "^1.1.15",
+        "reflect.getprototypeof": "^1.0.9"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/typed-array-length": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
+      "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "for-each": "^0.3.3",
+        "gopd": "^1.0.1",
+        "is-typed-array": "^1.1.13",
+        "possible-typed-array-names": "^1.0.0",
+        "reflect.getprototypeof": "^1.0.6"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "5.7.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
+      "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/typescript-eslint": {
+      "version": "8.18.1",
+      "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.18.1.tgz",
+      "integrity": "sha512-Mlaw6yxuaDEPQvb/2Qwu3/TfgeBHy9iTJ3mTwe7OvpPmF6KPQjVOfGyEJpPv6Ez2C34OODChhXrzYw/9phI0MQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/eslint-plugin": "8.18.1",
+        "@typescript-eslint/parser": "8.18.1",
+        "@typescript-eslint/utils": "8.18.1"
+      },
+      "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",
+        "typescript": ">=4.8.4 <5.8.0"
+      }
+    },
+    "node_modules/unbox-primitive": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
+      "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "has-bigints": "^1.0.2",
+        "has-symbols": "^1.1.0",
+        "which-boxed-primitive": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/undici": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.0.tgz",
+      "integrity": "sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=18.17"
+      }
+    },
+    "node_modules/undici-types": {
+      "version": "6.19.8",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+      "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
+      "license": "MIT"
+    },
+    "node_modules/universalify": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+      "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
+    "node_modules/unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz",
+      "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
+      "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.0"
+      },
+      "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==",
+      "license": "BSD-2-Clause",
+      "peer": true,
+      "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/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+      "license": "MIT"
+    },
+    "node_modules/utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/uuid": {
+      "version": "11.0.3",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.3.tgz",
+      "integrity": "sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==",
+      "funding": [
+        "https://github.com/sponsors/broofa",
+        "https://github.com/sponsors/ctavan"
+      ],
+      "license": "MIT",
+      "bin": {
+        "uuid": "dist/esm/bin/uuid"
+      }
+    },
+    "node_modules/valibot": {
+      "version": "0.41.0",
+      "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.41.0.tgz",
+      "integrity": "sha512-igDBb8CTYr8YTQlOKgaN9nSS0Be7z+WRuaeYqGf3Cjz3aKmSnqEmYnkfVjzIuumGqfHpa3fLIvMEAfhrpqN8ng==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "typescript": ">=5"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "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/validate-npm-package-name": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz",
+      "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/vite": {
+      "version": "5.4.11",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
+      "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
+      "license": "MIT",
+      "dependencies": {
+        "esbuild": "^0.21.3",
+        "postcss": "^8.4.43",
+        "rollup": "^4.20.0"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^18.0.0 || >=20.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      },
+      "peerDependencies": {
+        "@types/node": "^18.0.0 || >=20.0.0",
+        "less": "*",
+        "lightningcss": "^1.21.0",
+        "sass": "*",
+        "sass-embedded": "*",
+        "stylus": "*",
+        "sugarss": "*",
+        "terser": "^5.4.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "lightningcss": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vite-node": {
+      "version": "3.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.0-beta.2.tgz",
+      "integrity": "sha512-ofTf6cfRdL30Wbl9n/BX81EyIR5s4PReLmSurrxQ+koLaWUNOEo8E0lCM53OJkb8vpa2URM2nSrxZsIFyvY1rg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cac": "^6.7.14",
+        "debug": "^4.4.0",
+        "es-module-lexer": "^1.5.4",
+        "pathe": "^1.1.2",
+        "vite": "^5.0.0 || ^6.0.0"
+      },
+      "bin": {
+        "vite-node": "vite-node.mjs"
+      },
+      "engines": {
+        "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/vite-plugin-top-level-await": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/vite-plugin-top-level-await/-/vite-plugin-top-level-await-1.4.4.tgz",
+      "integrity": "sha512-QyxQbvcMkgt+kDb12m2P8Ed35Sp6nXP+l8ptGrnHV9zgYDUpraO0CPdlqLSeBqvY2DToR52nutDG7mIHuysdiw==",
+      "license": "MIT",
+      "dependencies": {
+        "@rollup/plugin-virtual": "^3.0.2",
+        "@swc/core": "^1.7.0",
+        "uuid": "^10.0.0"
+      },
+      "peerDependencies": {
+        "vite": ">=2.8"
+      }
+    },
+    "node_modules/vite-plugin-top-level-await/node_modules/uuid": {
+      "version": "10.0.0",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
+      "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
+      "funding": [
+        "https://github.com/sponsors/broofa",
+        "https://github.com/sponsors/ctavan"
+      ],
+      "license": "MIT",
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/vite-plugin-wasm": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmjs.org/vite-plugin-wasm/-/vite-plugin-wasm-3.4.1.tgz",
+      "integrity": "sha512-ja3nSo2UCkVeitltJGkS3pfQHAanHv/DqGatdI39ja6McgABlpsZ5hVgl6wuR8Qx5etY3T5qgDQhOWzc5RReZA==",
+      "license": "MIT",
+      "peerDependencies": {
+        "vite": "^2 || ^3 || ^4 || ^5 || ^6"
+      }
+    },
+    "node_modules/vite-tsconfig-paths": {
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz",
+      "integrity": "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "^4.1.1",
+        "globrex": "^0.1.2",
+        "tsconfck": "^3.0.3"
+      },
+      "peerDependencies": {
+        "vite": "*"
+      },
+      "peerDependenciesMeta": {
+        "vite": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vitest": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.8.tgz",
+      "integrity": "sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/expect": "2.1.8",
+        "@vitest/mocker": "2.1.8",
+        "@vitest/pretty-format": "^2.1.8",
+        "@vitest/runner": "2.1.8",
+        "@vitest/snapshot": "2.1.8",
+        "@vitest/spy": "2.1.8",
+        "@vitest/utils": "2.1.8",
+        "chai": "^5.1.2",
+        "debug": "^4.3.7",
+        "expect-type": "^1.1.0",
+        "magic-string": "^0.30.12",
+        "pathe": "^1.1.2",
+        "std-env": "^3.8.0",
+        "tinybench": "^2.9.0",
+        "tinyexec": "^0.3.1",
+        "tinypool": "^1.0.1",
+        "tinyrainbow": "^1.2.0",
+        "vite": "^5.0.0",
+        "vite-node": "2.1.8",
+        "why-is-node-running": "^2.3.0"
+      },
+      "bin": {
+        "vitest": "vitest.mjs"
+      },
+      "engines": {
+        "node": "^18.0.0 || >=20.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      },
+      "peerDependencies": {
+        "@edge-runtime/vm": "*",
+        "@types/node": "^18.0.0 || >=20.0.0",
+        "@vitest/browser": "2.1.8",
+        "@vitest/ui": "2.1.8",
+        "happy-dom": "*",
+        "jsdom": "*"
+      },
+      "peerDependenciesMeta": {
+        "@edge-runtime/vm": {
+          "optional": true
+        },
+        "@types/node": {
+          "optional": true
+        },
+        "@vitest/browser": {
+          "optional": true
+        },
+        "@vitest/ui": {
+          "optional": true
+        },
+        "happy-dom": {
+          "optional": true
+        },
+        "jsdom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vitest/node_modules/vite-node": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.8.tgz",
+      "integrity": "sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cac": "^6.7.14",
+        "debug": "^4.3.7",
+        "es-module-lexer": "^1.5.4",
+        "pathe": "^1.1.2",
+        "vite": "^5.0.0"
+      },
+      "bin": {
+        "vite-node": "vite-node.mjs"
+      },
+      "engines": {
+        "node": "^18.0.0 || >=20.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/web-streams-polyfill": {
+      "version": "4.0.0-beta.3",
+      "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
+      "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+      "license": "MIT",
+      "dependencies": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
+    "node_modules/which": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz",
+      "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/which.js"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/which-boxed-primitive": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
+      "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
+      "license": "MIT",
+      "dependencies": {
+        "is-bigint": "^1.1.0",
+        "is-boolean-object": "^1.2.1",
+        "is-number-object": "^1.1.1",
+        "is-string": "^1.1.1",
+        "is-symbol": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-builtin-type": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
+      "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "function.prototype.name": "^1.1.6",
+        "has-tostringtag": "^1.0.2",
+        "is-async-function": "^2.0.0",
+        "is-date-object": "^1.1.0",
+        "is-finalizationregistry": "^1.1.0",
+        "is-generator-function": "^1.0.10",
+        "is-regex": "^1.2.1",
+        "is-weakref": "^1.0.2",
+        "isarray": "^2.0.5",
+        "which-boxed-primitive": "^1.1.0",
+        "which-collection": "^1.0.2",
+        "which-typed-array": "^1.1.16"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-builtin-type/node_modules/isarray": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+      "license": "MIT"
+    },
+    "node_modules/which-collection": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
+      "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+      "license": "MIT",
+      "dependencies": {
+        "is-map": "^2.0.3",
+        "is-set": "^2.0.3",
+        "is-weakmap": "^2.0.2",
+        "is-weakset": "^2.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/which-typed-array": {
+      "version": "1.1.18",
+      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz",
+      "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==",
+      "license": "MIT",
+      "dependencies": {
+        "available-typed-arrays": "^1.0.7",
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.3",
+        "for-each": "^0.3.3",
+        "gopd": "^1.2.0",
+        "has-tostringtag": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true,
+      "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==",
+      "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==",
+      "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-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "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==",
+      "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==",
+      "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==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/ansi-styles": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+      "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4"
+      }
+    },
+    "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/yaml": {
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz",
+      "integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==",
+      "license": "ISC",
+      "bin": {
+        "yaml": "bin.mjs"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "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==",
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/zod": {
+      "version": "3.24.1",
+      "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz",
+      "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/colinhacks"
+      }
+    }
+  }
+}
diff --git a/dashboard/package.json b/dashboard/package.json
new file mode 100644
index 000000000..9928ff298
--- /dev/null
+++ b/dashboard/package.json
@@ -0,0 +1,60 @@
+{
+  "name": "tensorzero-dashboard",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "build": "cross-env NODE_ENV=production react-router build",
+    "dev": "react-router dev",
+    "start": "cross-env NODE_ENV=production react-router-serve ./build/server/index.js",
+    "typecheck": "react-router typegen && tsc",
+    "test": "vitest"
+  },
+  "dependencies": {
+    "@clickhouse/client": "^1.10.0",
+    "@eslint/js": "^9.17.0",
+    "@hookform/resolvers": "^3.9.1",
+    "@radix-ui/react-accordion": "^1.2.2",
+    "@radix-ui/react-dialog": "^1.1.4",
+    "@radix-ui/react-label": "^2.1.1",
+    "@radix-ui/react-select": "^2.1.4",
+    "@radix-ui/react-slot": "^1.1.1",
+    "@react-router/node": "^7.0.2",
+    "@react-router/serve": "^7.0.2",
+    "ajv": "^8.17.1",
+    "class-variance-authority": "^0.7.1",
+    "clsx": "^2.1.1",
+    "eslint-plugin-react": "^7.37.2",
+    "isbot": "^5.1.17",
+    "json-schema": "^0.4.0",
+    "lucide-react": "^0.469.0",
+    "openai": "^4.77.0",
+    "react": "^19.0.0",
+    "react-dom": "^19.0.0",
+    "react-hook-form": "^7.54.2",
+    "react-router": "^7.1.0",
+    "react-router-dom": "^7.1.0",
+    "smol-toml": "^1.3.1",
+    "tailwind-merge": "^2.5.5",
+    "tailwindcss-animate": "^1.0.7",
+    "typescript-eslint": "^8.18.1",
+    "uuid": "^11.0.3",
+    "vite-plugin-top-level-await": "^1.4.4",
+    "vite-plugin-wasm": "^3.4.1",
+    "zod": "^3.24.1"
+  },
+  "devDependencies": {
+    "@react-router/dev": "^7.0.2",
+    "@types/json-schema": "^7.0.15",
+    "@types/node": "^20",
+    "@types/react": "^19.0.0",
+    "@types/react-dom": "^19.0.0",
+    "autoprefixer": "^10.4.20",
+    "cross-env": "^7.0.3",
+    "postcss": "^8.4.49",
+    "tailwindcss": "^3.4.16",
+    "typescript": "^5.7.2",
+    "vite": "^5.4.11",
+    "vite-tsconfig-paths": "^5.1.4",
+    "vitest": "^2.1.8"
+  }
+}
diff --git a/dashboard/postcss.config.js b/dashboard/postcss.config.js
new file mode 100644
index 000000000..2aa7205d4
--- /dev/null
+++ b/dashboard/postcss.config.js
@@ -0,0 +1,6 @@
+export default {
+  plugins: {
+    tailwindcss: {},
+    autoprefixer: {},
+  },
+};
diff --git a/dashboard/public/favicon.ico b/dashboard/public/favicon.ico
new file mode 100644
index 000000000..5dbdfcddc
Binary files /dev/null and b/dashboard/public/favicon.ico differ
diff --git a/dashboard/react-router.config.ts b/dashboard/react-router.config.ts
new file mode 100644
index 000000000..6ff16f917
--- /dev/null
+++ b/dashboard/react-router.config.ts
@@ -0,0 +1,7 @@
+import type { Config } from "@react-router/dev/config";
+
+export default {
+  // Config options...
+  // Server-side render by default, to enable SPA mode set this to `false`
+  ssr: true,
+} satisfies Config;
diff --git a/dashboard/tailwind.config.ts b/dashboard/tailwind.config.ts
new file mode 100644
index 000000000..5bbc89558
--- /dev/null
+++ b/dashboard/tailwind.config.ts
@@ -0,0 +1,93 @@
+import type { Config } from "tailwindcss";
+import animate from "tailwindcss-animate";
+
+export default {
+  darkMode: ["class"],
+  content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"],
+  theme: {
+    extend: {
+      fontFamily: {
+        sans: [
+          "Inter",
+          "ui-sans-serif",
+          "system-ui",
+          "sans-serif",
+          "Apple Color Emoji",
+          "Segoe UI Emoji",
+          "Segoe UI Symbol",
+          "Noto Color Emoji",
+        ],
+      },
+      borderRadius: {
+        lg: "var(--radius)",
+        md: "calc(var(--radius) - 2px)",
+        sm: "calc(var(--radius) - 4px)",
+      },
+      colors: {
+        background: "hsl(var(--background))",
+        foreground: "hsl(var(--foreground))",
+        card: {
+          DEFAULT: "hsl(var(--card))",
+          foreground: "hsl(var(--card-foreground))",
+        },
+        popover: {
+          DEFAULT: "hsl(var(--popover))",
+          foreground: "hsl(var(--popover-foreground))",
+        },
+        primary: {
+          DEFAULT: "hsl(var(--primary))",
+          foreground: "hsl(var(--primary-foreground))",
+        },
+        secondary: {
+          DEFAULT: "hsl(var(--secondary))",
+          foreground: "hsl(var(--secondary-foreground))",
+        },
+        muted: {
+          DEFAULT: "hsl(var(--muted))",
+          foreground: "hsl(var(--muted-foreground))",
+        },
+        accent: {
+          DEFAULT: "hsl(var(--accent))",
+          foreground: "hsl(var(--accent-foreground))",
+        },
+        destructive: {
+          DEFAULT: "hsl(var(--destructive))",
+          foreground: "hsl(var(--destructive-foreground))",
+        },
+        border: "hsl(var(--border))",
+        input: "hsl(var(--input))",
+        ring: "hsl(var(--ring))",
+        chart: {
+          "1": "hsl(var(--chart-1))",
+          "2": "hsl(var(--chart-2))",
+          "3": "hsl(var(--chart-3))",
+          "4": "hsl(var(--chart-4))",
+          "5": "hsl(var(--chart-5))",
+        },
+      },
+      keyframes: {
+        "accordion-down": {
+          from: {
+            height: "0",
+          },
+          to: {
+            height: "var(--radix-accordion-content-height)",
+          },
+        },
+        "accordion-up": {
+          from: {
+            height: "var(--radix-accordion-content-height)",
+          },
+          to: {
+            height: "0",
+          },
+        },
+      },
+      animation: {
+        "accordion-down": "accordion-down 0.2s ease-out",
+        "accordion-up": "accordion-up 0.2s ease-out",
+      },
+    },
+  },
+  plugins: [animate],
+} satisfies Config;
diff --git a/dashboard/tsconfig.json b/dashboard/tsconfig.json
new file mode 100644
index 000000000..dc391a45f
--- /dev/null
+++ b/dashboard/tsconfig.json
@@ -0,0 +1,27 @@
+{
+  "include": [
+    "**/*",
+    "**/.server/**/*",
+    "**/.client/**/*",
+    ".react-router/types/**/*"
+  ],
+  "compilerOptions": {
+    "lib": ["DOM", "DOM.Iterable", "ES2022"],
+    "types": ["node", "vite/client"],
+    "target": "ES2022",
+    "module": "ES2022",
+    "moduleResolution": "bundler",
+    "jsx": "react-jsx",
+    "rootDirs": [".", "./.react-router/types"],
+    "baseUrl": ".",
+    "paths": {
+      "~/*": ["./app/*"]
+    },
+    "esModuleInterop": true,
+    "verbatimModuleSyntax": true,
+    "noEmit": true,
+    "resolveJsonModule": true,
+    "skipLibCheck": true,
+    "strict": true
+  }
+}
diff --git a/dashboard/vite.config.ts b/dashboard/vite.config.ts
new file mode 100644
index 000000000..6a3f070d9
--- /dev/null
+++ b/dashboard/vite.config.ts
@@ -0,0 +1,16 @@
+import { reactRouter } from "@react-router/dev/vite";
+import autoprefixer from "autoprefixer";
+import tailwindcss from "tailwindcss";
+import { defineConfig } from "vite";
+import tsconfigPaths from "vite-tsconfig-paths";
+import wasm from "vite-plugin-wasm";
+import topLevelAwait from "vite-plugin-top-level-await";
+
+export default defineConfig({
+  css: {
+    postcss: {
+      plugins: [tailwindcss, autoprefixer],
+    },
+  },
+  plugins: [reactRouter(), tsconfigPaths(), wasm(), topLevelAwait()],
+});
diff --git a/gateway/src/inference/types/mod.rs b/gateway/src/inference/types/mod.rs
index 884968f71..f7aace26d 100644
--- a/gateway/src/inference/types/mod.rs
+++ b/gateway/src/inference/types/mod.rs
@@ -316,8 +316,8 @@ pub struct ChatInferenceDatabaseInsert {
     pub function_name: String,
     pub variant_name: String,
     pub episode_id: Uuid,
-    pub input: String,
-    pub output: String,
+    pub input: String,  // serialized `Input`
+    pub output: String, // serialized `Vec<ContentBlockOutput>`
     #[serde(skip_serializing_if = "Option::is_none")]
     pub tool_params: Option<ToolCallConfigDatabaseInsert>,
     pub inference_params: InferenceParams,
@@ -331,8 +331,8 @@ pub struct JsonInferenceDatabaseInsert {
     pub function_name: String,
     pub variant_name: String,
     pub episode_id: Uuid,
-    pub input: String,
-    pub output: String,
+    pub input: String,  // serialized `Input`
+    pub output: String, // serialized `JsonInferenceOutput`
     pub inference_params: InferenceParams,
     pub processing_time_ms: u32,
     pub output_schema: String,
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 000000000..9778c9bcf
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1700 @@
+{
+  "name": "tensorzero",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "devDependencies": {
+        "@typescript-eslint/eslint-plugin": "^8.14.0",
+        "@typescript-eslint/parser": "^8.14.0"
+      }
+    },
+    "node_modules/@eslint-community/eslint-utils": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz",
+      "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==",
+      "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/regexpp": {
+      "version": "4.12.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+      "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@eslint/config-array": {
+      "version": "0.18.0",
+      "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz",
+      "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "@eslint/object-schema": "^2.1.4",
+        "debug": "^4.3.1",
+        "minimatch": "^3.1.2"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/config-array/node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/@eslint/config-array/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "peer": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/@eslint/core": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz",
+      "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/eslintrc": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz",
+      "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^10.0.1",
+        "globals": "^14.0.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "peer": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/@eslint/js": {
+      "version": "9.14.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz",
+      "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/object-schema": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz",
+      "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/plugin-kit": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.2.tgz",
+      "integrity": "sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "levn": "^0.4.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@humanfs/core": {
+      "version": "0.19.1",
+      "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+      "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node": {
+      "version": "0.16.6",
+      "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
+      "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "dependencies": {
+        "@humanfs/core": "^0.19.1",
+        "@humanwhocodes/retry": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
+      "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": ">=18.18"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "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",
+      "peer": true,
+      "engines": {
+        "node": ">=12.22"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@humanwhocodes/retry": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz",
+      "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": ">=18.18"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@types/estree": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+      "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true
+    },
+    "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",
+      "peer": true
+    },
+    "node_modules/@typescript-eslint/eslint-plugin": {
+      "version": "8.14.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.14.0.tgz",
+      "integrity": "sha512-tqp8H7UWFaZj0yNO6bycd5YjMwxa6wIHOLZvWPkidwbgLCsBMetQoGj7DPuAlWa2yGO3H48xmPwjhsSPPCGU5w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/regexpp": "^4.10.0",
+        "@typescript-eslint/scope-manager": "8.14.0",
+        "@typescript-eslint/type-utils": "8.14.0",
+        "@typescript-eslint/utils": "8.14.0",
+        "@typescript-eslint/visitor-keys": "8.14.0",
+        "graphemer": "^1.4.0",
+        "ignore": "^5.3.1",
+        "natural-compare": "^1.4.0",
+        "ts-api-utils": "^1.3.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.0.0 || ^8.0.0-alpha.0",
+        "eslint": "^8.57.0 || ^9.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/parser": {
+      "version": "8.14.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.14.0.tgz",
+      "integrity": "sha512-2p82Yn9juUJq0XynBXtFCyrBDb6/dJombnz6vbo6mgQEtWHfvHbQuEa9kAOVIt1c9YFwi7H6WxtPj1kg+80+RA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "@typescript-eslint/scope-manager": "8.14.0",
+        "@typescript-eslint/types": "8.14.0",
+        "@typescript-eslint/typescript-estree": "8.14.0",
+        "@typescript-eslint/visitor-keys": "8.14.0",
+        "debug": "^4.3.4"
+      },
+      "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"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/scope-manager": {
+      "version": "8.14.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.14.0.tgz",
+      "integrity": "sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.14.0",
+        "@typescript-eslint/visitor-keys": "8.14.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/type-utils": {
+      "version": "8.14.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.14.0.tgz",
+      "integrity": "sha512-Xcz9qOtZuGusVOH5Uk07NGs39wrKkf3AxlkK79RBK6aJC1l03CobXjJbwBPSidetAOV+5rEVuiT1VSBUOAsanQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/typescript-estree": "8.14.0",
+        "@typescript-eslint/utils": "8.14.0",
+        "debug": "^4.3.4",
+        "ts-api-utils": "^1.3.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/types": {
+      "version": "8.14.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.14.0.tgz",
+      "integrity": "sha512-yjeB9fnO/opvLJFAsPNYlKPnEM8+z4og09Pk504dkqonT02AyL5Z9SSqlE0XqezS93v6CXn49VHvB2G7XSsl0g==",
+      "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.14.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.14.0.tgz",
+      "integrity": "sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "@typescript-eslint/types": "8.14.0",
+        "@typescript-eslint/visitor-keys": "8.14.0",
+        "debug": "^4.3.4",
+        "fast-glob": "^3.3.2",
+        "is-glob": "^4.0.3",
+        "minimatch": "^9.0.4",
+        "semver": "^7.6.0",
+        "ts-api-utils": "^1.3.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/utils": {
+      "version": "8.14.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.14.0.tgz",
+      "integrity": "sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.4.0",
+        "@typescript-eslint/scope-manager": "8.14.0",
+        "@typescript-eslint/types": "8.14.0",
+        "@typescript-eslint/typescript-estree": "8.14.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"
+      }
+    },
+    "node_modules/@typescript-eslint/visitor-keys": {
+      "version": "8.14.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.14.0.tgz",
+      "integrity": "sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "8.14.0",
+        "eslint-visitor-keys": "^3.4.3"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/acorn": {
+      "version": "8.14.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
+      "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "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",
+      "peer": true,
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "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-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",
+      "peer": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true,
+      "license": "Python-2.0",
+      "peer": true
+    },
+    "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/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "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",
+      "peer": true,
+      "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/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",
+      "peer": true,
+      "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",
+      "peer": true
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz",
+      "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.3.7",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+      "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "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",
+      "peer": true
+    },
+    "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",
+      "peer": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint": {
+      "version": "9.14.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz",
+      "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@eslint-community/regexpp": "^4.12.1",
+        "@eslint/config-array": "^0.18.0",
+        "@eslint/core": "^0.7.0",
+        "@eslint/eslintrc": "^3.1.0",
+        "@eslint/js": "9.14.0",
+        "@eslint/plugin-kit": "^0.2.0",
+        "@humanfs/node": "^0.16.6",
+        "@humanwhocodes/module-importer": "^1.0.1",
+        "@humanwhocodes/retry": "^0.4.0",
+        "@types/estree": "^1.0.6",
+        "@types/json-schema": "^7.0.15",
+        "ajv": "^6.12.4",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.2",
+        "debug": "^4.3.2",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^8.2.0",
+        "eslint-visitor-keys": "^4.2.0",
+        "espree": "^10.3.0",
+        "esquery": "^1.5.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",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.3",
+        "text-table": "^0.2.0"
+      },
+      "bin": {
+        "eslint": "bin/eslint.js"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://eslint.org/donate"
+      },
+      "peerDependencies": {
+        "jiti": "*"
+      },
+      "peerDependenciesMeta": {
+        "jiti": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/eslint-scope": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz",
+      "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "peer": true,
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "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/node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/eslint/node_modules/eslint-visitor-keys": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+      "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "peer": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/espree": {
+      "version": "10.3.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
+      "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "peer": true,
+      "dependencies": {
+        "acorn": "^8.14.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^4.2.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/espree/node_modules/eslint-visitor-keys": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+      "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/esquery": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+      "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "peer": true,
+      "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",
+      "peer": true,
+      "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",
+      "peer": true,
+      "engines": {
+        "node": ">=4.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",
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.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",
+      "peer": true
+    },
+    "node_modules/fast-glob": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+      "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-glob/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "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",
+      "peer": true
+    },
+    "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",
+      "peer": true
+    },
+    "node_modules/fastq": {
+      "version": "1.17.1",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+      "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "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",
+      "peer": true,
+      "dependencies": {
+        "flat-cache": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=16.0.0"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "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",
+      "peer": true,
+      "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",
+      "peer": true,
+      "dependencies": {
+        "flatted": "^3.2.9",
+        "keyv": "^4.5.4"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/flatted": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
+      "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
+      "dev": true,
+      "license": "ISC",
+      "peer": true
+    },
+    "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",
+      "peer": true,
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/globals": {
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+      "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/graphemer": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+      "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "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",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "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/import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "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",
+      "peer": true,
+      "engines": {
+        "node": ">=0.8.19"
+      }
+    },
+    "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-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-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "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",
+      "peer": true
+    },
+    "node_modules/js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "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",
+      "peer": true
+    },
+    "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",
+      "peer": true
+    },
+    "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",
+      "peer": true
+    },
+    "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",
+      "peer": true,
+      "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",
+      "peer": true,
+      "dependencies": {
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "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",
+      "peer": true,
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "braces": "^3.0.3",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "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/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/optionator": {
+      "version": "0.9.4",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+      "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "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",
+      "peer": true,
+      "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",
+      "peer": true,
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "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",
+      "peer": true,
+      "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",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "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",
+      "peer": true,
+      "engines": {
+        "node": ">= 0.8.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",
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/semver": {
+      "version": "7.6.3",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+      "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "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",
+      "peer": true,
+      "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",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "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",
+      "peer": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/ts-api-utils": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz",
+      "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=16"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.2.0"
+      }
+    },
+    "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",
+      "peer": true,
+      "dependencies": {
+        "prelude-ls": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "5.6.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
+      "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "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",
+      "peer": true,
+      "dependencies": {
+        "punycode": "^2.1.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",
+      "peer": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "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",
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "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",
+      "peer": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    }
+  }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 000000000..23b64343c
--- /dev/null
+++ b/package.json
@@ -0,0 +1,6 @@
+{
+  "devDependencies": {
+    "@typescript-eslint/eslint-plugin": "^8.14.0",
+    "@typescript-eslint/parser": "^8.14.0"
+  }
+}


Test patch:
diff --git a/dashboard/app/utils/clickhouse.test.ts b/dashboard/app/utils/clickhouse.test.ts
new file mode 100644
index 000000000..15d741e2f
--- /dev/null
+++ b/dashboard/app/utils/clickhouse.test.ts
@@ -0,0 +1,23 @@
+import { expect, test } from "vitest";
+import {
+  checkClickhouseConnection,
+  queryGoodBooleanMetricData,
+} from "./clickhouse";
+
+test("checkClickhouseConnection", async () => {
+  const result = await checkClickhouseConnection();
+  expect(result).toBe(true);
+});
+
+test("queryBooleanMetricData", async () => {
+  const result = await queryGoodBooleanMetricData(
+    "dashboard_fixture_extract_entities",
+    "dashboard_fixture_exact_match",
+    "JsonInference",
+    "id",
+    true,
+    undefined,
+  );
+  // The fixture was written to have 41 rows with good boolean metric data that should be returned
+  expect(result.length).toBe(41);
+});
diff --git a/dashboard/app/utils/config/index.test.ts b/dashboard/app/utils/config/index.test.ts
new file mode 100644
index 000000000..21e5875ee
--- /dev/null
+++ b/dashboard/app/utils/config/index.test.ts
@@ -0,0 +1,98 @@
+import { expect, test } from "vitest";
+import { loadConfig } from "./index.server";
+
+test("parse e2e config", async () => {
+  const validatedConfig = await loadConfig(
+    "./../gateway/tests/e2e/tensorzero.toml",
+  );
+  expect(validatedConfig).toBeDefined();
+  // Test something in the gateway config
+  expect(validatedConfig.gateway.bind_address).toBe("0.0.0.0:3000");
+
+  // Test something in the model config
+  const azureProvider =
+    validatedConfig.models["gpt-4o-mini-azure"].providers["azure"];
+  if (azureProvider.type === "azure") {
+    expect(azureProvider.deployment_id).toBe("gpt4o-mini-20240718");
+  } else {
+    throw new Error("Azure provider not found");
+  }
+  // Test a chat function
+  const basicTestFunction = validatedConfig.functions["basic_test"];
+  const openAiVariant = basicTestFunction.variants.openai;
+  if (openAiVariant.type === "chat_completion") {
+    expect(openAiVariant.model).toBe("gpt-4o-mini-2024-07-18");
+  } else {
+    throw new Error("OpenAI variant not found");
+  }
+
+  // Test a json function
+  const jsonTestFunction = validatedConfig.functions["json_success"];
+  if (jsonTestFunction.type === "json") {
+    expect(jsonTestFunction.output_schema).toBe(
+      "../../fixtures/config/functions/basic_test/output_schema.json",
+    );
+  } else {
+    throw new Error("JSON function not found");
+  }
+  const gcpVertexGeminiProVariant =
+    jsonTestFunction.variants["gcp-vertex-gemini-pro"];
+  if (gcpVertexGeminiProVariant.type === "chat_completion") {
+    expect(gcpVertexGeminiProVariant.model).toBe("gemini-1.5-pro-001");
+  } else {
+    throw new Error("GCP Vertex Gemini Pro variant not found");
+  }
+
+  // Test a chat function with best of n sampling
+  const bestOfNTestFunction = validatedConfig.functions["best_of_n"];
+  const bestOfNVariant = bestOfNTestFunction.variants["best_of_n_variant"];
+  if (bestOfNVariant.type === "experimental_best_of_n_sampling") {
+    expect(bestOfNVariant.candidates).toEqual(["variant0", "variant1"]);
+    const evaluator = bestOfNVariant.evaluator;
+    expect(evaluator.system_template).toBe(
+      "../../fixtures/config/functions/basic_test/prompt/system_template.minijinja",
+    );
+  } else {
+    throw new Error("Best of N variant not found");
+  }
+
+  // Test a chat function with dynamic in context learning
+  const basicTestDiclVariant =
+    validatedConfig.functions["basic_test"].variants["dicl"];
+  if (
+    basicTestDiclVariant.type === "experimental_dynamic_in_context_learning"
+  ) {
+    expect(basicTestDiclVariant.model).toBe("gpt-4o-mini-2024-07-18");
+    expect(basicTestDiclVariant.embedding_model).toBe("text-embedding-3-small");
+    expect(basicTestDiclVariant.k).toBe(3);
+  } else {
+    throw new Error("Dynamic in context learning variant not found");
+  }
+
+  // Test a chat function with tools
+  const weatherHelperFunction = validatedConfig.functions["weather_helper"];
+  if (weatherHelperFunction.type === "chat") {
+    expect(weatherHelperFunction.tools).toEqual(["get_temperature"]);
+    expect(weatherHelperFunction.tool_choice).toBe("auto");
+  } else {
+    throw new Error("Weather helper function not found");
+  }
+
+  // Test a metric config
+  const taskSuccessMetric = validatedConfig.metrics["task_success"];
+  if (taskSuccessMetric.type === "boolean") {
+    expect(taskSuccessMetric.optimize).toBe("max");
+    expect(taskSuccessMetric.level).toBe("inference");
+  } else {
+    throw new Error("Task success metric not found");
+  }
+
+  // Test a tool config
+  const getTemperatureTool = validatedConfig.tools["get_temperature"];
+  expect(getTemperatureTool.description).toBe(
+    "Get the current temperature in a given location",
+  );
+  expect(getTemperatureTool.parameters).toBe(
+    "../../fixtures/config/tools/get_temperature.json",
+  );
+});
diff --git a/dashboard/app/utils/config/models.test.ts b/dashboard/app/utils/config/models.test.ts
new file mode 100644
index 000000000..0e87e68ab
--- /dev/null
+++ b/dashboard/app/utils/config/models.test.ts
@@ -0,0 +1,55 @@
+import { describe, it, expect } from "vitest";
+import { get_fine_tuned_model_config, dump_model_config } from "./models";
+
+describe("get_fine_tuned_model_config", () => {
+  it("should create correct config for anthropic model", async () => {
+    const result = get_fine_tuned_model_config("claude-2", "anthropic");
+    expect(result).toEqual({
+      models: {
+        "claude-2": {
+          routing: ["claude-2"],
+          providers: {
+            "claude-2": {
+              type: "anthropic",
+              model_name: "claude-2",
+            },
+          },
+        },
+      },
+    });
+  });
+
+  it("should create correct config for aws bedrock model", async () => {
+    const result = get_fine_tuned_model_config(
+      "anthropic.claude-v2",
+      "aws_bedrock",
+    );
+    expect(result).toEqual({
+      models: {
+        "anthropic.claude-v2": {
+          routing: ["anthropic.claude-v2"],
+          providers: {
+            "anthropic.claude-v2": {
+              type: "aws_bedrock",
+              model_id: "anthropic.claude-v2",
+            },
+          },
+        },
+      },
+    });
+  });
+});
+
+describe("dump_model_config", () => {
+  it("should correctly stringify model config", () => {
+    const fullyQualifiedModelConfig = get_fine_tuned_model_config(
+      "test",
+      "dummy",
+    );
+
+    const result = dump_model_config(fullyQualifiedModelConfig);
+    const expected_result =
+      '[models.test]\nrouting = [ "test" ]\n\n[models.test.providers.test]\ntype = "dummy"\nmodel_name = "test"';
+    expect(result).toBe(expected_result);
+  });
+});
diff --git a/dashboard/app/utils/config/variant.test.ts b/dashboard/app/utils/config/variant.test.ts
new file mode 100644
index 000000000..9e2b10a51
--- /dev/null
+++ b/dashboard/app/utils/config/variant.test.ts
@@ -0,0 +1,61 @@
+import { type ChatCompletionConfig } from "./variant";
+
+import { describe, it, expect } from "vitest";
+import { create_dump_variant_config } from "./variant.server";
+
+describe("create_dump_variant_config", () => {
+  it("should create correct variant config TOML with string templates", () => {
+    const oldVariant: ChatCompletionConfig = {
+      type: "chat_completion" as const,
+      weight: 1,
+      model: "old-model",
+      json_mode: "strict" as const,
+      system_template: {
+        path: "/templates/system.j2",
+        content: "This content should not appear in output",
+      },
+    };
+
+    const result = create_dump_variant_config(
+      oldVariant,
+      "new-model",
+      "test_function",
+    );
+
+    expect(result).toContain("[functions.test_function.variants.new-model]");
+    expect(result).toContain("weight = 0");
+    expect(result).toContain('model = "new-model"');
+  });
+
+  it("should handle template objects and only serialize paths", () => {
+    const oldVariant: ChatCompletionConfig = {
+      type: "chat_completion" as const,
+      weight: 1,
+      model: "old-model",
+      json_mode: "strict" as const,
+      system_template: {
+        path: "/templates/system.j2",
+        content: "This content should not appear in output",
+      },
+      user_template: {
+        path: "/templates/user.j2",
+        content: "This content should not appear in output",
+      },
+      assistant_template: {
+        path: "/templates/assistant.j2",
+        content: "This content should not appear in output",
+      },
+    };
+
+    const result = create_dump_variant_config(
+      oldVariant,
+      "new-model",
+      "test_function",
+    );
+
+    expect(result).toContain('system_template = "/templates/system.j2"');
+    expect(result).toContain('user_template = "/templates/user.j2"');
+    expect(result).toContain('assistant_template = "/templates/assistant.j2"');
+    expect(result).not.toContain("content");
+  });
+});
diff --git a/dashboard/app/utils/fine_tuning/fireworks.test.ts b/dashboard/app/utils/fine_tuning/fireworks.test.ts
new file mode 100644
index 000000000..552fed138
--- /dev/null
+++ b/dashboard/app/utils/fine_tuning/fireworks.test.ts
@@ -0,0 +1,100 @@
+import { describe, it, expect } from "vitest";
+import { tensorzero_inference_to_fireworks_messages } from "./fireworks";
+import { create_env } from "../minijinja/pkg/minijinja_bindings";
+import type { ParsedInferenceRow } from "../clickhouse";
+
+describe("tensorzero_inference_to_fireworks_messages", async () => {
+  it("test simple json", () => {
+    const env = create_env({
+      system: "Do NER Properly!",
+    });
+    const row = {
+      variant_name: "turbo",
+      input: {
+        messages: [
+          {
+            role: "user",
+            content: [
+              {
+                type: "text",
+                value:
+                  'We have in no way seen any Iraqi troops in the city or in its approaches , " a U.N. relief official told Reuters .',
+              },
+            ],
+          },
+        ],
+      },
+      output: {
+        raw: '{"person":[],"organization":["U.N.","Reuters"],"location":[],"miscellaneous":["Iraqi"]}',
+        parsed: {
+          person: [],
+          organization: ["U.N.", "Reuters"],
+          location: [],
+          miscellaneous: ["Iraqi"],
+        },
+      },
+      episode_id: "0192ced0-a2c6-7323-be23-ce4124e683d3",
+    } as ParsedInferenceRow;
+
+    const fireworksExample = tensorzero_inference_to_fireworks_messages(
+      row,
+      env,
+    );
+    expect(fireworksExample.messages.length).toBe(3);
+    expect(fireworksExample.messages[0]).toStrictEqual({
+      role: "system",
+      content: "Do NER Properly!",
+    });
+    expect(fireworksExample.messages[1]).toStrictEqual({
+      role: "user",
+      content:
+        'We have in no way seen any Iraqi troops in the city or in its approaches , " a U.N. relief official told Reuters .',
+    });
+    expect(fireworksExample.messages[2]).toStrictEqual({
+      role: "assistant",
+      content:
+        '{"person":[],"organization":["U.N.","Reuters"],"location":[],"miscellaneous":["Iraqi"]}',
+    });
+  });
+  it("test chat", () => {
+    const env = create_env({
+      system: "Help me out with the weather!",
+    });
+    const row = {
+      variant_name: "turbo",
+      input: {
+        messages: [
+          {
+            role: "user",
+            content: [
+              {
+                type: "text",
+                value: "What is the weather in Columbus?",
+              },
+            ],
+          },
+        ],
+      },
+      output: [{ type: "text", text: "it is 34 and sunny" }],
+      episode_id: "0192ced0-a2c6-7323-be23-ce4124e683d3",
+    } as ParsedInferenceRow;
+
+    const fireworksExample = tensorzero_inference_to_fireworks_messages(
+      row,
+      env,
+    );
+    expect(fireworksExample.messages.length).toBe(3);
+    expect(fireworksExample.messages[0]).toStrictEqual({
+      role: "system",
+      content: "Help me out with the weather!",
+    });
+    expect(fireworksExample.messages[1]).toStrictEqual({
+      role: "user",
+      content: "What is the weather in Columbus?",
+    });
+    expect(fireworksExample.messages[2]).toStrictEqual({
+      role: "assistant",
+      content: "it is 34 and sunny",
+    });
+  });
+});
diff --git a/dashboard/app/utils/fine_tuning/openai.test.ts b/dashboard/app/utils/fine_tuning/openai.test.ts
new file mode 100644
index 000000000..5bf389f05
--- /dev/null
+++ b/dashboard/app/utils/fine_tuning/openai.test.ts
@@ -0,0 +1,232 @@
+import { describe, it, expect } from "vitest";
+import {
+  content_block_to_openai_message,
+  tensorzero_inference_to_openai_messages,
+} from "./openai";
+import { create_env } from "../minijinja/pkg/minijinja_bindings";
+import type {
+  ParsedInferenceRow,
+  textInputMessageContent,
+  toolCallInputMessageContent,
+  toolResultInputMessageContent,
+} from "../clickhouse";
+
+describe("content_block_to_openai_message", () => {
+  it("test text content block with no template", async () => {
+    const textContentBlock = {
+      type: "text",
+      value: "foo bar baz",
+    } as textInputMessageContent;
+    const env = create_env({});
+    const openai_message = content_block_to_openai_message(
+      textContentBlock,
+      "user",
+      env,
+    );
+    expect(openai_message).toEqual({ role: "user", content: "foo bar baz" });
+  });
+
+  it("test text content block with template", async () => {
+    const textContentBlock = {
+      type: "text",
+      value: { dogName: "Wally" },
+    } as textInputMessageContent;
+    const env = create_env({
+      assistant: "Hi, I'm your friendly canine assistant {{ dogName }}!",
+    });
+    const openai_message = content_block_to_openai_message(
+      textContentBlock,
+      "assistant",
+      env,
+    );
+    expect(openai_message).toEqual({
+      role: "assistant",
+      content: "Hi, I'm your friendly canine assistant Wally!",
+    });
+  });
+
+  it("test toolCall content block", async () => {
+    const toolCall = {
+      type: "tool_call",
+      name: "get_weather",
+      arguments: '{"location": "Manaus"}',
+      id: "tool_494949",
+    } as toolCallInputMessageContent;
+    const env = create_env({
+      assistant: "Hi, I'm your friendly canine assistant {{ dogName }}!",
+    });
+    const openai_message = content_block_to_openai_message(
+      toolCall,
+      "user",
+      env,
+    );
+    expect(openai_message).toEqual({
+      role: "assistant",
+      tool_calls: [
+        {
+          id: "tool_494949",
+          type: "function",
+          function: {
+            name: "get_weather",
+            arguments: '{"location": "Manaus"}',
+          },
+        },
+      ],
+    });
+  });
+
+  it("test toolResult content block", async () => {
+    const toolResult = {
+      type: "tool_result",
+      name: "get_weather",
+      result: "35 and sunny",
+      id: "tool_494949",
+    } as toolResultInputMessageContent;
+    const env = create_env({
+      assistant: "Hi, I'm your friendly canine assistant {{ dogName }}!",
+    });
+    const openai_message = content_block_to_openai_message(
+      toolResult,
+      "user",
+      env,
+    );
+    expect(openai_message).toEqual({
+      role: "tool",
+      content: "35 and sunny",
+      tool_call_id: "tool_494949",
+    });
+  });
+});
+
+describe("tensorzero_inference_to_openai_messages", async () => {
+  it("test simple json", () => {
+    const env = create_env({
+      system: "Do NER Properly!",
+    });
+    const row = {
+      variant_name: "turbo",
+      input: {
+        messages: [
+          {
+            role: "user",
+            content: [
+              {
+                type: "text",
+                value:
+                  'We have in no way seen any Iraqi troops in the city or in its approaches , " a U.N. relief official told Reuters .',
+              },
+            ],
+          },
+        ],
+      },
+      output: {
+        raw: '{"person":[],"organization":["U.N.","Reuters"],"location":[],"miscellaneous":["Iraqi"]}',
+        parsed: {
+          person: [],
+          organization: ["U.N.", "Reuters"],
+          location: [],
+          miscellaneous: ["Iraqi"],
+        },
+      },
+      episode_id: "0192ced0-a2c6-7323-be23-ce4124e683d3",
+    } as ParsedInferenceRow;
+
+    const openaiMessages = tensorzero_inference_to_openai_messages(row, env);
+    expect(openaiMessages.length).toBe(3);
+    expect(openaiMessages[0]).toStrictEqual({
+      role: "system",
+      content: "Do NER Properly!",
+    });
+    expect(openaiMessages[1]).toStrictEqual({
+      role: "user",
+      content:
+        'We have in no way seen any Iraqi troops in the city or in its approaches , " a U.N. relief official told Reuters .',
+    });
+    expect(openaiMessages[2]).toStrictEqual({
+      role: "assistant",
+      content:
+        '{"person":[],"organization":["U.N.","Reuters"],"location":[],"miscellaneous":["Iraqi"]}',
+    });
+  });
+  it("test chat with tool calls", () => {
+    const env = create_env({
+      system: "Help me out with the weather!",
+    });
+    const row = {
+      variant_name: "turbo",
+      input: {
+        messages: [
+          {
+            role: "user",
+            content: [
+              {
+                type: "text",
+                value: "What is the weather in Columbus?",
+              },
+            ],
+          },
+          {
+            role: "assistant",
+            content: [
+              {
+                type: "tool_call",
+                arguments: { location: "Columbus" },
+                id: "tool3",
+                name: "get_weather",
+                raw_arguments: '{"location", "Columbus"}',
+                raw_name: "get_weather",
+              },
+            ],
+          },
+          {
+            role: "user",
+            content: [
+              {
+                type: "tool_result",
+                name: "get_weather",
+                result: "34F, clear skies",
+                id: "tool3",
+              },
+            ],
+          },
+        ],
+      },
+      output: [{ type: "text", text: "it is 34 and sunny" }],
+      episode_id: "0192ced0-a2c6-7323-be23-ce4124e683d3",
+    } as ParsedInferenceRow;
+
+    const openaiMessages = tensorzero_inference_to_openai_messages(row, env);
+    expect(openaiMessages.length).toBe(5);
+    expect(openaiMessages[0]).toStrictEqual({
+      role: "system",
+      content: "Help me out with the weather!",
+    });
+    expect(openaiMessages[1]).toStrictEqual({
+      role: "user",
+      content: "What is the weather in Columbus?",
+    });
+    expect(openaiMessages[2]).toStrictEqual({
+      role: "assistant",
+      tool_calls: [
+        {
+          id: "tool3",
+          type: "function",
+          function: {
+            name: "get_weather",
+            // TODO: double check that this should not be serialized
+            arguments: { location: "Columbus" },
+          },
+        },
+      ],
+    });
+    expect(openaiMessages[3]).toStrictEqual({
+      role: "tool",
+      content: "34F, clear skies",
+      tool_call_id: "tool3",
+    });
+    expect(openaiMessages[4]).toStrictEqual({
+      role: "assistant",
+      content: "it is 34 and sunny",
+    });
+  });
+});