diff --git a/.github/workflows/release-pypi.yml b/.github/workflows/release-pypi.yml index 808e17f..c50e886 100644 --- a/.github/workflows/release-pypi.yml +++ b/.github/workflows/release-pypi.yml @@ -1,4 +1,4 @@ -# Publish sdist + wheel to PyPI when a SemVer tag is pushed (e.g. v1.0.6). +# Publish sdist + wheel to PyPI when a SemVer tag is pushed (e.g. v1.1.0). # Configure "trusted publishing" on PyPI for this workflow + repository + optional GitHub environment. # https://docs.pypi.org/trusted-publishers/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 442845e..9b688a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,21 @@ This project follows [Semantic Versioning](https://semver.org/). From **v1.0.0** ## Unreleased +## 1.1.0 - 2026-05-03 + +### Added + +- **Pricing catalog:** optional `pricing_catalog_path` in `flightdeck.yaml` loads a `PricingCatalog` YAML; `POST /v1/diff` / `release diff` include additive `pricing.catalog` and `pricing.hints` (see `schemas/v1/pricing_catalog.schema.json`, `examples/pricing/catalog.sample.yaml`). +- **Promotion approval:** `promotion_requires_approval` in `flightdeck.yaml`; `POST /v1/promote/request`, `POST /v1/promote/confirm`, `GET /v1/promotion-requests`, and CLI `release promote-request` / `promote-confirm`. +- **Forensics:** `GET /v1/runs` and `flightdeck runs list` for read-only run event slices. +- **Deploy:** optional Helm chart under `examples/deploy/chart/flightdeck/`. +- **Examples:** `examples/fleet/README.md` and workspace template. +- **SQLite migration v4:** `promotion_requests` table. + +### Changed + +- **Examples / CI snippets:** **`flightdeck-ai>=1.1.0`** in Docker and PyPI gate samples. + ## 1.0.6 - 2026-05-02 ### Added diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index a265021..51c7281 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -133,7 +133,7 @@ Merging to **`main` does not publish packages** — PyPI uploads are **tag-drive 1. **PyPI:** add a **trusted publisher** for **[github.com/flightdeckdev/flightdeck](https://github.com/flightdeckdev/flightdeck)** — workflow **`release-pypi.yml`**. If PyPI offers **Environment name: (Any)**, you can still use a GitHub **Environment** named **`pypi`** for approval gates; otherwise match whatever you register on PyPI ([trusted publishers](https://docs.pypi.org/trusted-publishers/)). 2. **GitHub:** Settings → **Environments** → create **`pypi`** (optional: required reviewers / wait timer before OIDC publish). 3. Bump **`version`** in **`pyproject.toml`** and **`src/flightdeck/__init__.py`**, update **`CHANGELOG.md`**, merge to **`main`**. -4. **`git tag vX.Y.Z`** (must match **`pyproject.toml`** exactly, e.g. **`v1.0.6`**) then **`git push origin vX.Y.Z`**. +4. **`git tag vX.Y.Z`** (must match **`pyproject.toml`** exactly, e.g. **`v1.1.0`**) then **`git push origin vX.Y.Z`**. The workflow runs **ruff**, **pytest**, schema drift, **`uv build`**, publishes **sdist + wheel** to **PyPI** via **OIDC** (no long-lived API token in repo secrets), enables **publish attestations**, and creates a **GitHub Release** with generated notes and **`dist/*`** assets. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 835a237..aae6251 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -4,6 +4,10 @@ High-level notes for **shipping FlightDeck**. Detailed history: **[CHANGELOG.md] Narrative docs (including the CLI reference) are maintained on **[github.com/flightdeckdev/flightdeck](https://github.com/flightdeckdev/flightdeck)** `main`; this file and **`schemas/`** ship in minimal clones. +## v1.1.0 — Phase 1 first slice (catalog, approval, runs, Helm, fleet) + +Minor release (see **[CHANGELOG.md](CHANGELOG.md)**): optional **`pricing_catalog_path`** + **`PricingCatalog`** YAML for cross-vendor comparable **`pricing.catalog`** lines on diffs; **`pricing.hints`** for multi-version and model-name diagnostics; **`promotion_requires_approval`** with **`POST /v1/promote/request`** / **`POST /v1/promote/confirm`** / **`GET /v1/promotion-requests`** and matching CLI; **`GET /v1/runs`** and **`flightdeck runs list`**; SQLite migration **v4** (`promotion_requests`); reference **Helm** chart and **fleet** docs under **`examples/`**. **Stable contracts:** additive HTTP and CLI surfaces; existing **`v1`** event and release payloads unchanged. + ## v1.0.6 — Phase 0 closure (backup, cross-language emitters, roadmap) Patch release (see **[CHANGELOG.md](CHANGELOG.md)**): **`flightdeck doctor --backup PATH`** performs a SQLite online backup of the workspace DB; **[examples/integration/](examples/integration/README.md)** gains **`curl`** and a **Node** **`emit_sample_events.node.mjs`** path for **`POST /v1/events`**; **[examples/deploy/README.md](examples/deploy/README.md)** documents the Compose **`/health`** healthcheck and backup scheduling. **ROADMAP:** **Phase 0** is **closed**; **catalog-level** multi-provider pricing normalization is an explicit **Phase 1** build item. **Stable contracts:** additive CLI flag and HTTP field **`pricing.warnings`** (from **v1.0.5**) remain backward-compatible. diff --git a/ROADMAP.md b/ROADMAP.md index cb8b440..61ab595 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -21,7 +21,11 @@ This roadmap is meant to be clear from **what is already shipped** to **near-ter ## Next release -**v1.0.6** (patch): Phase 0 closure — **`flightdeck release diff --output json`** (same shape as **`POST /v1/diff`**); **`pricing.warnings`** when a release model has no row in its pricing table (CLI **`WARNING:`** lines + web Diff); **Overview** ledger metrics card (**`GET /v1/metrics`**); **`curl`** + **Node** samples under **[examples/integration/](examples/integration/README.md)**; **`flightdeck doctor --backup PATH`** (SQLite online backup); **[examples/deploy/](examples/deploy/README.md)** documents Compose **`/health`** healthcheck and backup scheduling. **Phase 0** is declared **closed**; **catalog-level** multi-provider normalization moves to **Phase 1**. See **[CHANGELOG.md](CHANGELOG.md)** and **[RELEASE_NOTES.md](RELEASE_NOTES.md)**. No breaking changes to stable CLI, HTTP, or **`api_version` `v1`** contracts. +Further **Phase 1** work after **v1.1.0** (deeper forensics / replay UX, richer approval UI if needed, OTLP-oriented telemetry per gaps table). Track **[CHANGELOG.md](CHANGELOG.md)**. + +**v1.1.0** (minor, shipped): Phase 1 first slice — **`pricing_catalog_path`** + **`pricing.catalog`** / **`pricing.hints`** on diffs; **`promotion_requires_approval`** + promote **request/confirm** (HTTP + CLI) + **`GET /v1/promotion-requests`**; **`GET /v1/runs`** / **`runs list`**; **Helm** reference chart; **`examples/fleet/`**; SQLite migration **v4**. See **[CHANGELOG.md](CHANGELOG.md)** and **[RELEASE_NOTES.md](RELEASE_NOTES.md)**. + +**v1.0.6** (patch, shipped): Phase 0 closure — **`flightdeck release diff --output json`** (same shape as **`POST /v1/diff`**); **`pricing.warnings`** when a release model has no row in its pricing table (CLI **`WARNING:`** lines + web Diff); **Overview** ledger metrics card (**`GET /v1/metrics`**); **`curl`** + **Node** samples under **[examples/integration/](examples/integration/README.md)**; **`flightdeck doctor --backup PATH`** (SQLite online backup); **[examples/deploy/](examples/deploy/README.md)** documents Compose **`/health`** healthcheck and backup scheduling. **Phase 0** is declared **closed**; **catalog-level** multi-provider normalization moves to **Phase 1**. See **[CHANGELOG.md](CHANGELOG.md)** and **[RELEASE_NOTES.md](RELEASE_NOTES.md)**. No breaking changes to stable CLI, HTTP, or **`api_version` `v1`** contracts. --- @@ -49,7 +53,7 @@ Goal: prove the wedge with real teams using FlightDeck as release governance sou - Harden CLI/schema contracts and edge-case policy coverage (sample windows, sparse traffic, error paths). - Add concrete integration references: app runtime event emitters, CI pipeline examples, and deployment recipes for `flightdeck serve`. -- **Catalog-level cross-vendor pricing normalization** — deferred to **Phase 1** (see Phase 1 build list). **v1.0.4–v1.0.6** ship per-side **`pricing.prices`** and **`pricing.warnings`** diagnostics only. +- **Catalog-level cross-vendor pricing normalization** — first operator-driven slice in **v1.1.0** (`pricing_catalog_path`, **`pricing.catalog`** on diffs); **v1.0.4–v1.0.6** shipped per-side **`pricing.prices`** and **`pricing.warnings`** only. - Strengthen local security ergonomics: explicit token/env status in UI, mutation guardrails, optional read-only UX. - Continue UI productization for current scope (structured views over raw JSON where stable). @@ -86,6 +90,8 @@ Shipped on **`main`**: Goal: move from solid local tooling to repeatable production usage patterns. +**v1.1.0** ships the first tranche: catalog + hints on diffs, approval-gated promote (HTTP + CLI), read-only runs listing, Helm + fleet reference docs, and migration **v4**. Remaining bullets below are still in scope for later minors/patches. + ### Build in this phase - Human-in-the-loop approval workflow on top of policy gates (without requiring a hosted control plane). diff --git a/docs/cli.md b/docs/cli.md index 42b2eff..6cc5d69 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -88,7 +88,7 @@ Without **`--backup`**, only the checks run. In both cases **`migrate()`** runs Output format: ``` -ok schema_migrations: applied=[1, 2, 3] expected 1..3 +ok schema_migrations: applied=[1, 2, 3, 4] expected 1..4 ok promoted_pointer:agent_support:production: release_id=rel_abc123 ok ok audit_seq: contiguous 1..4 (4 row(s)) Doctor: 3 check(s), all passed. @@ -296,6 +296,28 @@ Policy: FAIL Error: Promotion blocked by policy ``` +When **`promotion_requires_approval: true`** in `flightdeck.yaml`, use **`flightdeck release promote-request`** +and **`flightdeck release promote-confirm`** instead of a direct `promote` (see [http-api.md](http-api.md)). + +### `flightdeck release promote-request` + +Create a pending promotion after policy evaluation (requires `promotion_requires_approval: true`). + +```bash +flightdeck release promote-request RELEASE_ID --env ENV --window WINDOW --reason REASON +``` + +On success prints `request_id=…` and policy JSON. If policy would block promotion, exits 1 +and does **not** create a pending row. + +### `flightdeck release promote-confirm` + +Apply a pending request from `promote-request`. + +```bash +flightdeck release promote-confirm REQUEST_ID --approval-reason REASON +``` + ### `flightdeck release rollback` Roll back to a prior release. Same contract as `promote` but records `"rollback"` in @@ -424,7 +446,15 @@ If no policy has been set, prints the default policy (all constraints `null`/dis ## `flightdeck runs` -Subgroup for ingesting run events. +Subgroup for ingesting and listing run events. + +### `flightdeck runs list` + +Print ingested events for a release (newest first), truncated to `--limit`. + +```bash +flightdeck runs list RELEASE_ID --window WINDOW [--env ENV] [--tenant …] [--task …] [--limit N] [--output json] +``` ### `flightdeck runs ingest` diff --git a/docs/http-api.md b/docs/http-api.md index 6df3871..4b913b7 100644 --- a/docs/http-api.md +++ b/docs/http-api.md @@ -22,14 +22,16 @@ Two access tiers: | Route | No token configured | `FLIGHTDECK_LOCAL_API_TOKEN` set | |-------|--------------------|---------------------------------| | `GET /health` | open | open | -| `GET /v1/*` (reads, including `GET /v1/metrics`) | open | open | +| `GET /v1/*` (reads, including `GET /v1/metrics`, `GET /v1/runs`, `GET /v1/promotion-requests`) | open | open | | `POST /v1/events` | open† | open (no Bearer required) | | `POST /v1/diff` | open | open | | `POST /v1/promote` | loopback only | `Authorization: Bearer ` required | +| `POST /v1/promote/request`, `POST /v1/promote/confirm` | loopback only | `Authorization: Bearer ` required | | `POST /v1/rollback` | loopback only | `Authorization: Bearer ` required | †`POST /v1/events` has **no server-side loopback or token gate** in code - (`server/routes/ingest.py`). Only `POST /v1/promote` and `POST /v1/rollback` call + (`server/routes/ingest.py`). Only `POST /v1/promote`, `POST /v1/promote/request`, + `POST /v1/promote/confirm`, and `POST /v1/rollback` call `_require_mutation_access`. When the server binds to `127.0.0.1` (the default), ingest is effectively local-only by network topology, not by application enforcement. If you bind `--host 0.0.0.0`, event ingest becomes reachable from any host. Protect it at the network @@ -83,7 +85,7 @@ Read-only JSON snapshot of aggregate counts in the local SQLite ledger (releases "actions_total": 5, "actions_by_action": { "promote": 4, "rollback": 1 } }, - "schema_version": 3, + "schema_version": 4, "generated_at": "2026-05-03T12:00:00+00:00" } ``` @@ -179,6 +181,77 @@ doctor` checks that the sequence has no gaps. --- +## `GET /v1/promotion-requests` + +List promotion approval requests (Phase 1). Newest first. + +**Query parameters** + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `status` | string | — | Filter by status (`pending`, `completed`, `cancelled`) | +| `limit` | integer | 50 | Max rows (1–500) | + +**Response** + +```json +{ + "requests": [ + { + "request_id": "prq_abc123", + "status": "pending", + "release_id": "rel_xyz", + "agent_id": "agent_support", + "environment": "production", + "window": "7d", + "reason": "rollout candidate", + "actor": "ci", + "baseline_release_id": "rel_prev", + "policy": { "passed": true, "reasons": [], "evaluated_at": "2026-05-02T12:00:00+00:00" }, + "created_at": "2026-05-02T12:00:00+00:00", + "resolved_at": null, + "completed_action_id": null + } + ] +} +``` + +--- + +## `GET /v1/runs` + +Read-only forensics: return a slice of ingested run events for one release (newest first). + +**Query parameters (required in bold)** + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| **`release_id`** | string | — | Registered release | +| **`window`** | string | — | Same format as diff (`7d`, `24h`, `30m`) | +| `environment` | string | — | Defaults to workspace `default_environment` | +| `tenant_id` | string | — | Optional filter | +| `task_id` | string | — | Optional filter | +| `limit` | integer | 100 | Max events returned (1–500) | + +**Response** + +```json +{ + "release_id": "rel_abc", + "since": "2026-04-25T12:00:00+00:00", + "until": "2026-05-02T12:00:00+00:00", + "filters": { "environment": "local", "tenant_id": null, "task_id": null }, + "matched_total": 42, + "returned": 10, + "truncated": true, + "events": [] +} +``` + +Each element of `events` is a `RunEvent` object (`schemas/v1/run_event.schema.json`). + +--- + ## `POST /v1/events` Ingest `RunEvent` records (runtime evidence for diff and policy evaluation). @@ -352,7 +425,18 @@ included. "candidate_output_usd_per_1k_tokens": 0.0135, "candidate_cached_input_usd_per_1k_tokens": null }, - "warnings": [] + "warnings": [], + "hints": [], + "catalog": { + "enabled": false, + "catalog_version": null, + "baseline_slot_id": null, + "candidate_slot_id": null, + "baseline_cost_per_run_usd": null, + "candidate_cost_per_run_usd": null, + "delta_cost_per_run_usd": null, + "warnings": [] + } }, "samples": { "baseline_runs": 1200, @@ -386,6 +470,14 @@ table. Per-side **`prices.*`** fields are **`null`** in that case. Warnings are only** and do not change **`policy`**. If ingested run events reference a model that cannot be priced, the diff request still fails with HTTP 400 as before. +**`pricing.hints`** — optional diagnostics (for example other imported `pricing_version` +values for the same provider, or substring model-name hints when the exact model is missing). + +**`pricing.catalog`** — when `flightdeck.yaml` sets `pricing_catalog_path` to a valid +`PricingCatalog` YAML, `enabled` is true and comparable per-run costs may appear using +operator-defined slot tariffs (additive; existing `metrics.*` semantics unchanged). See +`schemas/v1/pricing_catalog.schema.json` and `examples/pricing/catalog.sample.yaml`. + **Confidence levels** | Label | Meaning | @@ -410,6 +502,9 @@ Evaluate active policy and promote the release to the specified environment. Wri audit record regardless of whether policy passes; updates the promoted pointer only when policy passes. +When **`promotion_requires_approval: true`** in `flightdeck.yaml`, this route returns HTTP +**400**; use **`POST /v1/promote/request`** then **`POST /v1/promote/confirm`** instead. + **Requires mutation access** (loopback client or Bearer token). **Request body** @@ -484,6 +579,29 @@ Check `detail.outcome.policy.reasons` for the specific constraints that failed. --- +## `POST /v1/promote/request` + +When **`promotion_requires_approval: true`** in `flightdeck.yaml`, create a **pending** +promotion after the same policy evaluation as `/v1/promote` would run. If policy fails, +returns HTTP **409** with a JSON `detail.message` (no `promotion_requests` row is written). +If policy passes, returns **`request_id`** for **`POST /v1/promote/confirm`**. + +**Requires mutation access.** Request body matches `/v1/promote` (`release_id`, `environment`, `window`, `reason`, optional `actor`). + +If `promotion_requires_approval` is **false**, returns HTTP **400**. + +--- + +## `POST /v1/promote/confirm` + +Complete a pending request from **`/v1/promote/request`**. Body: `request_id`, +`approval_reason` (non-empty), optional `actor`. Re-runs promotion evaluation; on success +marks the request **completed** and returns the same shape as **`POST /v1/promote`**. + +**Requires mutation access.** + +--- + ## `POST /v1/rollback` Roll back to a prior release. Identical contract to `/v1/promote` but with `"action": diff --git a/docs/operations-and-policy.md b/docs/operations-and-policy.md index 4c16fd2..94d8b03 100644 --- a/docs/operations-and-policy.md +++ b/docs/operations-and-policy.md @@ -464,7 +464,7 @@ Exit behavior: all checks pass → `0`; any failure → prints the failed check exits non-zero (`click.ClickException`). ``` -ok schema_migrations: applied=[1, 2, 3] expected 1..3 +ok schema_migrations: applied=[1, 2, 3, 4] expected 1..4 ok promoted_pointer:agent_support:production: release_id=rel_abc123 ok ok audit_seq: contiguous 1..4 (4 row(s)) Doctor: 3 check(s), all passed. @@ -646,7 +646,7 @@ After restore, run `flightdeck doctor` to confirm integrity. | Check | Failure message | Meaning | Fix | |-------|----------------|---------|-----| -| `schema_migrations` | `migrations applied=[1, 2] but expected 1..3` | A newer migration has not run (DB was created by an older version) | Run `flightdeck doctor` again (it calls `migrate()` at start); if it still fails, the DB file may be from a version with a different schema history | +| `schema_migrations` | `migrations applied=[1, 2, 3] but expected 1..4` | A newer migration has not run (DB was created by an older version) | Run `flightdeck doctor` again (it calls `migrate()` at start); if it still fails, the DB file may be from a version with a different schema history | | `promoted_pointer::` | `release_id=rel_... not found in releases` | A promoted pointer references a deleted or never-registered release | Re-register the release with the same ID (not supported) or reset the promoted pointer by promoting a known good release | | `audit_seq` | `gap at seq=5` or `duplicate seq=3` | The `release_actions` table has a missing or duplicate `audit_seq` | Indicates a manual DB edit or incomplete write; restore from backup and reinspect the affected rows with `sqlite3` | diff --git a/docs/sdk.md b/docs/sdk.md index 370e1ad..de26716 100644 --- a/docs/sdk.md +++ b/docs/sdk.md @@ -163,6 +163,20 @@ audit log). Requires the mutation token if one is configured. `POST /v1/rollback` — same contract as promote; rolls back to the specified release. +### `post_promote_request(…)` / `post_promote_confirm(…)` + +`POST /v1/promote/request` and `POST /v1/promote/confirm` — two-step promotion when +`promotion_requires_approval` is enabled in `flightdeck.yaml`. Same mutation token rules +as `post_promote`. + +### `list_promotion_requests(*, status=None, limit=50) -> dict` + +`GET /v1/promotion-requests`. + +### `list_runs(*, release_id, window, environment=None, tenant_id=None, task_id=None, limit=100) -> dict` + +`GET /v1/runs` — read-only event slice for forensics. + ## Async usage ```python diff --git a/examples/README.md b/examples/README.md index 562eb99..5d1517a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -20,3 +20,5 @@ This folder holds **copy-pasteable** references for wiring FlightDeck into a rea | [ci/](ci/README.md) | Policy gate script, sample policy YAML, GitHub Actions job snippets. | | [deploy/](deploy/README.md) | Dockerfile and compose for `flightdeck serve`. | | [integration/](integration/README.md) | Sample event emitter for HTTP ingest. | +| [fleet/](fleet/README.md) | Multi-workspace naming, optional catalog path, approval workflow notes. | +| [pricing/catalog.sample.yaml](pricing/catalog.sample.yaml) | Sample `PricingCatalog` for cross-vendor comparable diff costs. | diff --git a/examples/ci/README.md b/examples/ci/README.md index c53cd18..b5f9ea6 100644 --- a/examples/ci/README.md +++ b/examples/ci/README.md @@ -37,7 +37,7 @@ uv run python examples/ci/ledger_gate.py Example (**PyPI** install): ```bash -pip install "flightdeck-ai>=1.0.6" +pip install "flightdeck-ai>=1.1.0" export WORKSPACE="$(mktemp -d)" export QUICKSTART_ROOT=/path/to/flightdeck/examples/quickstart python /path/to/flightdeck/examples/ci/ledger_gate.py diff --git a/examples/ci/github-actions/policy-gate-pypi.yml b/examples/ci/github-actions/policy-gate-pypi.yml index 5a43c1b..e294f88 100644 --- a/examples/ci/github-actions/policy-gate-pypi.yml +++ b/examples/ci/github-actions/policy-gate-pypi.yml @@ -11,7 +11,7 @@ on: env: # Pin to a tag or SHA that matches your installed flightdeck-ai version when possible. FLIGHTDECK_REF: main - FLIGHTDECK_AI_SPEC: ">=1.0.6" + FLIGHTDECK_AI_SPEC: ">=1.1.0" jobs: ledger-gate: diff --git a/examples/deploy/Dockerfile b/examples/deploy/Dockerfile index e193bdd..ff6d071 100644 --- a/examples/deploy/Dockerfile +++ b/examples/deploy/Dockerfile @@ -2,7 +2,7 @@ FROM python:3.14-slim RUN pip install --no-cache-dir --upgrade pip \ - && pip install --no-cache-dir "flightdeck-ai>=1.0.6" + && pip install --no-cache-dir "flightdeck-ai>=1.1.0" WORKDIR /workspace diff --git a/examples/deploy/README.md b/examples/deploy/README.md index 6544095..625cbf8 100644 --- a/examples/deploy/README.md +++ b/examples/deploy/README.md @@ -40,6 +40,17 @@ Inside the Compose stack, **`exec`** into the running container with **`/workspa Set **`FLIGHTDECK_LOCAL_API_TOKEN`** in your environment before `docker compose up` (or in an `.env` file beside `docker-compose.yml`). Clients must send **`Authorization: Bearer …`** for **`POST /v1/promote`** and **`POST /v1/rollback`**. Ingest and diff are **not** behind this Bearer gate by default—treat network placement accordingly. +## Helm (optional single-replica chart) + +A minimal chart lives under **`chart/flightdeck/`**. It runs one replica of **`flightdeck serve`** with an **`emptyDir`** workspace (ephemeral); for a persistent ledger, replace the volume in **`templates/deployment.yaml`** with a PVC or mount your own image init. + +```bash +docker build -t flightdeck-serve:local . +helm install fd ./chart/flightdeck --namespace flightdeck --create-namespace +``` + +Tune **`values.yaml`** (`image`, `resources`, `service.type`) for your cluster. + ### Bind-mounting a host workspace To reuse an existing directory that already contains **`flightdeck.yaml`** and **`.flightdeck/`**, replace the `volumes` entry with: diff --git a/examples/deploy/chart/flightdeck/Chart.yaml b/examples/deploy/chart/flightdeck/Chart.yaml new file mode 100644 index 0000000..ddc2714 --- /dev/null +++ b/examples/deploy/chart/flightdeck/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: flightdeck +description: Optional Helm chart for flightdeck serve (single-replica reference) +type: application +version: 0.1.0 +appVersion: "1.1.0" diff --git a/examples/deploy/chart/flightdeck/templates/_helpers.tpl b/examples/deploy/chart/flightdeck/templates/_helpers.tpl new file mode 100644 index 0000000..a9ca021 --- /dev/null +++ b/examples/deploy/chart/flightdeck/templates/_helpers.tpl @@ -0,0 +1,3 @@ +{{- define "flightdeck.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end }} diff --git a/examples/deploy/chart/flightdeck/templates/deployment.yaml b/examples/deploy/chart/flightdeck/templates/deployment.yaml new file mode 100644 index 0000000..2480f45 --- /dev/null +++ b/examples/deploy/chart/flightdeck/templates/deployment.yaml @@ -0,0 +1,45 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "flightdeck.name" . }} + labels: + app.kubernetes.io/name: {{ include "flightdeck.name" . }} +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: {{ include "flightdeck.name" . }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "flightdeck.name" . }} + spec: + containers: + - name: flightdeck + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: ["serve", "--host", "0.0.0.0", "--port", "{{ .Values.service.port }}"] + workingDir: {{ .Values.workspaceMountPath | quote }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + readinessProbe: + httpGet: + path: /health + port: http + initialDelaySeconds: 3 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /health + port: http + initialDelaySeconds: 10 + periodSeconds: 20 + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: workspace + mountPath: {{ .Values.workspaceMountPath | quote }} + volumes: + - name: workspace + emptyDir: {} diff --git a/examples/deploy/chart/flightdeck/templates/service.yaml b/examples/deploy/chart/flightdeck/templates/service.yaml new file mode 100644 index 0000000..e292257 --- /dev/null +++ b/examples/deploy/chart/flightdeck/templates/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "flightdeck.name" . }} + labels: + app.kubernetes.io/name: {{ include "flightdeck.name" . }} +spec: + type: {{ .Values.service.type }} + selector: + app.kubernetes.io/name: {{ include "flightdeck.name" . }} + ports: + - name: http + port: {{ .Values.service.port }} + targetPort: http diff --git a/examples/deploy/chart/flightdeck/values.yaml b/examples/deploy/chart/flightdeck/values.yaml new file mode 100644 index 0000000..29eec06 --- /dev/null +++ b/examples/deploy/chart/flightdeck/values.yaml @@ -0,0 +1,14 @@ +image: + # Build the same image as Compose: from examples/deploy run `docker build -t flightdeck-serve:local .` + repository: flightdeck-serve + tag: local + pullPolicy: Never + +service: + type: ClusterIP + port: 8765 + +# Mount a workspace ConfigMap/Secret with flightdeck.yaml + optional policy; see templates. +workspaceMountPath: /workspace + +resources: {} diff --git a/examples/fleet/README.md b/examples/fleet/README.md new file mode 100644 index 0000000..5ba3a37 --- /dev/null +++ b/examples/fleet/README.md @@ -0,0 +1,21 @@ +# Multi-workspace operator patterns (Phase 1) + +FlightDeck is **local-first**: one `flightdeck.yaml` + SQLite database per working directory. “Fleet” ergonomics here means **repeatable layouts** and naming—not a hosted control plane. + +## Recommended layout + +- One directory per environment or product slice, each with its own `flightdeck.yaml` and `.flightdeck/flightdeck.db`. +- Pin `db_path` per workspace (default `.flightdeck/flightdeck.db` is fine if directories never merge). +- Use consistent `default_environment` values (`staging`, `prod`) across repos that feed the same promotion gates. + +## Optional pricing catalog + +For cross-vendor **comparable** cost lines on `release diff` / `POST /v1/diff`, add `pricing_catalog_path` in `flightdeck.yaml` pointing at a `PricingCatalog` YAML (see `examples/pricing/catalog.sample.yaml`). + +## Human approval for promote + +Set `promotion_requires_approval: true` in `flightdeck.yaml` to require `release promote-request` / `release promote-confirm` (or HTTP `POST /v1/promote/request` + `POST /v1/promote/confirm`) instead of a direct `release promote`. + +## Template + +See `workspace-staging.example.yaml` for a copy-paste starting point; copy to your repo root as `flightdeck.yaml` and edit paths. diff --git a/examples/fleet/workspace-staging.example.yaml b/examples/fleet/workspace-staging.example.yaml new file mode 100644 index 0000000..ceee19b --- /dev/null +++ b/examples/fleet/workspace-staging.example.yaml @@ -0,0 +1,11 @@ +api_version: v1 +kind: WorkspaceConfig +db_path: .flightdeck/flightdeck.db +default_environment: staging +diff: + min_candidate_runs: 500 + min_baseline_runs: 500 + min_low_runs: 50 +# Optional Phase 1 fields (uncomment and adjust paths): +# pricing_catalog_path: examples/pricing/catalog.sample.yaml +# promotion_requires_approval: true diff --git a/examples/pricing/catalog.sample.yaml b/examples/pricing/catalog.sample.yaml new file mode 100644 index 0000000..58c23b8 --- /dev/null +++ b/examples/pricing/catalog.sample.yaml @@ -0,0 +1,19 @@ +# Sample PricingCatalog — maps imported pricing tables + model IDs to comparable slots. +# Reference: flightdeck.catalog.PricingCatalog (JSON Schema: schemas/v1/pricing_catalog.schema.json). +api_version: v1 +kind: PricingCatalog +catalog_version: "sample-1" +mappings: + - provider: openai + pricing_version: openai-2026-04-30 + model: gpt-4o-mini + catalog_slot_id: reasoning_tier_1 + - provider: anthropic + pricing_version: anthropic-2026-04-30 + model: claude-3-5-sonnet-20241022 + catalog_slot_id: reasoning_tier_1 +tariffs: + reasoning_tier_1: + input_usd_per_1k_tokens: 0.25 + output_usd_per_1k_tokens: 0.75 + cached_input_usd_per_1k_tokens: 0.1 diff --git a/pyproject.toml b/pyproject.toml index e21eda7..eb006b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "flightdeck-ai" -version = "1.0.6" +version = "1.1.0" description = "AI Release Governance for production agents." readme = "README.md" license = "Apache-2.0" diff --git a/schemas/v1/pricing_catalog.schema.json b/schemas/v1/pricing_catalog.schema.json new file mode 100644 index 0000000..521da6f --- /dev/null +++ b/schemas/v1/pricing_catalog.schema.json @@ -0,0 +1,103 @@ +{ + "$defs": { + "PricingCatalogMapping": { + "properties": { + "catalog_slot_id": { + "title": "Catalog Slot Id", + "type": "string" + }, + "model": { + "title": "Model", + "type": "string" + }, + "pricing_version": { + "title": "Pricing Version", + "type": "string" + }, + "provider": { + "title": "Provider", + "type": "string" + } + }, + "required": [ + "provider", + "pricing_version", + "model", + "catalog_slot_id" + ], + "title": "PricingCatalogMapping", + "type": "object" + }, + "PricingCatalogTariff": { + "description": "Comparable USD rates for one catalog slot (same units as :class:`PricingEntry`).", + "properties": { + "cached_input_usd_per_1k_tokens": { + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cached Input Usd Per 1K Tokens" + }, + "input_usd_per_1k_tokens": { + "minimum": 0, + "title": "Input Usd Per 1K Tokens", + "type": "number" + }, + "output_usd_per_1k_tokens": { + "minimum": 0, + "title": "Output Usd Per 1K Tokens", + "type": "number" + } + }, + "required": [ + "input_usd_per_1k_tokens", + "output_usd_per_1k_tokens" + ], + "title": "PricingCatalogTariff", + "type": "object" + } + }, + "properties": { + "api_version": { + "const": "v1", + "default": "v1", + "title": "Api Version", + "type": "string" + }, + "catalog_version": { + "title": "Catalog Version", + "type": "string" + }, + "kind": { + "const": "PricingCatalog", + "default": "PricingCatalog", + "title": "Kind", + "type": "string" + }, + "mappings": { + "items": { + "$ref": "#/$defs/PricingCatalogMapping" + }, + "title": "Mappings", + "type": "array" + }, + "tariffs": { + "additionalProperties": { + "$ref": "#/$defs/PricingCatalogTariff" + }, + "title": "Tariffs", + "type": "object" + } + }, + "required": [ + "catalog_version" + ], + "title": "PricingCatalog", + "type": "object" +} diff --git a/scripts/generate_schemas.py b/scripts/generate_schemas.py index 6dc2a92..aec96bb 100644 --- a/scripts/generate_schemas.py +++ b/scripts/generate_schemas.py @@ -3,6 +3,7 @@ import json from pathlib import Path +from flightdeck.catalog import PricingCatalog from flightdeck.models import Policy, PricingTable, ReleaseArtifact, RunEvent @@ -17,6 +18,7 @@ def main() -> None: write_schema(root / "run_event.schema.json", RunEvent.model_json_schema()) write_schema(root / "pricing_table.schema.json", PricingTable.model_json_schema()) write_schema(root / "policy.schema.json", Policy.model_json_schema()) + write_schema(root / "pricing_catalog.schema.json", PricingCatalog.model_json_schema()) if __name__ == "__main__": diff --git a/src/flightdeck/__init__.py b/src/flightdeck/__init__.py index f8979f4..5539e47 100644 --- a/src/flightdeck/__init__.py +++ b/src/flightdeck/__init__.py @@ -1,3 +1,3 @@ """FlightDeck - AI Release Governance for production agents.""" -__version__ = "1.0.6" +__version__ = "1.1.0" diff --git a/src/flightdeck/catalog.py b/src/flightdeck/catalog.py new file mode 100644 index 0000000..f350002 --- /dev/null +++ b/src/flightdeck/catalog.py @@ -0,0 +1,102 @@ +"""Optional workspace pricing catalog for cross-vendor comparable cost rollups. + +A catalog maps (provider, pricing_version, model) to a *catalog slot* with +operator-defined USD-per-1k-token tariffs. Re-costing each side's run events +with those tariffs yields ``catalog_*`` metrics on diffs without changing +existing per-table ``metrics.*`` semantics. +""" + +from __future__ import annotations + +from pathlib import Path +from typing import Any, Literal + +import yaml +from pydantic import BaseModel, Field + +from flightdeck.models import PricingEntry, PricingTable + + +class PricingCatalogMapping(BaseModel): + provider: str + pricing_version: str + model: str + catalog_slot_id: str + + +class PricingCatalogTariff(BaseModel): + """Comparable USD rates for one catalog slot (same units as :class:`PricingEntry`).""" + + input_usd_per_1k_tokens: float = Field(ge=0) + output_usd_per_1k_tokens: float = Field(ge=0) + cached_input_usd_per_1k_tokens: float | None = Field(default=None, ge=0) + + +class PricingCatalog(BaseModel): + api_version: Literal["v1"] = "v1" + kind: Literal["PricingCatalog"] = "PricingCatalog" + + catalog_version: str + mappings: list[PricingCatalogMapping] = Field(default_factory=list) + tariffs: dict[str, PricingCatalogTariff] = Field(default_factory=dict) + + +def load_pricing_catalog(path: str | Path) -> PricingCatalog: + p = Path(path).expanduser().resolve() + if not p.is_file(): + raise FileNotFoundError(f"Pricing catalog not found: {p}") + with p.open("r", encoding="utf-8") as f: + data: Any = yaml.safe_load(f) or {} + return PricingCatalog.model_validate(data) + + +def resolve_catalog_slot_id( + catalog: PricingCatalog, + *, + provider: str, + pricing_version: str, + model: str, +) -> str | None: + for m in catalog.mappings: + if m.provider == provider and m.pricing_version == pricing_version and m.model == model: + return m.catalog_slot_id + return None + + +def resolve_catalog_pricing_entry( + catalog: PricingCatalog, + *, + provider: str, + pricing_version: str, + model: str, +) -> tuple[PricingEntry | None, str | None]: + """Return a :class:`PricingEntry` for ``model`` using catalog tariffs, or (None, reason).""" + slot = resolve_catalog_slot_id(catalog, provider=provider, pricing_version=pricing_version, model=model) + if slot is None: + return None, f"no catalog mapping for {provider}/{pricing_version} model={model!r}" + tariff = catalog.tariffs.get(slot) + if tariff is None: + return None, f"catalog slot {slot!r} has no tariffs entry" + entry = PricingEntry( + model=model, + input_usd_per_1k_tokens=tariff.input_usd_per_1k_tokens, + output_usd_per_1k_tokens=tariff.output_usd_per_1k_tokens, + cached_input_usd_per_1k_tokens=tariff.cached_input_usd_per_1k_tokens, + ) + return entry, None + + +def catalog_tariff_as_table(model: str, entry: PricingEntry) -> PricingTable: + """Single-model table for :func:`flightdeck.ledger.compute_rollup`.""" + return PricingTable( + provider="_flightdeck_catalog", + pricing_version="_synthetic", + entries=[ + PricingEntry( + model=model, + input_usd_per_1k_tokens=entry.input_usd_per_1k_tokens, + output_usd_per_1k_tokens=entry.output_usd_per_1k_tokens, + cached_input_usd_per_1k_tokens=entry.cached_input_usd_per_1k_tokens, + ) + ], + ) diff --git a/src/flightdeck/cli/main.py b/src/flightdeck/cli/main.py index 073b812..aaa01f9 100644 --- a/src/flightdeck/cli/main.py +++ b/src/flightdeck/cli/main.py @@ -26,8 +26,12 @@ from flightdeck.operations import ( OperationError, compute_diff, + confirm_promotion_request, default_policy, + diff_outcome_to_public_dict, promote_release, + query_run_events_page, + request_promotion, rollback_release, ) from flightdeck.storage import Storage @@ -311,6 +315,57 @@ def runs() -> None: """Ingest run events.""" +@runs.command("list") +@click.argument("release_id") +@click.option("--window", required=True, help="Time window like 7d, 24h, 30m.") +@click.option("--env", "environment", default=None) +@click.option("--tenant", "tenant_id", default=None) +@click.option("--task", "task_id", default=None) +@click.option("--limit", default=100, show_default=True, type=int) +@click.option( + "--output", + "output_format", + type=click.Choice(["text", "json"]), + default="text", + show_default=True, +) +def runs_list( + release_id: str, + window: str, + environment: str | None, + tenant_id: str | None, + task_id: str | None, + limit: int, + output_format: str, +) -> None: + """List ingested run events for a release (newest first; truncated to --limit).""" + cfg = load_config() + storage = Storage(cfg.db_path) + storage.migrate() + try: + payload = query_run_events_page( + cfg=cfg, + storage=storage, + release_id=release_id, + window=window, + environment=environment, + tenant_id=tenant_id, + task_id=task_id, + limit=limit, + ) + except OperationError as e: + raise click.ClickException(str(e)) from e + if output_format == "json": + click.echo(json.dumps(payload, indent=2, sort_keys=True)) + return + click.echo( + f"release={payload['release_id']} matched_total={payload['matched_total']} " + f"returned={payload['returned']} truncated={payload['truncated']}" + ) + for ev in payload["events"]: + click.echo(json.dumps(ev, sort_keys=True)) + + @runs.command("ingest") @click.argument("path", type=click.Path(exists=True, path_type=Path)) def runs_ingest(path: Path) -> None: @@ -374,53 +429,7 @@ def release_diff( raise click.ClickException(str(e)) from e if output_format == "json": - body = { - "window": result.window, - "since": result.since.isoformat(), - "until": result.until.isoformat(), - "filters": { - "environment": result.environment, - "tenant_id": result.tenant_id, - "task_id": result.task_id, - }, - "pricing": { - "baseline_provider": result.baseline_pricing_provider, - "baseline_version": result.baseline_pricing_version, - "baseline_model": result.baseline_model, - "candidate_provider": result.candidate_pricing_provider, - "candidate_version": result.candidate_pricing_version, - "candidate_model": result.candidate_model, - "pricing_or_model_changed": result.pricing_or_model_changed, - "prices": { - "baseline_input_usd_per_1k_tokens": result.baseline_input_usd_per_1k_tokens, - "baseline_output_usd_per_1k_tokens": result.baseline_output_usd_per_1k_tokens, - "baseline_cached_input_usd_per_1k_tokens": result.baseline_cached_input_usd_per_1k_tokens, - "candidate_input_usd_per_1k_tokens": result.candidate_input_usd_per_1k_tokens, - "candidate_output_usd_per_1k_tokens": result.candidate_output_usd_per_1k_tokens, - "candidate_cached_input_usd_per_1k_tokens": result.candidate_cached_input_usd_per_1k_tokens, - }, - "warnings": list(result.pricing_warnings), - }, - "samples": { - "baseline_runs": result.baseline_runs, - "candidate_runs": result.candidate_runs, - "confidence": result.confidence, - "confidence_reason": result.confidence_reason, - }, - "metrics": { - "baseline_cost_per_run_usd": result.baseline_cost_per_run_usd, - "candidate_cost_per_run_usd": result.candidate_cost_per_run_usd, - "delta_cost_per_run_usd": result.delta_cost_per_run_usd, - "delta_cost_per_run_pct": result.delta_cost_per_run_pct, - "baseline_latency_ms_avg": result.baseline_latency_ms_avg, - "candidate_latency_ms_avg": result.candidate_latency_ms_avg, - "delta_latency_ms_avg": result.delta_latency_ms_avg, - "baseline_error_rate": result.baseline_error_rate, - "candidate_error_rate": result.candidate_error_rate, - "delta_error_rate": result.delta_error_rate, - }, - "policy": result.policy.model_dump(mode="json"), - } + body = diff_outcome_to_public_dict(result) click.echo(json.dumps(body, indent=2, sort_keys=True)) if fail_on_policy and not result.policy.passed: raise click.ClickException("Policy gate: diff blocked by active policy (see policy.reasons in JSON output).") @@ -438,6 +447,25 @@ def release_diff( ) for w in result.pricing_warnings: click.echo(f"WARNING: {w}") + for h in result.pricing_hints: + click.echo(f"HINT: {h}") + if result.catalog_enabled or result.catalog_warnings: + click.echo( + f"Catalog: enabled={result.catalog_enabled} version={result.catalog_version or '-'} " + f"slots baseline={result.baseline_catalog_slot_id or '-'} candidate={result.candidate_catalog_slot_id or '-'}" + ) + if ( + result.baseline_catalog_cost_per_run_usd is not None + and result.candidate_catalog_cost_per_run_usd is not None + and result.delta_catalog_cost_per_run_usd is not None + ): + click.echo( + f"Catalog-comparable cost/run (USD): {result.baseline_catalog_cost_per_run_usd:.6f} -> " + f"{result.candidate_catalog_cost_per_run_usd:.6f} " + f"(delta {result.delta_catalog_cost_per_run_usd:+.6f})" + ) + for cw in result.catalog_warnings: + click.echo(f"WARNING (catalog): {cw}") if result.pricing_or_model_changed: click.echo("NOTE: cost delta includes pricing/model assumption changes (pricing reference and/or model differ).") if ( @@ -515,6 +543,64 @@ def release_promote(release_id: str, environment: str, window: str, reason: str) click.echo(f"- {r}") +@release.command("promote-request") +@click.argument("release_id") +@click.option("--env", "environment", required=True) +@click.option("--window", required=True, help="Required. Time window like 7d, 24h, 30m.") +@click.option("--reason", required=True, help="Rationale for requesting promotion (policy must pass).") +def release_promote_request(release_id: str, environment: str, window: str, reason: str) -> None: + """Create a pending promotion request (requires promotion_requires_approval in flightdeck.yaml).""" + cfg = load_config() + storage = Storage(cfg.db_path) + storage.migrate() + try: + record = request_promotion( + cfg=cfg, + storage=storage, + release_id=release_id, + environment=environment, + window=window, + reason=reason, + actor=actor_name(), + ) + except OperationError as e: + raise click.ClickException(str(e)) from e + click.echo(f"request_id={record.request_id}") + click.echo(json.dumps({"policy": record.policy_result.model_dump(mode="json")}, indent=2)) + + +@release.command("promote-confirm") +@click.argument("request_id") +@click.option("--approval-reason", required=True, help="Human approval rationale.") +def release_promote_confirm(request_id: str, approval_reason: str) -> None: + """Confirm a pending promotion request and perform the promotion.""" + cfg = load_config() + storage = Storage(cfg.db_path) + storage.migrate() + try: + outcome = confirm_promotion_request( + cfg=cfg, + storage=storage, + request_id=request_id, + approval_reason=approval_reason, + actor=actor_name(), + ) + except OperationError as e: + raise click.ClickException(str(e)) from e + + if not outcome.policy.passed: + click.echo("Policy: FAIL") + for r in outcome.policy.reasons: + click.echo(f"- {r}") + raise click.ClickException("Promotion blocked by policy") + + click.echo(f"Promoted {outcome.release_id} for {outcome.agent_id}/{outcome.environment}") + click.echo(f"action_id={outcome.action_id}") + click.echo("Policy: PASS") + for r in outcome.policy.reasons: + click.echo(f"- {r}") + + @release.command("rollback") @click.argument("release_id") @click.option("--env", "environment", required=True) diff --git a/src/flightdeck/models.py b/src/flightdeck/models.py index 37af999..1c13dc4 100644 --- a/src/flightdeck/models.py +++ b/src/flightdeck/models.py @@ -21,6 +21,14 @@ class WorkspaceConfig(BaseModel): diff: DiffConfig = Field(default_factory=DiffConfig) + # Optional path (relative to cwd or absolute) to a PricingCatalog YAML for + # cross-vendor comparable per-run costs on diffs (additive ``pricing.catalog``). + pricing_catalog_path: str | None = None + + # When true, ``POST /v1/promote`` and CLI ``release promote`` reject until a + # pending request is confirmed (``promote/request`` + ``promote/confirm``). + promotion_requires_approval: bool = False + class PricingEntry(BaseModel): model: str @@ -233,3 +241,21 @@ class PromotionRecord(BaseModel): # Assigned by storage on insert when None; monotonic for `flightdeck doctor` gap checks. audit_seq: int | None = None + +class PromotionRequestRecord(BaseModel): + """Pending human approval before ``commit_promotion`` (Phase 1).""" + + request_id: str + status: Literal["pending", "completed", "cancelled"] = "pending" + release_id: str + agent_id: str + environment: str + window: str + reason: str + actor: str + baseline_release_id: str | None = None + policy_result: PolicyResult + created_at: datetime + resolved_at: datetime | None = None + completed_action_id: str | None = None + diff --git a/src/flightdeck/operations.py b/src/flightdeck/operations.py index 0bc7efd..747f1a5 100644 --- a/src/flightdeck/operations.py +++ b/src/flightdeck/operations.py @@ -2,19 +2,31 @@ from dataclasses import dataclass from datetime import datetime +from pathlib import Path from typing import Literal from uuid import uuid4 -from flightdeck.ledger import diff_releases, parse_window, pricing_entry_for +import yaml +from pydantic import ValidationError + +from flightdeck.catalog import ( + catalog_tariff_as_table, + load_pricing_catalog, + resolve_catalog_pricing_entry, + resolve_catalog_slot_id, +) +from flightdeck.ledger import compute_rollup, diff_releases, parse_window, pricing_entry_for from flightdeck.models import ( Policy, PolicyResult, PromotionRecord, + PromotionRequestRecord, ReleaseArtifact, ReleaseRecord, WorkspaceConfig, utc_now, ) +from flightdeck.pricing_hints import collect_pricing_skew_hints from flightdeck.storage import Storage @@ -58,6 +70,15 @@ class DiffOutcome: candidate_error_rate: float delta_error_rate: float policy: PolicyResult + pricing_hints: tuple[str, ...] + catalog_enabled: bool + catalog_version: str | None + baseline_catalog_slot_id: str | None + candidate_catalog_slot_id: str | None + baseline_catalog_cost_per_run_usd: float | None + candidate_catalog_cost_per_run_usd: float | None + delta_catalog_cost_per_run_usd: float | None + catalog_warnings: tuple[str, ...] pricing_warnings: tuple[str, ...] @@ -88,6 +109,68 @@ def default_policy() -> Policy: ) +def diff_outcome_to_public_dict(result: DiffOutcome) -> dict[str, object]: + """JSON shape for ``POST /v1/diff`` and ``release diff --output json``.""" + return { + "window": result.window, + "since": result.since.isoformat(), + "until": result.until.isoformat(), + "filters": { + "environment": result.environment, + "tenant_id": result.tenant_id, + "task_id": result.task_id, + }, + "pricing": { + "baseline_provider": result.baseline_pricing_provider, + "baseline_version": result.baseline_pricing_version, + "baseline_model": result.baseline_model, + "candidate_provider": result.candidate_pricing_provider, + "candidate_version": result.candidate_pricing_version, + "candidate_model": result.candidate_model, + "pricing_or_model_changed": result.pricing_or_model_changed, + "prices": { + "baseline_input_usd_per_1k_tokens": result.baseline_input_usd_per_1k_tokens, + "baseline_output_usd_per_1k_tokens": result.baseline_output_usd_per_1k_tokens, + "baseline_cached_input_usd_per_1k_tokens": result.baseline_cached_input_usd_per_1k_tokens, + "candidate_input_usd_per_1k_tokens": result.candidate_input_usd_per_1k_tokens, + "candidate_output_usd_per_1k_tokens": result.candidate_output_usd_per_1k_tokens, + "candidate_cached_input_usd_per_1k_tokens": result.candidate_cached_input_usd_per_1k_tokens, + }, + "warnings": list(result.pricing_warnings), + "hints": list(result.pricing_hints), + "catalog": { + "enabled": result.catalog_enabled, + "catalog_version": result.catalog_version, + "baseline_slot_id": result.baseline_catalog_slot_id, + "candidate_slot_id": result.candidate_catalog_slot_id, + "baseline_cost_per_run_usd": result.baseline_catalog_cost_per_run_usd, + "candidate_cost_per_run_usd": result.candidate_catalog_cost_per_run_usd, + "delta_cost_per_run_usd": result.delta_catalog_cost_per_run_usd, + "warnings": list(result.catalog_warnings), + }, + }, + "samples": { + "baseline_runs": result.baseline_runs, + "candidate_runs": result.candidate_runs, + "confidence": result.confidence, + "confidence_reason": result.confidence_reason, + }, + "metrics": { + "baseline_cost_per_run_usd": result.baseline_cost_per_run_usd, + "candidate_cost_per_run_usd": result.candidate_cost_per_run_usd, + "delta_cost_per_run_usd": result.delta_cost_per_run_usd, + "delta_cost_per_run_pct": result.delta_cost_per_run_pct, + "baseline_latency_ms_avg": result.baseline_latency_ms_avg, + "candidate_latency_ms_avg": result.candidate_latency_ms_avg, + "delta_latency_ms_avg": result.delta_latency_ms_avg, + "baseline_error_rate": result.baseline_error_rate, + "candidate_error_rate": result.candidate_error_rate, + "delta_error_rate": result.delta_error_rate, + }, + "policy": result.policy.model_dump(mode="json"), + } + + def _load_release_or_error(storage: Storage, release_id: str, *, role: str) -> tuple[ReleaseRecord, ReleaseArtifact]: record = storage.get_release(release_id) if not record: @@ -206,6 +289,90 @@ def compute_diff( f"has no entry for model {cand_artifact.spec.runtime.model!r}" ) + pricing_hints: list[str] = [] + pricing_hints.extend( + collect_pricing_skew_hints( + storage, + role="baseline", + ref=base_ref, + model=base_artifact.spec.runtime.model, + table=base_table, + model_in_table=base_entry is not None, + ) + ) + pricing_hints.extend( + collect_pricing_skew_hints( + storage, + role="candidate", + ref=cand_ref, + model=cand_artifact.spec.runtime.model, + table=cand_table, + model_in_table=cand_entry is not None, + ) + ) + + catalog_enabled = False + catalog_version: str | None = None + baseline_catalog_slot_id: str | None = None + candidate_catalog_slot_id: str | None = None + baseline_catalog_cost: float | None = None + candidate_catalog_cost: float | None = None + delta_catalog_cost: float | None = None + catalog_warnings: list[str] = [] + + if cfg.pricing_catalog_path: + cat_path = Path(cfg.pricing_catalog_path) + if not cat_path.is_absolute(): + cat_path = Path.cwd() / cat_path + try: + catalog = load_pricing_catalog(cat_path) + catalog_enabled = True + catalog_version = catalog.catalog_version + baseline_catalog_slot_id = resolve_catalog_slot_id( + catalog, + provider=base_ref.provider, + pricing_version=base_ref.pricing_version, + model=base_artifact.spec.runtime.model, + ) + candidate_catalog_slot_id = resolve_catalog_slot_id( + catalog, + provider=cand_ref.provider, + pricing_version=cand_ref.pricing_version, + model=cand_artifact.spec.runtime.model, + ) + b_cat_entry, b_err = resolve_catalog_pricing_entry( + catalog, + provider=base_ref.provider, + pricing_version=base_ref.pricing_version, + model=base_artifact.spec.runtime.model, + ) + c_cat_entry, c_err = resolve_catalog_pricing_entry( + catalog, + provider=cand_ref.provider, + pricing_version=cand_ref.pricing_version, + model=cand_artifact.spec.runtime.model, + ) + if b_err: + catalog_warnings.append(f"baseline: {b_err}") + if c_err: + catalog_warnings.append(f"candidate: {c_err}") + if b_cat_entry is not None and c_cat_entry is not None: + b_tab = catalog_tariff_as_table(base_artifact.spec.runtime.model, b_cat_entry) + c_tab = catalog_tariff_as_table(cand_artifact.spec.runtime.model, c_cat_entry) + b_roll = compute_rollup(baseline_events, b_tab) + c_roll = compute_rollup(candidate_events, c_tab) + baseline_catalog_cost = b_roll.cost_per_run_usd + candidate_catalog_cost = c_roll.cost_per_run_usd + delta_catalog_cost = candidate_catalog_cost - baseline_catalog_cost + except FileNotFoundError as exc: + catalog_warnings.append(str(exc)) + except yaml.YAMLError as exc: + catalog_warnings.append(f"pricing catalog YAML parse error: {exc}") + except ValidationError as exc: + catalog_warnings.append(f"invalid pricing catalog YAML: {exc}") + except OSError as exc: + catalog_warnings.append(f"pricing catalog I/O error: {exc}") + return DiffOutcome( window=window, since=since, @@ -249,11 +416,20 @@ def compute_diff( candidate_error_rate=diff.candidate.error_rate, delta_error_rate=diff.delta_error_rate, policy=diff.policy, + pricing_hints=tuple(pricing_hints), + catalog_enabled=catalog_enabled, + catalog_version=catalog_version, + baseline_catalog_slot_id=baseline_catalog_slot_id, + candidate_catalog_slot_id=candidate_catalog_slot_id, + baseline_catalog_cost_per_run_usd=baseline_catalog_cost, + candidate_catalog_cost_per_run_usd=candidate_catalog_cost, + delta_catalog_cost_per_run_usd=delta_catalog_cost, + catalog_warnings=tuple(catalog_warnings), pricing_warnings=tuple(pricing_warnings), ) -def _evaluate_promotion_or_rollback( +def _compute_promotion_policy_result( *, cfg: WorkspaceConfig, storage: Storage, @@ -261,84 +437,109 @@ def _evaluate_promotion_or_rollback( release_id: str, environment: str, window: str, - reason: str, - actor: str, -) -> ActionOutcome: - if not reason.strip(): - raise OperationError("Reason is required for promote/rollback actions.") - +) -> tuple[PolicyResult, str | None, str]: + """Evaluate policy for promote/rollback without mutating the ledger.""" _, target_artifact = _load_release_or_error(storage, release_id, role="target") agent_id = target_artifact.spec.agent.agent_id current_release_id = storage.get_promoted_release_id(agent_id, environment) active_policy = storage.get_active_policy() or default_policy() if action == "promote" and not current_release_id: - policy_result = PolicyResult( - passed=True, - reasons=["first promotion: no promoted baseline for agent/environment"], - ) - else: - if not current_release_id: - raise OperationError("No promoted release exists for this agent/environment; nothing to roll back to.") - baseline_record = storage.get_release(current_release_id) - if not baseline_record: - raise OperationError(f"Promoted baseline release is missing: {current_release_id}") - - baseline_artifact = ReleaseArtifact.model_validate(baseline_record.artifact_json) - baseline_ref = baseline_artifact.spec.pricing_reference - candidate_ref = target_artifact.spec.pricing_reference - baseline_table = _load_pricing_or_error( - storage, - provider=baseline_ref.provider, - version=baseline_ref.pricing_version, - role="promoted_baseline", - ) - candidate_table = _load_pricing_or_error( - storage, - provider=candidate_ref.provider, - version=candidate_ref.pricing_version, - role="candidate" if action == "promote" else "rollback", + return ( + PolicyResult( + passed=True, + reasons=["first promotion: no promoted baseline for agent/environment"], + ), + current_release_id, + agent_id, ) - try: - delta = parse_window(window) - except ValueError as e: - raise OperationError(str(e)) from e - until = utc_now() - since = until - delta + if not current_release_id: + raise OperationError("No promoted release exists for this agent/environment; nothing to roll back to.") + + baseline_record = storage.get_release(current_release_id) + if not baseline_record: + raise OperationError(f"Promoted baseline release is missing: {current_release_id}") + + baseline_artifact = ReleaseArtifact.model_validate(baseline_record.artifact_json) + baseline_ref = baseline_artifact.spec.pricing_reference + candidate_ref = target_artifact.spec.pricing_reference + baseline_table = _load_pricing_or_error( + storage, + provider=baseline_ref.provider, + version=baseline_ref.pricing_version, + role="promoted_baseline", + ) + candidate_table = _load_pricing_or_error( + storage, + provider=candidate_ref.provider, + version=candidate_ref.pricing_version, + role="candidate" if action == "promote" else "rollback", + ) - baseline_events = storage.query_runs( - current_release_id, - since, - until, - environment=environment, - ) - candidate_events = storage.query_runs( - release_id, - since, - until, - environment=environment, + try: + delta = parse_window(window) + except ValueError as e: + raise OperationError(str(e)) from e + until = utc_now() + since = until - delta + + baseline_events = storage.query_runs( + current_release_id, + since, + until, + environment=environment, + ) + candidate_events = storage.query_runs( + release_id, + since, + until, + environment=environment, + ) + + try: + diff = diff_releases( + cfg=cfg, + policy=active_policy, + baseline_events=baseline_events, + candidate_events=candidate_events, + baseline_pricing_table=baseline_table, + candidate_pricing_table=candidate_table, + window=window, ) + except KeyError as e: + raise OperationError( + "Pricing table missing model entry. " + f"baseline_model={baseline_artifact.spec.runtime.model} " + f"candidate_model={target_artifact.spec.runtime.model}." + ) from e + except ValueError as e: + raise OperationError(str(e)) from e + return (diff.policy, current_release_id, agent_id) - try: - diff = diff_releases( - cfg=cfg, - policy=active_policy, - baseline_events=baseline_events, - candidate_events=candidate_events, - baseline_pricing_table=baseline_table, - candidate_pricing_table=candidate_table, - window=window, - ) - except KeyError as e: - raise OperationError( - "Pricing table missing model entry. " - f"baseline_model={baseline_artifact.spec.runtime.model} " - f"candidate_model={target_artifact.spec.runtime.model}." - ) from e - except ValueError as e: - raise OperationError(str(e)) from e - policy_result = diff.policy + +def _evaluate_promotion_or_rollback( + *, + cfg: WorkspaceConfig, + storage: Storage, + action: Literal["promote", "rollback"], + release_id: str, + environment: str, + window: str, + reason: str, + actor: str, +) -> ActionOutcome: + if not reason.strip(): + raise OperationError("Reason is required for promote/rollback actions.") + + policy_result, current_release_id, agent_id = _compute_promotion_policy_result( + cfg=cfg, + storage=storage, + action=action, + release_id=release_id, + environment=environment, + window=window, + ) action_id = f"act_{uuid4().hex[:12]}" record = PromotionRecord( @@ -389,7 +590,13 @@ def promote_release( window: str, reason: str, actor: str, + _approval_confirm: bool = False, ) -> ActionOutcome: + if cfg.promotion_requires_approval and not _approval_confirm: + raise OperationError( + "Workspace promotion_requires_approval=true: use promote-request then promote-confirm " + "(HTTP POST /v1/promote/request and POST /v1/promote/confirm)." + ) return _evaluate_promotion_or_rollback( cfg=cfg, storage=storage, @@ -402,6 +609,86 @@ def promote_release( ) +def request_promotion( + *, + cfg: WorkspaceConfig, + storage: Storage, + release_id: str, + environment: str, + window: str, + reason: str, + actor: str, +) -> PromotionRequestRecord: + if not cfg.promotion_requires_approval: + raise OperationError( + "promotion_requires_approval is false in flightdeck.yaml; use direct `release promote` " + "or set promotion_requires_approval: true to use the approval workflow." + ) + if not reason.strip(): + raise OperationError("Reason is required for promotion requests.") + + policy_result, current_release_id, agent_id = _compute_promotion_policy_result( + cfg=cfg, + storage=storage, + action="promote", + release_id=release_id, + environment=environment, + window=window, + ) + if not policy_result.passed: + raise OperationError( + "Policy does not allow this promotion; request not recorded. Reasons: " + + "; ".join(policy_result.reasons) + ) + + request_id = f"prq_{uuid4().hex[:12]}" + record = PromotionRequestRecord( + request_id=request_id, + status="pending", + release_id=release_id, + agent_id=agent_id, + environment=environment, + window=window, + reason=reason, + actor=actor, + baseline_release_id=current_release_id, + policy_result=policy_result, + created_at=utc_now(), + ) + storage.insert_promotion_request(record) + return record + + +def confirm_promotion_request( + *, + cfg: WorkspaceConfig, + storage: Storage, + request_id: str, + approval_reason: str, + actor: str, +) -> ActionOutcome: + if not approval_reason.strip(): + raise OperationError("approval_reason is required for promote-confirm.") + pending = storage.get_promotion_request(request_id) + if pending is None or pending.status != "pending": + raise OperationError("Unknown promotion request_id or request is not pending.") + + combined_reason = f"{pending.reason} | approval: {approval_reason}" + outcome = promote_release( + cfg=cfg, + storage=storage, + release_id=pending.release_id, + environment=pending.environment, + window=pending.window, + reason=combined_reason, + actor=actor, + _approval_confirm=True, + ) + if outcome.promoted_pointer_changed: + storage.mark_promotion_request_completed(request_id, completed_action_id=outcome.action_id) + return outcome + + def rollback_release( *, cfg: WorkspaceConfig, @@ -424,6 +711,54 @@ def rollback_release( ) +def query_run_events_page( + *, + cfg: WorkspaceConfig, + storage: Storage, + release_id: str, + window: str, + environment: str | None, + tenant_id: str | None, + task_id: str | None, + limit: int, +) -> dict[str, object]: + """Read-only slice of run events for forensics (newest-first truncation).""" + if not storage.get_release(release_id): + raise OperationError(f"Unknown release: {release_id}") + env = environment or cfg.default_environment + try: + delta = parse_window(window) + except ValueError as e: + raise OperationError(str(e)) from e + until = utc_now() + since = until - delta + events = storage.query_runs( + release_id, + since, + until, + tenant_id=tenant_id, + task_id=task_id, + environment=env, + ) + events_sorted = sorted(events, key=lambda e: e.timestamp, reverse=True) + lim = max(1, min(500, limit)) + page = events_sorted[:lim] + return { + "release_id": release_id, + "since": since.isoformat(), + "until": until.isoformat(), + "filters": { + "environment": env, + "tenant_id": tenant_id, + "task_id": task_id, + }, + "matched_total": len(events), + "returned": len(page), + "truncated": len(events) > len(page), + "events": [e.model_dump(mode="json") for e in page], + } + + def list_timeline( *, storage: Storage, diff --git a/src/flightdeck/pricing_hints.py b/src/flightdeck/pricing_hints.py new file mode 100644 index 0000000..46f255d --- /dev/null +++ b/src/flightdeck/pricing_hints.py @@ -0,0 +1,53 @@ +"""Non-blocking pricing diagnostics (version skew hints, model name hints).""" + +from __future__ import annotations + +from flightdeck.models import PricingTable, ReleasePricingReference +from flightdeck.storage import Storage + + +def _other_versions_for_provider(storage: Storage, provider: str, current_version: str) -> list[str]: + return [v for v in storage.list_pricing_versions(provider) if v != current_version] + + +def _similar_model_hints(table: PricingTable, model: str, *, limit: int = 5) -> list[str]: + if not model: + return [] + ml = model.lower() + hints: list[str] = [] + for e in table.entries: + el = e.model.lower() + if el == ml: + continue + if ml in el or el in ml: + hints.append(e.model) + if len(hints) >= limit: + break + return hints + + +def collect_pricing_skew_hints( + storage: Storage, + *, + role: str, + ref: ReleasePricingReference, + model: str, + table: PricingTable, + model_in_table: bool, +) -> list[str]: + """Return human-readable hints; never raises.""" + hints: list[str] = [] + others = _other_versions_for_provider(storage, ref.provider, ref.pricing_version) + if len(others) >= 1: + sample = ", ".join(others[:5]) + more = f" (+{len(others) - 5} more)" if len(others) > 5 else "" + hints.append( + f"{role}: provider {ref.provider!r} has other imported pricing_version values " + f"besides {ref.pricing_version!r}: {sample}{more}. " + f"Confirm the release pins the table you intend." + ) + if not model_in_table and model: + sim = _similar_model_hints(table, model) + if sim: + hints.append(f"{role}: table has no exact model {model!r}; similar names: {', '.join(sim)}") + return hints diff --git a/src/flightdeck/sdk/client.py b/src/flightdeck/sdk/client.py index 9797afa..0f13968 100644 --- a/src/flightdeck/sdk/client.py +++ b/src/flightdeck/sdk/client.py @@ -117,6 +117,90 @@ def post_promote( resp.raise_for_status() return resp.json() + def post_promote_request( + self, + *, + release_id: str, + environment: str, + window: str, + reason: str, + actor: str = "sdk", + ) -> dict[str, Any]: + body = { + "release_id": release_id, + "environment": environment, + "window": window, + "reason": reason, + "actor": actor, + } + resp = self._request_with_retry("POST", "/v1/promote/request", json=body, headers=self._json_headers()) + resp.raise_for_status() + return resp.json() + + def post_promote_confirm( + self, + *, + request_id: str, + approval_reason: str, + actor: str = "sdk", + ) -> dict[str, Any]: + body = { + "request_id": request_id, + "approval_reason": approval_reason, + "actor": actor, + } + resp = self._request_with_retry("POST", "/v1/promote/confirm", json=body, headers=self._json_headers()) + resp.raise_for_status() + return resp.json() + + def list_promotion_requests( + self, + *, + status: str | None = None, + limit: int = 50, + ) -> dict[str, Any]: + params: dict[str, str | int] = {"limit": limit} + if status is not None: + params["status"] = status + resp = self._request_with_retry( + "GET", + "/v1/promotion-requests", + params=params, + headers=self._auth_headers() or None, + ) + resp.raise_for_status() + return resp.json() + + def list_runs( + self, + *, + release_id: str, + window: str, + environment: str | None = None, + tenant_id: str | None = None, + task_id: str | None = None, + limit: int = 100, + ) -> dict[str, Any]: + params: dict[str, str | int] = { + "release_id": release_id, + "window": window, + "limit": limit, + } + if environment is not None: + params["environment"] = environment + if tenant_id is not None: + params["tenant_id"] = tenant_id + if task_id is not None: + params["task_id"] = task_id + resp = self._request_with_retry( + "GET", + "/v1/runs", + params=params, + headers=self._auth_headers() or None, + ) + resp.raise_for_status() + return resp.json() + def post_rollback( self, *, @@ -282,6 +366,90 @@ async def post_promote( resp.raise_for_status() return resp.json() + async def post_promote_request( + self, + *, + release_id: str, + environment: str, + window: str, + reason: str, + actor: str = "sdk", + ) -> dict[str, Any]: + body = { + "release_id": release_id, + "environment": environment, + "window": window, + "reason": reason, + "actor": actor, + } + resp = await self._request_with_retry("POST", "/v1/promote/request", json=body, headers=self._json_headers()) + resp.raise_for_status() + return resp.json() + + async def post_promote_confirm( + self, + *, + request_id: str, + approval_reason: str, + actor: str = "sdk", + ) -> dict[str, Any]: + body = { + "request_id": request_id, + "approval_reason": approval_reason, + "actor": actor, + } + resp = await self._request_with_retry("POST", "/v1/promote/confirm", json=body, headers=self._json_headers()) + resp.raise_for_status() + return resp.json() + + async def list_promotion_requests( + self, + *, + status: str | None = None, + limit: int = 50, + ) -> dict[str, Any]: + params: dict[str, str | int] = {"limit": limit} + if status is not None: + params["status"] = status + resp = await self._request_with_retry( + "GET", + "/v1/promotion-requests", + params=params, + headers=self._auth_headers() or None, + ) + resp.raise_for_status() + return resp.json() + + async def list_runs( + self, + *, + release_id: str, + window: str, + environment: str | None = None, + tenant_id: str | None = None, + task_id: str | None = None, + limit: int = 100, + ) -> dict[str, Any]: + params: dict[str, str | int] = { + "release_id": release_id, + "window": window, + "limit": limit, + } + if environment is not None: + params["environment"] = environment + if tenant_id is not None: + params["tenant_id"] = tenant_id + if task_id is not None: + params["task_id"] = task_id + resp = await self._request_with_retry( + "GET", + "/v1/runs", + params=params, + headers=self._auth_headers() or None, + ) + resp.raise_for_status() + return resp.json() + async def post_rollback( self, *, diff --git a/src/flightdeck/server/routes/actions.py b/src/flightdeck/server/routes/actions.py index f2632ae..9771001 100644 --- a/src/flightdeck/server/routes/actions.py +++ b/src/flightdeck/server/routes/actions.py @@ -3,7 +3,16 @@ from fastapi import APIRouter, HTTPException, Request from pydantic import BaseModel, Field -from flightdeck.operations import ActionOutcome, OperationError, compute_diff, promote_release, rollback_release +from flightdeck.operations import ( + ActionOutcome, + OperationError, + compute_diff, + confirm_promotion_request, + diff_outcome_to_public_dict, + promote_release, + request_promotion, + rollback_release, +) from flightdeck.server.routes.common import ensure_app_state router = APIRouter() @@ -28,6 +37,20 @@ class ActionRequest(BaseModel): actor: str = "http" +class PromotionRequestCreate(BaseModel): + release_id: str + environment: str + window: str + reason: str = Field(min_length=1) + actor: str = "http" + + +class PromotionConfirmRequest(BaseModel): + request_id: str + approval_reason: str = Field(min_length=1) + actor: str = "http" + + def _raise_bad_request(exc: OperationError) -> HTTPException: return HTTPException(status_code=400, detail=str(exc)) @@ -89,60 +112,7 @@ def post_diff(request: Request, req: DiffRequest) -> dict[str, object]: except OperationError as exc: raise _raise_bad_request(exc) from exc - return { - "window": result.window, - "since": result.since.isoformat(), - "until": result.until.isoformat(), - "filters": { - "environment": result.environment, - "tenant_id": result.tenant_id, - "task_id": result.task_id, - }, - "pricing": { - "baseline_provider": result.baseline_pricing_provider, - "baseline_version": result.baseline_pricing_version, - "baseline_model": result.baseline_model, - "candidate_provider": result.candidate_pricing_provider, - "candidate_version": result.candidate_pricing_version, - "candidate_model": result.candidate_model, - "pricing_or_model_changed": result.pricing_or_model_changed, - # Per-side unit prices for the resolved model (None when the model - # is missing from the pricing table; cost rollup will surface its - # own KeyError before reaching here when events are present). - "prices": { - "baseline_input_usd_per_1k_tokens": result.baseline_input_usd_per_1k_tokens, - "baseline_output_usd_per_1k_tokens": result.baseline_output_usd_per_1k_tokens, - "baseline_cached_input_usd_per_1k_tokens": result.baseline_cached_input_usd_per_1k_tokens, - "candidate_input_usd_per_1k_tokens": result.candidate_input_usd_per_1k_tokens, - "candidate_output_usd_per_1k_tokens": result.candidate_output_usd_per_1k_tokens, - "candidate_cached_input_usd_per_1k_tokens": result.candidate_cached_input_usd_per_1k_tokens, - }, - # Diagnostic strings when a release's resolved model has no entry - # in its pricing table; the cost rollup still raises if such a - # model appears in events. These are informational only and do - # not flip policy. - "warnings": list(result.pricing_warnings), - }, - "samples": { - "baseline_runs": result.baseline_runs, - "candidate_runs": result.candidate_runs, - "confidence": result.confidence, - "confidence_reason": result.confidence_reason, - }, - "metrics": { - "baseline_cost_per_run_usd": result.baseline_cost_per_run_usd, - "candidate_cost_per_run_usd": result.candidate_cost_per_run_usd, - "delta_cost_per_run_usd": result.delta_cost_per_run_usd, - "delta_cost_per_run_pct": result.delta_cost_per_run_pct, - "baseline_latency_ms_avg": result.baseline_latency_ms_avg, - "candidate_latency_ms_avg": result.candidate_latency_ms_avg, - "delta_latency_ms_avg": result.delta_latency_ms_avg, - "baseline_error_rate": result.baseline_error_rate, - "candidate_error_rate": result.candidate_error_rate, - "delta_error_rate": result.delta_error_rate, - }, - "policy": result.policy.model_dump(mode="json"), - } + return diff_outcome_to_public_dict(result) @router.post("/v1/promote") @@ -168,6 +138,63 @@ def post_promote(request: Request, req: ActionRequest) -> dict[str, object]: return _action_body(outcome) +@router.post("/v1/promote/request") +def post_promote_request(request: Request, req: PromotionRequestCreate) -> dict[str, object]: + _require_mutation_access(request) + cfg, storage = ensure_app_state(request) + try: + record = request_promotion( + cfg=cfg, + storage=storage, + release_id=req.release_id, + environment=req.environment, + window=req.window, + reason=req.reason, + actor=req.actor, + ) + except OperationError as exc: + msg = str(exc) + if msg.startswith("Policy does not allow"): + raise HTTPException( + status_code=409, + detail={"message": msg}, + ) from exc + raise _raise_bad_request(exc) from exc + + return { + "request_id": record.request_id, + "status": record.status, + "release_id": record.release_id, + "agent_id": record.agent_id, + "environment": record.environment, + "window": record.window, + "baseline_release_id": record.baseline_release_id, + "policy": record.policy_result.model_dump(mode="json"), + "created_at": record.created_at.isoformat(), + } + + +@router.post("/v1/promote/confirm") +def post_promote_confirm(request: Request, req: PromotionConfirmRequest) -> dict[str, object]: + _require_mutation_access(request) + cfg, storage = ensure_app_state(request) + try: + outcome = confirm_promotion_request( + cfg=cfg, + storage=storage, + request_id=req.request_id, + approval_reason=req.approval_reason, + actor=req.actor, + ) + except OperationError as exc: + raise _raise_bad_request(exc) from exc + + if not outcome.policy.passed: + raise _raise_policy_blocked("promotion", outcome) + + return _action_body(outcome) + + @router.post("/v1/rollback") def post_rollback(request: Request, req: ActionRequest) -> dict[str, object]: _require_mutation_access(request) diff --git a/src/flightdeck/server/routes/read.py b/src/flightdeck/server/routes/read.py index 549e473..7717083 100644 --- a/src/flightdeck/server/routes/read.py +++ b/src/flightdeck/server/routes/read.py @@ -1,8 +1,9 @@ from __future__ import annotations -from fastapi import APIRouter, Query, Request +from fastapi import APIRouter, HTTPException, Query, Request -from flightdeck.operations import list_timeline +from flightdeck.models import PromotionRequestRecord +from flightdeck.operations import OperationError, list_timeline, query_run_events_page from flightdeck.server.routes.common import ensure_app_state router = APIRouter() @@ -32,3 +33,58 @@ def get_actions( _, storage = ensure_app_state(request) timeline = list_timeline(storage=storage, agent_id=agent_id, environment=environment, action_limit=limit) return {"actions": timeline.actions} + + +def _promotion_request_to_dict(r: PromotionRequestRecord) -> dict[str, object]: + return { + "request_id": r.request_id, + "status": r.status, + "release_id": r.release_id, + "agent_id": r.agent_id, + "environment": r.environment, + "window": r.window, + "reason": r.reason, + "actor": r.actor, + "baseline_release_id": r.baseline_release_id, + "policy": r.policy_result.model_dump(mode="json"), + "created_at": r.created_at.isoformat(), + "resolved_at": r.resolved_at.isoformat() if r.resolved_at else None, + "completed_action_id": r.completed_action_id, + } + + +@router.get("/v1/promotion-requests") +def get_promotion_requests( + request: Request, + status: str | None = Query(default=None), + limit: int = Query(default=50, ge=1, le=500), +) -> dict[str, list[dict[str, object]]]: + _, storage = ensure_app_state(request) + rows = storage.list_promotion_requests(status=status, limit=limit) + return {"requests": [_promotion_request_to_dict(r) for r in rows]} + + +@router.get("/v1/runs") +def get_runs( + request: Request, + release_id: str = Query(..., min_length=1), + window: str = Query(..., min_length=1), + environment: str | None = Query(default=None), + tenant_id: str | None = Query(default=None), + task_id: str | None = Query(default=None), + limit: int = Query(default=100, ge=1, le=500), +) -> dict[str, object]: + cfg, storage = ensure_app_state(request) + try: + return query_run_events_page( + cfg=cfg, + storage=storage, + release_id=release_id, + window=window, + environment=environment, + tenant_id=tenant_id, + task_id=task_id, + limit=limit, + ) + except OperationError as exc: + raise HTTPException(status_code=400, detail=str(exc)) from exc diff --git a/src/flightdeck/server/static/assets/index-92annNc3.js b/src/flightdeck/server/static/assets/index-CSQLdWTa.js similarity index 58% rename from src/flightdeck/server/static/assets/index-92annNc3.js rename to src/flightdeck/server/static/assets/index-CSQLdWTa.js index 85ff6f3..e2cd5f6 100644 --- a/src/flightdeck/server/static/assets/index-92annNc3.js +++ b/src/flightdeck/server/static/assets/index-CSQLdWTa.js @@ -1,11 +1,11 @@ -(function(){const s=document.createElement("link").relList;if(s&&s.supports&&s.supports("modulepreload"))return;for(const d of document.querySelectorAll('link[rel="modulepreload"]'))f(d);new MutationObserver(d=>{for(const h of d)if(h.type==="childList")for(const b of h.addedNodes)b.tagName==="LINK"&&b.rel==="modulepreload"&&f(b)}).observe(document,{childList:!0,subtree:!0});function o(d){const h={};return d.integrity&&(h.integrity=d.integrity),d.referrerPolicy&&(h.referrerPolicy=d.referrerPolicy),d.crossOrigin==="use-credentials"?h.credentials="include":d.crossOrigin==="anonymous"?h.credentials="omit":h.credentials="same-origin",h}function f(d){if(d.ep)return;d.ep=!0;const h=o(d);fetch(d.href,h)}})();var Cf={exports:{}},Mn={};var im;function yy(){if(im)return Mn;im=1;var i=Symbol.for("react.transitional.element"),s=Symbol.for("react.fragment");function o(f,d,h){var b=null;if(h!==void 0&&(b=""+h),d.key!==void 0&&(b=""+d.key),"key"in d){h={};for(var N in d)N!=="key"&&(h[N]=d[N])}else h=d;return d=h.ref,{$$typeof:i,type:f,key:b,ref:d!==void 0?d:null,props:h}}return Mn.Fragment=s,Mn.jsx=o,Mn.jsxs=o,Mn}var cm;function py(){return cm||(cm=1,Cf.exports=yy()),Cf.exports}var m=py(),Uf={exports:{}},P={};var fm;function gy(){if(fm)return P;fm=1;var i=Symbol.for("react.transitional.element"),s=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),f=Symbol.for("react.strict_mode"),d=Symbol.for("react.profiler"),h=Symbol.for("react.consumer"),b=Symbol.for("react.context"),N=Symbol.for("react.forward_ref"),S=Symbol.for("react.suspense"),y=Symbol.for("react.memo"),j=Symbol.for("react.lazy"),A=Symbol.for("react.activity"),q=Symbol.iterator;function H(g){return g===null||typeof g!="object"?null:(g=q&&g[q]||g["@@iterator"],typeof g=="function"?g:null)}var Z={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},G=Object.assign,B={};function Q(g,U,Y){this.props=g,this.context=U,this.refs=B,this.updater=Y||Z}Q.prototype.isReactComponent={},Q.prototype.setState=function(g,U){if(typeof g!="object"&&typeof g!="function"&&g!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,g,U,"setState")},Q.prototype.forceUpdate=function(g){this.updater.enqueueForceUpdate(this,g,"forceUpdate")};function V(){}V.prototype=Q.prototype;function $(g,U,Y){this.props=g,this.context=U,this.refs=B,this.updater=Y||Z}var F=$.prototype=new V;F.constructor=$,G(F,Q.prototype),F.isPureReactComponent=!0;var le=Array.isArray;function be(){}var X={H:null,A:null,T:null,S:null},Ne=Object.prototype.hasOwnProperty;function Ke(g,U,Y){var K=Y.ref;return{$$typeof:i,type:g,key:U,ref:K!==void 0?K:null,props:Y}}function Ct(g,U){return Ke(g.type,U,g.props)}function vt(g){return typeof g=="object"&&g!==null&&g.$$typeof===i}function Je(g){var U={"=":"=0",":":"=2"};return"$"+g.replace(/[=:]/g,function(Y){return U[Y]})}var Ut=/\/+/g;function yt(g,U){return typeof g=="object"&&g!==null&&g.key!=null?Je(""+g.key):U.toString(36)}function Ce(g){switch(g.status){case"fulfilled":return g.value;case"rejected":throw g.reason;default:switch(typeof g.status=="string"?g.then(be,be):(g.status="pending",g.then(function(U){g.status==="pending"&&(g.status="fulfilled",g.value=U)},function(U){g.status==="pending"&&(g.status="rejected",g.reason=U)})),g.status){case"fulfilled":return g.value;case"rejected":throw g.reason}}throw g}function D(g,U,Y,K,ee){var ne=typeof g;(ne==="undefined"||ne==="boolean")&&(g=null);var me=!1;if(g===null)me=!0;else switch(ne){case"bigint":case"string":case"number":me=!0;break;case"object":switch(g.$$typeof){case i:case s:me=!0;break;case j:return me=g._init,D(me(g._payload),U,Y,K,ee)}}if(me)return ee=ee(g),me=K===""?"."+yt(g,0):K,le(ee)?(Y="",me!=null&&(Y=me.replace(Ut,"$&/")+"/"),D(ee,U,Y,"",function(La){return La})):ee!=null&&(vt(ee)&&(ee=Ct(ee,Y+(ee.key==null||g&&g.key===ee.key?"":(""+ee.key).replace(Ut,"$&/")+"/")+me)),U.push(ee)),1;me=0;var We=K===""?".":K+":";if(le(g))for(var je=0;je>>1,_e=D[ye];if(0>>1;yed(Y,I))K<_e&&0>d(ee,Y)?(D[ye]=ee,D[K]=I,ye=K):(D[ye]=Y,D[U]=I,ye=U);else if(K<_e&&0>d(ee,I))D[ye]=ee,D[K]=I,ye=K;else break e}}return L}function d(D,L){var I=D.sortIndex-L.sortIndex;return I!==0?I:D.id-L.id}if(i.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var h=performance;i.unstable_now=function(){return h.now()}}else{var b=Date,N=b.now();i.unstable_now=function(){return b.now()-N}}var S=[],y=[],j=1,A=null,q=3,H=!1,Z=!1,G=!1,B=!1,Q=typeof setTimeout=="function"?setTimeout:null,V=typeof clearTimeout=="function"?clearTimeout:null,$=typeof setImmediate<"u"?setImmediate:null;function F(D){for(var L=o(y);L!==null;){if(L.callback===null)f(y);else if(L.startTime<=D)f(y),L.sortIndex=L.expirationTime,s(S,L);else break;L=o(y)}}function le(D){if(G=!1,F(D),!Z)if(o(S)!==null)Z=!0,be||(be=!0,Je());else{var L=o(y);L!==null&&Ce(le,L.startTime-D)}}var be=!1,X=-1,Ne=5,Ke=-1;function Ct(){return B?!0:!(i.unstable_now()-KeD&&Ct());){var ye=A.callback;if(typeof ye=="function"){A.callback=null,q=A.priorityLevel;var _e=ye(A.expirationTime<=D);if(D=i.unstable_now(),typeof _e=="function"){A.callback=_e,F(D),L=!0;break t}A===o(S)&&f(S),F(D)}else f(S);A=o(S)}if(A!==null)L=!0;else{var g=o(y);g!==null&&Ce(le,g.startTime-D),L=!1}}break e}finally{A=null,q=I,H=!1}L=void 0}}finally{L?Je():be=!1}}}var Je;if(typeof $=="function")Je=function(){$(vt)};else if(typeof MessageChannel<"u"){var Ut=new MessageChannel,yt=Ut.port2;Ut.port1.onmessage=vt,Je=function(){yt.postMessage(null)}}else Je=function(){Q(vt,0)};function Ce(D,L){X=Q(function(){D(i.unstable_now())},L)}i.unstable_IdlePriority=5,i.unstable_ImmediatePriority=1,i.unstable_LowPriority=4,i.unstable_NormalPriority=3,i.unstable_Profiling=null,i.unstable_UserBlockingPriority=2,i.unstable_cancelCallback=function(D){D.callback=null},i.unstable_forceFrameRate=function(D){0>D||125ye?(D.sortIndex=I,s(y,D),o(S)===null&&D===o(y)&&(G?(V(X),X=-1):G=!0,Ce(le,I-ye))):(D.sortIndex=_e,s(S,D),Z||H||(Z=!0,be||(be=!0,Je()))),D},i.unstable_shouldYield=Ct,i.unstable_wrapCallback=function(D){var L=q;return function(){var I=q;q=L;try{return D.apply(this,arguments)}finally{q=I}}}})(qf)),qf}var om;function by(){return om||(om=1,Bf.exports=Sy()),Bf.exports}var Lf={exports:{}},$e={};var dm;function _y(){if(dm)return $e;dm=1;var i=$f();function s(S){var y="https://react.dev/errors/"+S;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(i)}catch(s){console.error(s)}}return i(),Lf.exports=_y(),Lf.exports}var hm;function Ty(){if(hm)return Cn;hm=1;var i=by(),s=$f(),o=Ey();function f(e){var t="https://react.dev/errors/"+e;if(1_e||(e.current=ye[_e],ye[_e]=null,_e--)}function Y(e,t){_e++,ye[_e]=e.current,e.current=t}var K=g(null),ee=g(null),ne=g(null),me=g(null);function We(e,t){switch(Y(ne,t),Y(ee,e),Y(K,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Od(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Od(t),e=jd(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}U(K),Y(K,e)}function je(){U(K),U(ee),U(ne)}function La(e){e.memoizedState!==null&&Y(me,e);var t=K.current,l=jd(t,e.type);t!==l&&(Y(ee,e),Y(K,l))}function Yn(e){ee.current===e&&(U(K),U(ee)),me.current===e&&(U(me),Rn._currentValue=I)}var hi,ns;function jl(e){if(hi===void 0)try{throw Error()}catch(l){var t=l.stack.trim().match(/\n( *(at )?)/);hi=t&&t[1]||"",ns=-1{for(const h of m)if(h.type==="childList")for(const b of h.addedNodes)b.tagName==="LINK"&&b.rel==="modulepreload"&&f(b)}).observe(document,{childList:!0,subtree:!0});function o(m){const h={};return m.integrity&&(h.integrity=m.integrity),m.referrerPolicy&&(h.referrerPolicy=m.referrerPolicy),m.crossOrigin==="use-credentials"?h.credentials="include":m.crossOrigin==="anonymous"?h.credentials="omit":h.credentials="same-origin",h}function f(m){if(m.ep)return;m.ep=!0;const h=o(m);fetch(m.href,h)}})();var Mf={exports:{}},Mn={};var im;function yy(){if(im)return Mn;im=1;var i=Symbol.for("react.transitional.element"),s=Symbol.for("react.fragment");function o(f,m,h){var b=null;if(h!==void 0&&(b=""+h),m.key!==void 0&&(b=""+m.key),"key"in m){h={};for(var N in m)N!=="key"&&(h[N]=m[N])}else h=m;return m=h.ref,{$$typeof:i,type:f,key:b,ref:m!==void 0?m:null,props:h}}return Mn.Fragment=s,Mn.jsx=o,Mn.jsxs=o,Mn}var cm;function gy(){return cm||(cm=1,Mf.exports=yy()),Mf.exports}var d=gy(),Uf={exports:{}},P={};var fm;function py(){if(fm)return P;fm=1;var i=Symbol.for("react.transitional.element"),s=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),f=Symbol.for("react.strict_mode"),m=Symbol.for("react.profiler"),h=Symbol.for("react.consumer"),b=Symbol.for("react.context"),N=Symbol.for("react.forward_ref"),S=Symbol.for("react.suspense"),v=Symbol.for("react.memo"),j=Symbol.for("react.lazy"),A=Symbol.for("react.activity"),q=Symbol.iterator;function H(p){return p===null||typeof p!="object"?null:(p=q&&p[q]||p["@@iterator"],typeof p=="function"?p:null)}var V={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},X=Object.assign,B={};function Z(p,U,G){this.props=p,this.context=U,this.refs=B,this.updater=G||V}Z.prototype.isReactComponent={},Z.prototype.setState=function(p,U){if(typeof p!="object"&&typeof p!="function"&&p!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,p,U,"setState")},Z.prototype.forceUpdate=function(p){this.updater.enqueueForceUpdate(this,p,"forceUpdate")};function w(){}w.prototype=Z.prototype;function W(p,U,G){this.props=p,this.context=U,this.refs=B,this.updater=G||V}var Q=W.prototype=new w;Q.constructor=W,X(Q,Z.prototype),Q.isPureReactComponent=!0;var le=Array.isArray;function be(){}var L={H:null,A:null,T:null,S:null},Ne=Object.prototype.hasOwnProperty;function Ke(p,U,G){var J=G.ref;return{$$typeof:i,type:p,key:U,ref:J!==void 0?J:null,props:G}}function Mt(p,U){return Ke(p.type,U,p.props)}function vt(p){return typeof p=="object"&&p!==null&&p.$$typeof===i}function Je(p){var U={"=":"=0",":":"=2"};return"$"+p.replace(/[=:]/g,function(G){return U[G]})}var Ut=/\/+/g;function yt(p,U){return typeof p=="object"&&p!==null&&p.key!=null?Je(""+p.key):U.toString(36)}function Me(p){switch(p.status){case"fulfilled":return p.value;case"rejected":throw p.reason;default:switch(typeof p.status=="string"?p.then(be,be):(p.status="pending",p.then(function(U){p.status==="pending"&&(p.status="fulfilled",p.value=U)},function(U){p.status==="pending"&&(p.status="rejected",p.reason=U)})),p.status){case"fulfilled":return p.value;case"rejected":throw p.reason}}throw p}function C(p,U,G,J,ee){var ne=typeof p;(ne==="undefined"||ne==="boolean")&&(p=null);var me=!1;if(p===null)me=!0;else switch(ne){case"bigint":case"string":case"number":me=!0;break;case"object":switch(p.$$typeof){case i:case s:me=!0;break;case j:return me=p._init,C(me(p._payload),U,G,J,ee)}}if(me)return ee=ee(p),me=J===""?"."+yt(p,0):J,le(ee)?(G="",me!=null&&(G=me.replace(Ut,"$&/")+"/"),C(ee,U,G,"",function(Ya){return Ya})):ee!=null&&(vt(ee)&&(ee=Mt(ee,G+(ee.key==null||p&&p.key===ee.key?"":(""+ee.key).replace(Ut,"$&/")+"/")+me)),U.push(ee)),1;me=0;var We=J===""?".":J+":";if(le(p))for(var je=0;je>>1,_e=C[ye];if(0>>1;yem(G,I))J<_e&&0>m(ee,G)?(C[ye]=ee,C[J]=I,ye=J):(C[ye]=G,C[U]=I,ye=U);else if(J<_e&&0>m(ee,I))C[ye]=ee,C[J]=I,ye=J;else break e}}return Y}function m(C,Y){var I=C.sortIndex-Y.sortIndex;return I!==0?I:C.id-Y.id}if(i.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var h=performance;i.unstable_now=function(){return h.now()}}else{var b=Date,N=b.now();i.unstable_now=function(){return b.now()-N}}var S=[],v=[],j=1,A=null,q=3,H=!1,V=!1,X=!1,B=!1,Z=typeof setTimeout=="function"?setTimeout:null,w=typeof clearTimeout=="function"?clearTimeout:null,W=typeof setImmediate<"u"?setImmediate:null;function Q(C){for(var Y=o(v);Y!==null;){if(Y.callback===null)f(v);else if(Y.startTime<=C)f(v),Y.sortIndex=Y.expirationTime,s(S,Y);else break;Y=o(v)}}function le(C){if(X=!1,Q(C),!V)if(o(S)!==null)V=!0,be||(be=!0,Je());else{var Y=o(v);Y!==null&&Me(le,Y.startTime-C)}}var be=!1,L=-1,Ne=5,Ke=-1;function Mt(){return B?!0:!(i.unstable_now()-KeC&&Mt());){var ye=A.callback;if(typeof ye=="function"){A.callback=null,q=A.priorityLevel;var _e=ye(A.expirationTime<=C);if(C=i.unstable_now(),typeof _e=="function"){A.callback=_e,Q(C),Y=!0;break t}A===o(S)&&f(S),Q(C)}else f(S);A=o(S)}if(A!==null)Y=!0;else{var p=o(v);p!==null&&Me(le,p.startTime-C),Y=!1}}break e}finally{A=null,q=I,H=!1}Y=void 0}}finally{Y?Je():be=!1}}}var Je;if(typeof W=="function")Je=function(){W(vt)};else if(typeof MessageChannel<"u"){var Ut=new MessageChannel,yt=Ut.port2;Ut.port1.onmessage=vt,Je=function(){yt.postMessage(null)}}else Je=function(){Z(vt,0)};function Me(C,Y){L=Z(function(){C(i.unstable_now())},Y)}i.unstable_IdlePriority=5,i.unstable_ImmediatePriority=1,i.unstable_LowPriority=4,i.unstable_NormalPriority=3,i.unstable_Profiling=null,i.unstable_UserBlockingPriority=2,i.unstable_cancelCallback=function(C){C.callback=null},i.unstable_forceFrameRate=function(C){0>C||125ye?(C.sortIndex=I,s(v,C),o(S)===null&&C===o(v)&&(X?(w(L),L=-1):X=!0,Me(le,I-ye))):(C.sortIndex=_e,s(S,C),V||H||(V=!0,be||(be=!0,Je()))),C},i.unstable_shouldYield=Mt,i.unstable_wrapCallback=function(C){var Y=q;return function(){var I=q;q=Y;try{return C.apply(this,arguments)}finally{q=I}}}})(qf)),qf}var om;function by(){return om||(om=1,Bf.exports=Sy()),Bf.exports}var Lf={exports:{}},$e={};var dm;function _y(){if(dm)return $e;dm=1;var i=$f();function s(S){var v="https://react.dev/errors/"+S;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(i)}catch(s){console.error(s)}}return i(),Lf.exports=_y(),Lf.exports}var hm;function Ty(){if(hm)return Un;hm=1;var i=by(),s=$f(),o=Ey();function f(e){var t="https://react.dev/errors/"+e;if(1_e||(e.current=ye[_e],ye[_e]=null,_e--)}function G(e,t){_e++,ye[_e]=e.current,e.current=t}var J=p(null),ee=p(null),ne=p(null),me=p(null);function We(e,t){switch(G(ne,t),G(ee,e),G(J,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Od(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Od(t),e=jd(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}U(J),G(J,e)}function je(){U(J),U(ee),U(ne)}function Ya(e){e.memoizedState!==null&&G(me,e);var t=J.current,l=jd(t,e.type);t!==l&&(G(ee,e),G(J,l))}function Yn(e){ee.current===e&&(U(J),U(ee)),me.current===e&&(U(me),On._currentValue=I)}var hi,ns;function jl(e){if(hi===void 0)try{throw Error()}catch(l){var t=l.stack.trim().match(/\n( *(at )?)/);hi=t&&t[1]||"",ns=-1)":-1n||v[a]!==x[n]){var O=` -`+v[a].replace(" at new "," at ");return e.displayName&&O.includes("")&&(O=O.replace("",e.displayName)),O}while(1<=a&&0<=n);break}}}finally{vi=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?jl(l):""}function Jm(e,t){switch(e.tag){case 26:case 27:case 5:return jl(e.type);case 16:return jl("Lazy");case 13:return e.child!==t&&t!==null?jl("Suspense Fallback"):jl("Suspense");case 19:return jl("SuspenseList");case 0:case 15:return yi(e.type,!1);case 11:return yi(e.type.render,!1);case 1:return yi(e.type,!0);case 31:return jl("Activity");default:return""}}function us(e){try{var t="",l=null;do t+=Jm(e,l),l=e,e=e.return;while(e);return t}catch(a){return` +`);for(n=a=0;an||y[a]!==x[n]){var O=` +`+y[a].replace(" at new "," at ");return e.displayName&&O.includes("")&&(O=O.replace("",e.displayName)),O}while(1<=a&&0<=n);break}}}finally{vi=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?jl(l):""}function Jm(e,t){switch(e.tag){case 26:case 27:case 5:return jl(e.type);case 16:return jl("Lazy");case 13:return e.child!==t&&t!==null?jl("Suspense Fallback"):jl("Suspense");case 19:return jl("SuspenseList");case 0:case 15:return yi(e.type,!1);case 11:return yi(e.type.render,!1);case 1:return yi(e.type,!0);case 31:return jl("Activity");default:return""}}function us(e){try{var t="",l=null;do t+=Jm(e,l),l=e,e=e.return;while(e);return t}catch(a){return` Error generating stack: `+a.message+` -`+a.stack}}var pi=Object.prototype.hasOwnProperty,gi=i.unstable_scheduleCallback,Si=i.unstable_cancelCallback,$m=i.unstable_shouldYield,Wm=i.unstable_requestPaint,nt=i.unstable_now,km=i.unstable_getCurrentPriorityLevel,is=i.unstable_ImmediatePriority,cs=i.unstable_UserBlockingPriority,Gn=i.unstable_NormalPriority,Fm=i.unstable_LowPriority,fs=i.unstable_IdlePriority,Im=i.log,Pm=i.unstable_setDisableYieldValue,Ya=null,ut=null;function ul(e){if(typeof Im=="function"&&Pm(e),ut&&typeof ut.setStrictMode=="function")try{ut.setStrictMode(Ya,e)}catch{}}var it=Math.clz32?Math.clz32:lh,eh=Math.log,th=Math.LN2;function lh(e){return e>>>=0,e===0?32:31-(eh(e)/th|0)|0}var Xn=256,Qn=262144,Zn=4194304;function Dl(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Vn(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var n=0,u=e.suspendedLanes,c=e.pingedLanes;e=e.warmLanes;var r=a&134217727;return r!==0?(a=r&~u,a!==0?n=Dl(a):(c&=r,c!==0?n=Dl(c):l||(l=r&~e,l!==0&&(n=Dl(l))))):(r=a&~u,r!==0?n=Dl(r):c!==0?n=Dl(c):l||(l=a&~e,l!==0&&(n=Dl(l)))),n===0?0:t!==0&&t!==n&&(t&u)===0&&(u=n&-n,l=t&-t,u>=l||u===32&&(l&4194048)!==0)?t:n}function Ga(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function ah(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function ss(){var e=Zn;return Zn<<=1,(Zn&62914560)===0&&(Zn=4194304),e}function bi(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function Xa(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function nh(e,t,l,a,n,u){var c=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var r=e.entanglements,v=e.expirationTimes,x=e.hiddenUpdates;for(l=c&~l;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var rh=/[\n"\\]/g;function gt(e){return e.replace(rh,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function zi(e,t,l,a,n,u,c,r){e.name="",c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"?e.type=c:e.removeAttribute("type"),t!=null?c==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+pt(t)):e.value!==""+pt(t)&&(e.value=""+pt(t)):c!=="submit"&&c!=="reset"||e.removeAttribute("value"),t!=null?Ni(e,c,pt(t)):l!=null?Ni(e,c,pt(l)):a!=null&&e.removeAttribute("value"),n==null&&u!=null&&(e.defaultChecked=!!u),n!=null&&(e.checked=n&&typeof n!="function"&&typeof n!="symbol"),r!=null&&typeof r!="function"&&typeof r!="symbol"&&typeof r!="boolean"?e.name=""+pt(r):e.removeAttribute("name")}function Es(e,t,l,a,n,u,c,r){if(u!=null&&typeof u!="function"&&typeof u!="symbol"&&typeof u!="boolean"&&(e.type=u),t!=null||l!=null){if(!(u!=="submit"&&u!=="reset"||t!=null)){Ai(e);return}l=l!=null?""+pt(l):"",t=t!=null?""+pt(t):l,r||t===e.value||(e.value=t),e.defaultValue=t}a=a??n,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=r?e.checked:!!a,e.defaultChecked=!!a,c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"&&(e.name=c),Ai(e)}function Ni(e,t,l){t==="number"&&Jn(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function la(e,t,l,a){if(e=e.options,t){t={};for(var n=0;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Mi=!1;if(Qt)try{var wa={};Object.defineProperty(wa,"passive",{get:function(){Mi=!0}}),window.addEventListener("test",wa,wa),window.removeEventListener("test",wa,wa)}catch{Mi=!1}var cl=null,Ci=null,Wn=null;function Os(){if(Wn)return Wn;var e,t=Ci,l=t.length,a,n="value"in cl?cl.value:cl.textContent,u=n.length;for(e=0;e=$a),Hs=" ",Bs=!1;function qs(e,t){switch(e){case"keyup":return Lh.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Ls(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var ia=!1;function Gh(e,t){switch(e){case"compositionend":return Ls(t);case"keypress":return t.which!==32?null:(Bs=!0,Hs);case"textInput":return e=t.data,e===Hs&&Bs?null:e;default:return null}}function Xh(e,t){if(ia)return e==="compositionend"||!Li&&qs(e,t)?(e=Os(),Wn=Ci=cl=null,ia=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=a}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Ks(l)}}function $s(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?$s(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Ws(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Jn(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=Jn(e.document)}return t}function Xi(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var Wh=Qt&&"documentMode"in document&&11>=document.documentMode,ca=null,Qi=null,Ia=null,Zi=!1;function ks(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;Zi||ca==null||ca!==Jn(a)||(a=ca,"selectionStart"in a&&Xi(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),Ia&&Fa(Ia,a)||(Ia=a,a=Qu(Qi,"onSelect"),0>=c,n-=c,Ht=1<<32-it(t)+n|l<ae?(fe=J,J=null):fe=J.sibling;var oe=z(_,J,T[ae],M);if(oe===null){J===null&&(J=fe);break}e&&J&&oe.alternate===null&&t(_,J),p=u(oe,p,ae),re===null?W=oe:re.sibling=oe,re=oe,J=fe}if(ae===T.length)return l(_,J),se&&Vt(_,ae),W;if(J===null){for(;aeae?(fe=J,J=null):fe=J.sibling;var Ol=z(_,J,oe.value,M);if(Ol===null){J===null&&(J=fe);break}e&&J&&Ol.alternate===null&&t(_,J),p=u(Ol,p,ae),re===null?W=Ol:re.sibling=Ol,re=Ol,J=fe}if(oe.done)return l(_,J),se&&Vt(_,ae),W;if(J===null){for(;!oe.done;ae++,oe=T.next())oe=C(_,oe.value,M),oe!==null&&(p=u(oe,p,ae),re===null?W=oe:re.sibling=oe,re=oe);return se&&Vt(_,ae),W}for(J=a(J);!oe.done;ae++,oe=T.next())oe=R(J,_,ae,oe.value,M),oe!==null&&(e&&oe.alternate!==null&&J.delete(oe.key===null?ae:oe.key),p=u(oe,p,ae),re===null?W=oe:re.sibling=oe,re=oe);return e&&J.forEach(function(vy){return t(_,vy)}),se&&Vt(_,ae),W}function Se(_,p,T,M){if(typeof T=="object"&&T!==null&&T.type===G&&T.key===null&&(T=T.props.children),typeof T=="object"&&T!==null){switch(T.$$typeof){case H:e:{for(var W=T.key;p!==null;){if(p.key===W){if(W=T.type,W===G){if(p.tag===7){l(_,p.sibling),M=n(p,T.props.children),M.return=_,_=M;break e}}else if(p.elementType===W||typeof W=="object"&&W!==null&&W.$$typeof===Ne&&Ql(W)===p.type){l(_,p.sibling),M=n(p,T.props),nn(M,T),M.return=_,_=M;break e}l(_,p);break}else t(_,p);p=p.sibling}T.type===G?(M=ql(T.props.children,_.mode,M,T.key),M.return=_,_=M):(M=uu(T.type,T.key,T.props,null,_.mode,M),nn(M,T),M.return=_,_=M)}return c(_);case Z:e:{for(W=T.key;p!==null;){if(p.key===W)if(p.tag===4&&p.stateNode.containerInfo===T.containerInfo&&p.stateNode.implementation===T.implementation){l(_,p.sibling),M=n(p,T.children||[]),M.return=_,_=M;break e}else{l(_,p);break}else t(_,p);p=p.sibling}M=ki(T,_.mode,M),M.return=_,_=M}return c(_);case Ne:return T=Ql(T),Se(_,p,T,M)}if(Ce(T))return w(_,p,T,M);if(Je(T)){if(W=Je(T),typeof W!="function")throw Error(f(150));return T=W.call(T),k(_,p,T,M)}if(typeof T.then=="function")return Se(_,p,du(T),M);if(T.$$typeof===$)return Se(_,p,fu(_,T),M);mu(_,T)}return typeof T=="string"&&T!==""||typeof T=="number"||typeof T=="bigint"?(T=""+T,p!==null&&p.tag===6?(l(_,p.sibling),M=n(p,T),M.return=_,_=M):(l(_,p),M=Wi(T,_.mode,M),M.return=_,_=M),c(_)):l(_,p)}return function(_,p,T,M){try{an=0;var W=Se(_,p,T,M);return ga=null,W}catch(J){if(J===pa||J===ru)throw J;var re=ft(29,J,null,_.mode);return re.lanes=M,re.return=_,re}}}var Vl=Sr(!0),br=Sr(!1),dl=!1;function fc(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function sc(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function ml(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function hl(e,t,l){var a=e.updateQueue;if(a===null)return null;if(a=a.shared,(de&2)!==0){var n=a.pending;return n===null?t.next=t:(t.next=n.next,n.next=t),a.pending=t,t=nu(e),ar(e,null,l),t}return au(e,a,t,l),nu(e)}function un(e,t,l){if(t=t.updateQueue,t!==null&&(t=t.shared,(l&4194048)!==0)){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,os(e,l)}}function rc(e,t){var l=e.updateQueue,a=e.alternate;if(a!==null&&(a=a.updateQueue,l===a)){var n=null,u=null;if(l=l.firstBaseUpdate,l!==null){do{var c={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};u===null?n=u=c:u=u.next=c,l=l.next}while(l!==null);u===null?n=u=t:u=u.next=t}else n=u=t;l={baseState:a.baseState,firstBaseUpdate:n,lastBaseUpdate:u,shared:a.shared,callbacks:a.callbacks},e.updateQueue=l;return}e=l.lastBaseUpdate,e===null?l.firstBaseUpdate=t:e.next=t,l.lastBaseUpdate=t}var oc=!1;function cn(){if(oc){var e=ya;if(e!==null)throw e}}function fn(e,t,l,a){oc=!1;var n=e.updateQueue;dl=!1;var u=n.firstBaseUpdate,c=n.lastBaseUpdate,r=n.shared.pending;if(r!==null){n.shared.pending=null;var v=r,x=v.next;v.next=null,c===null?u=x:c.next=x,c=v;var O=e.alternate;O!==null&&(O=O.updateQueue,r=O.lastBaseUpdate,r!==c&&(r===null?O.firstBaseUpdate=x:r.next=x,O.lastBaseUpdate=v))}if(u!==null){var C=n.baseState;c=0,O=x=v=null,r=u;do{var z=r.lane&-536870913,R=z!==r.lane;if(R?(ce&z)===z:(a&z)===z){z!==0&&z===va&&(oc=!0),O!==null&&(O=O.next={lane:0,tag:r.tag,payload:r.payload,callback:null,next:null});e:{var w=e,k=r;z=t;var Se=l;switch(k.tag){case 1:if(w=k.payload,typeof w=="function"){C=w.call(Se,C,z);break e}C=w;break e;case 3:w.flags=w.flags&-65537|128;case 0:if(w=k.payload,z=typeof w=="function"?w.call(Se,C,z):w,z==null)break e;C=A({},C,z);break e;case 2:dl=!0}}z=r.callback,z!==null&&(e.flags|=64,R&&(e.flags|=8192),R=n.callbacks,R===null?n.callbacks=[z]:R.push(z))}else R={lane:z,tag:r.tag,payload:r.payload,callback:r.callback,next:null},O===null?(x=O=R,v=C):O=O.next=R,c|=z;if(r=r.next,r===null){if(r=n.shared.pending,r===null)break;R=r,r=R.next,R.next=null,n.lastBaseUpdate=R,n.shared.pending=null}}while(!0);O===null&&(v=C),n.baseState=v,n.firstBaseUpdate=x,n.lastBaseUpdate=O,u===null&&(n.shared.lanes=0),Sl|=c,e.lanes=c,e.memoizedState=C}}function _r(e,t){if(typeof e!="function")throw Error(f(191,e));e.call(t)}function Er(e,t){var l=e.callbacks;if(l!==null)for(e.callbacks=null,e=0;eu?u:8;var c=D.T,r={};D.T=r,jc(e,!1,t,l);try{var v=n(),x=D.S;if(x!==null&&x(r,v),v!==null&&typeof v=="object"&&typeof v.then=="function"){var O=nv(v,a);on(e,t,O,mt(e))}else on(e,t,a,mt(e))}catch(C){on(e,t,{then:function(){},status:"rejected",reason:C},mt())}finally{L.p=u,c!==null&&r.types!==null&&(c.types=r.types),D.T=c}}function rv(){}function Rc(e,t,l,a){if(e.tag!==5)throw Error(f(476));var n=eo(e).queue;Pr(e,n,t,I,l===null?rv:function(){return to(e),l(a)})}function eo(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:I,baseState:I,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:$t,lastRenderedState:I},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:$t,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function to(e){var t=eo(e);t.next===null&&(t=e.alternate.memoizedState),on(e,t.next.queue,{},mt())}function Oc(){return Ze(Rn)}function lo(){return Me().memoizedState}function ao(){return Me().memoizedState}function ov(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=mt();e=ml(l);var a=hl(t,e,l);a!==null&&(at(a,t,l),un(a,t,l)),t={cache:nc()},e.payload=t;return}t=t.return}}function dv(e,t,l){var a=mt();l={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},Tu(e)?uo(t,l):(l=Ji(e,t,l,a),l!==null&&(at(l,e,a),io(l,t,a)))}function no(e,t,l){var a=mt();on(e,t,l,a)}function on(e,t,l,a){var n={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(Tu(e))uo(t,n);else{var u=e.alternate;if(e.lanes===0&&(u===null||u.lanes===0)&&(u=t.lastRenderedReducer,u!==null))try{var c=t.lastRenderedState,r=u(c,l);if(n.hasEagerState=!0,n.eagerState=r,ct(r,c))return au(e,t,n,0),Ee===null&&lu(),!1}catch{}if(l=Ji(e,t,n,a),l!==null)return at(l,e,a),io(l,t,a),!0}return!1}function jc(e,t,l,a){if(a={lane:2,revertLane:sf(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},Tu(e)){if(t)throw Error(f(479))}else t=Ji(e,l,a,2),t!==null&&at(t,e,2)}function Tu(e){var t=e.alternate;return e===te||t!==null&&t===te}function uo(e,t){ba=yu=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function io(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,os(e,l)}}var dn={readContext:Ze,use:Su,useCallback:Re,useContext:Re,useEffect:Re,useImperativeHandle:Re,useLayoutEffect:Re,useInsertionEffect:Re,useMemo:Re,useReducer:Re,useRef:Re,useState:Re,useDebugValue:Re,useDeferredValue:Re,useTransition:Re,useSyncExternalStore:Re,useId:Re,useHostTransitionStatus:Re,useFormState:Re,useActionState:Re,useOptimistic:Re,useMemoCache:Re,useCacheRefresh:Re};dn.useEffectEvent=Re;var co={readContext:Ze,use:Su,useCallback:function(e,t){return ke().memoizedState=[e,t===void 0?null:t],e},useContext:Ze,useEffect:Vr,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,_u(4194308,4,$r.bind(null,t,e),l)},useLayoutEffect:function(e,t){return _u(4194308,4,e,t)},useInsertionEffect:function(e,t){_u(4,2,e,t)},useMemo:function(e,t){var l=ke();t=t===void 0?null:t;var a=e();if(wl){ul(!0);try{e()}finally{ul(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=ke();if(l!==void 0){var n=l(t);if(wl){ul(!0);try{l(t)}finally{ul(!1)}}}else n=t;return a.memoizedState=a.baseState=n,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:n},a.queue=e,e=e.dispatch=dv.bind(null,te,e),[a.memoizedState,e]},useRef:function(e){var t=ke();return e={current:e},t.memoizedState=e},useState:function(e){e=Tc(e);var t=e.queue,l=no.bind(null,te,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:zc,useDeferredValue:function(e,t){var l=ke();return Nc(l,e,t)},useTransition:function(){var e=Tc(!1);return e=Pr.bind(null,te,e.queue,!0,!1),ke().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=te,n=ke();if(se){if(l===void 0)throw Error(f(407));l=l()}else{if(l=t(),Ee===null)throw Error(f(349));(ce&127)!==0||Rr(a,t,l)}n.memoizedState=l;var u={value:l,getSnapshot:t};return n.queue=u,Vr(jr.bind(null,a,u,e),[e]),a.flags|=2048,Ea(9,{destroy:void 0},Or.bind(null,a,u,l,t),null),l},useId:function(){var e=ke(),t=Ee.identifierPrefix;if(se){var l=Bt,a=Ht;l=(a&~(1<<32-it(a)-1)).toString(32)+l,t="_"+t+"R_"+l,l=pu++,0<\/script>",u=u.removeChild(u.firstChild);break;case"select":u=typeof a.is=="string"?c.createElement("select",{is:a.is}):c.createElement("select"),a.multiple?u.multiple=!0:a.size&&(u.size=a.size);break;default:u=typeof a.is=="string"?c.createElement(n,{is:a.is}):c.createElement(n)}}u[Xe]=t,u[Fe]=a;e:for(c=t.child;c!==null;){if(c.tag===5||c.tag===6)u.appendChild(c.stateNode);else if(c.tag!==4&&c.tag!==27&&c.child!==null){c.child.return=c,c=c.child;continue}if(c===t)break e;for(;c.sibling===null;){if(c.return===null||c.return===t)break e;c=c.return}c.sibling.return=c.return,c=c.sibling}t.stateNode=u;e:switch(we(u,n,a),n){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break e;case"img":a=!0;break e;default:a=!1}a&&kt(t)}}return xe(t),Vc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,l),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==a&&kt(t);else{if(typeof a!="string"&&t.stateNode===null)throw Error(f(166));if(e=ne.current,ma(t)){if(e=t.stateNode,l=t.memoizedProps,a=null,n=Qe,n!==null)switch(n.tag){case 27:case 5:a=n.memoizedProps}e[Xe]=t,e=!!(e.nodeValue===l||a!==null&&a.suppressHydrationWarning===!0||Nd(e.nodeValue,l)),e||rl(t,!0)}else e=Zu(e).createTextNode(a),e[Xe]=t,t.stateNode=e}return xe(t),null;case 31:if(l=t.memoizedState,e===null||e.memoizedState!==null){if(a=ma(t),l!==null){if(e===null){if(!a)throw Error(f(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(f(557));e[Xe]=t}else Ll(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;xe(t),e=!1}else l=ec(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),e=!0;if(!e)return t.flags&256?(rt(t),t):(rt(t),null);if((t.flags&128)!==0)throw Error(f(558))}return xe(t),null;case 13:if(a=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(n=ma(t),a!==null&&a.dehydrated!==null){if(e===null){if(!n)throw Error(f(318));if(n=t.memoizedState,n=n!==null?n.dehydrated:null,!n)throw Error(f(317));n[Xe]=t}else Ll(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;xe(t),n=!1}else n=ec(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),n=!0;if(!n)return t.flags&256?(rt(t),t):(rt(t),null)}return rt(t),(t.flags&128)!==0?(t.lanes=l,t):(l=a!==null,e=e!==null&&e.memoizedState!==null,l&&(a=t.child,n=null,a.alternate!==null&&a.alternate.memoizedState!==null&&a.alternate.memoizedState.cachePool!==null&&(n=a.alternate.memoizedState.cachePool.pool),u=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(u=a.memoizedState.cachePool.pool),u!==n&&(a.flags|=2048)),l!==e&&l&&(t.child.flags|=8192),Ru(t,t.updateQueue),xe(t),null);case 4:return je(),e===null&&mf(t.stateNode.containerInfo),xe(t),null;case 10:return Kt(t.type),xe(t),null;case 19:if(U(De),a=t.memoizedState,a===null)return xe(t),null;if(n=(t.flags&128)!==0,u=a.rendering,u===null)if(n)hn(a,!1);else{if(Oe!==0||e!==null&&(e.flags&128)!==0)for(e=t.child;e!==null;){if(u=vu(e),u!==null){for(t.flags|=128,hn(a,!1),e=u.updateQueue,t.updateQueue=e,Ru(t,e),t.subtreeFlags=0,e=l,l=t.child;l!==null;)nr(l,e),l=l.sibling;return Y(De,De.current&1|2),se&&Vt(t,a.treeForkCount),t.child}e=e.sibling}a.tail!==null&&nt()>Cu&&(t.flags|=128,n=!0,hn(a,!1),t.lanes=4194304)}else{if(!n)if(e=vu(u),e!==null){if(t.flags|=128,n=!0,e=e.updateQueue,t.updateQueue=e,Ru(t,e),hn(a,!0),a.tail===null&&a.tailMode==="hidden"&&!u.alternate&&!se)return xe(t),null}else 2*nt()-a.renderingStartTime>Cu&&l!==536870912&&(t.flags|=128,n=!0,hn(a,!1),t.lanes=4194304);a.isBackwards?(u.sibling=t.child,t.child=u):(e=a.last,e!==null?e.sibling=u:t.child=u,a.last=u)}return a.tail!==null?(e=a.tail,a.rendering=e,a.tail=e.sibling,a.renderingStartTime=nt(),e.sibling=null,l=De.current,Y(De,n?l&1|2:l&1),se&&Vt(t,a.treeForkCount),e):(xe(t),null);case 22:case 23:return rt(t),mc(),a=t.memoizedState!==null,e!==null?e.memoizedState!==null!==a&&(t.flags|=8192):a&&(t.flags|=8192),a?(l&536870912)!==0&&(t.flags&128)===0&&(xe(t),t.subtreeFlags&6&&(t.flags|=8192)):xe(t),l=t.updateQueue,l!==null&&Ru(t,l.retryQueue),l=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(l=e.memoizedState.cachePool.pool),a=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(a=t.memoizedState.cachePool.pool),a!==l&&(t.flags|=2048),e!==null&&U(Xl),null;case 24:return l=null,e!==null&&(l=e.memoizedState.cache),t.memoizedState.cache!==l&&(t.flags|=2048),Kt(Ue),xe(t),null;case 25:return null;case 30:return null}throw Error(f(156,t.tag))}function pv(e,t){switch(Ii(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Kt(Ue),je(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return Yn(t),null;case 31:if(t.memoizedState!==null){if(rt(t),t.alternate===null)throw Error(f(340));Ll()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(rt(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(f(340));Ll()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return U(De),null;case 4:return je(),null;case 10:return Kt(t.type),null;case 22:case 23:return rt(t),mc(),e!==null&&U(Xl),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Kt(Ue),null;case 25:return null;default:return null}}function Mo(e,t){switch(Ii(t),t.tag){case 3:Kt(Ue),je();break;case 26:case 27:case 5:Yn(t);break;case 4:je();break;case 31:t.memoizedState!==null&&rt(t);break;case 13:rt(t);break;case 19:U(De);break;case 10:Kt(t.type);break;case 22:case 23:rt(t),mc(),e!==null&&U(Xl);break;case 24:Kt(Ue)}}function vn(e,t){try{var l=t.updateQueue,a=l!==null?l.lastEffect:null;if(a!==null){var n=a.next;l=n;do{if((l.tag&e)===e){a=void 0;var u=l.create,c=l.inst;a=u(),c.destroy=a}l=l.next}while(l!==n)}}catch(r){ve(t,t.return,r)}}function pl(e,t,l){try{var a=t.updateQueue,n=a!==null?a.lastEffect:null;if(n!==null){var u=n.next;a=u;do{if((a.tag&e)===e){var c=a.inst,r=c.destroy;if(r!==void 0){c.destroy=void 0,n=t;var v=l,x=r;try{x()}catch(O){ve(n,v,O)}}}a=a.next}while(a!==u)}}catch(O){ve(t,t.return,O)}}function Co(e){var t=e.updateQueue;if(t!==null){var l=e.stateNode;try{Er(t,l)}catch(a){ve(e,e.return,a)}}}function Uo(e,t,l){l.props=Kl(e.type,e.memoizedProps),l.state=e.memoizedState;try{l.componentWillUnmount()}catch(a){ve(e,t,a)}}function yn(e,t){try{var l=e.ref;if(l!==null){switch(e.tag){case 26:case 27:case 5:var a=e.stateNode;break;case 30:a=e.stateNode;break;default:a=e.stateNode}typeof l=="function"?e.refCleanup=l(a):l.current=a}}catch(n){ve(e,t,n)}}function qt(e,t){var l=e.ref,a=e.refCleanup;if(l!==null)if(typeof a=="function")try{a()}catch(n){ve(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(n){ve(e,t,n)}else l.current=null}function Ho(e){var t=e.type,l=e.memoizedProps,a=e.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":l.autoFocus&&a.focus();break e;case"img":l.src?a.src=l.src:l.srcSet&&(a.srcset=l.srcSet)}}catch(n){ve(e,e.return,n)}}function wc(e,t,l){try{var a=e.stateNode;Yv(a,e.type,l,t),a[Fe]=t}catch(n){ve(e,e.return,n)}}function Bo(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&xl(e.type)||e.tag===4}function Kc(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Bo(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&xl(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Jc(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(e,t):(t=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,t.appendChild(e),l=l._reactRootContainer,l!=null||t.onclick!==null||(t.onclick=Xt));else if(a!==4&&(a===27&&xl(e.type)&&(l=e.stateNode,t=null),e=e.child,e!==null))for(Jc(e,t,l),e=e.sibling;e!==null;)Jc(e,t,l),e=e.sibling}function Ou(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?l.insertBefore(e,t):l.appendChild(e);else if(a!==4&&(a===27&&xl(e.type)&&(l=e.stateNode),e=e.child,e!==null))for(Ou(e,t,l),e=e.sibling;e!==null;)Ou(e,t,l),e=e.sibling}function qo(e){var t=e.stateNode,l=e.memoizedProps;try{for(var a=e.type,n=t.attributes;n.length;)t.removeAttributeNode(n[0]);we(t,a,l),t[Xe]=e,t[Fe]=l}catch(u){ve(e,e.return,u)}}var Ft=!1,qe=!1,$c=!1,Lo=typeof WeakSet=="function"?WeakSet:Set,Ge=null;function gv(e,t){if(e=e.containerInfo,yf=ku,e=Ws(e),Xi(e)){if("selectionStart"in e)var l={start:e.selectionStart,end:e.selectionEnd};else e:{l=(l=e.ownerDocument)&&l.defaultView||window;var a=l.getSelection&&l.getSelection();if(a&&a.rangeCount!==0){l=a.anchorNode;var n=a.anchorOffset,u=a.focusNode;a=a.focusOffset;try{l.nodeType,u.nodeType}catch{l=null;break e}var c=0,r=-1,v=-1,x=0,O=0,C=e,z=null;t:for(;;){for(var R;C!==l||n!==0&&C.nodeType!==3||(r=c+n),C!==u||a!==0&&C.nodeType!==3||(v=c+a),C.nodeType===3&&(c+=C.nodeValue.length),(R=C.firstChild)!==null;)z=C,C=R;for(;;){if(C===e)break t;if(z===l&&++x===n&&(r=c),z===u&&++O===a&&(v=c),(R=C.nextSibling)!==null)break;C=z,z=C.parentNode}C=R}l=r===-1||v===-1?null:{start:r,end:v}}else l=null}l=l||{start:0,end:0}}else l=null;for(pf={focusedElem:e,selectionRange:l},ku=!1,Ge=t;Ge!==null;)if(t=Ge,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,Ge=e;else for(;Ge!==null;){switch(t=Ge,u=t.alternate,e=t.flags,t.tag){case 0:if((e&4)!==0&&(e=t.updateQueue,e=e!==null?e.events:null,e!==null))for(l=0;l title"))),we(u,a,l),u[Xe]=e,Ye(u),a=u;break e;case"link":var c=Vd("link","href",n).get(a+(l.href||""));if(c){for(var r=0;rSe&&(c=Se,Se=k,k=c);var _=Js(r,k),p=Js(r,Se);if(_&&p&&(R.rangeCount!==1||R.anchorNode!==_.node||R.anchorOffset!==_.offset||R.focusNode!==p.node||R.focusOffset!==p.offset)){var T=C.createRange();T.setStart(_.node,_.offset),R.removeAllRanges(),k>Se?(R.addRange(T),R.extend(p.node,p.offset)):(T.setEnd(p.node,p.offset),R.addRange(T))}}}}for(C=[],R=r;R=R.parentNode;)R.nodeType===1&&C.push({element:R,left:R.scrollLeft,top:R.scrollTop});for(typeof r.focus=="function"&&r.focus(),r=0;rl?32:l,D.T=null,l=tf,tf=null;var u=_l,c=ll;if(Le=0,Na=_l=null,ll=0,(de&6)!==0)throw Error(f(331));var r=de;if(de|=4,Wo(u.current),Ko(u,u.current,c,l),de=r,En(0,!1),ut&&typeof ut.onPostCommitFiberRoot=="function")try{ut.onPostCommitFiberRoot(Ya,u)}catch{}return!0}finally{L.p=n,D.T=a,md(e,t)}}function vd(e,t,l){t=bt(l,t),t=Uc(e.stateNode,t,2),e=hl(e,t,2),e!==null&&(Xa(e,2),Lt(e))}function ve(e,t,l){if(e.tag===3)vd(e,e,l);else for(;t!==null;){if(t.tag===3){vd(t,e,l);break}else if(t.tag===1){var a=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(bl===null||!bl.has(a))){e=bt(l,e),l=yo(2),a=hl(t,l,2),a!==null&&(po(l,a,t,e),Xa(a,2),Lt(a));break}}t=t.return}}function uf(e,t,l){var a=e.pingCache;if(a===null){a=e.pingCache=new _v;var n=new Set;a.set(t,n)}else n=a.get(t),n===void 0&&(n=new Set,a.set(t,n));n.has(l)||(Fc=!0,n.add(l),e=zv.bind(null,e,t,l),t.then(e,e))}function zv(e,t,l){var a=e.pingCache;a!==null&&a.delete(t),e.pingedLanes|=e.suspendedLanes&l,e.warmLanes&=~l,Ee===e&&(ce&l)===l&&(Oe===4||Oe===3&&(ce&62914560)===ce&&300>nt()-Mu?(de&2)===0&&Ra(e,0):Ic|=l,za===ce&&(za=0)),Lt(e)}function yd(e,t){t===0&&(t=ss()),e=Bl(e,t),e!==null&&(Xa(e,t),Lt(e))}function Nv(e){var t=e.memoizedState,l=0;t!==null&&(l=t.retryLane),yd(e,l)}function Rv(e,t){var l=0;switch(e.tag){case 31:case 13:var a=e.stateNode,n=e.memoizedState;n!==null&&(l=n.retryLane);break;case 19:a=e.stateNode;break;case 22:a=e.stateNode._retryCache;break;default:throw Error(f(314))}a!==null&&a.delete(t),yd(e,l)}function Ov(e,t){return gi(e,t)}var Yu=null,ja=null,cf=!1,Gu=!1,ff=!1,Tl=0;function Lt(e){e!==ja&&e.next===null&&(ja===null?Yu=ja=e:ja=ja.next=e),Gu=!0,cf||(cf=!0,Dv())}function En(e,t){if(!ff&&Gu){ff=!0;do for(var l=!1,a=Yu;a!==null;){if(e!==0){var n=a.pendingLanes;if(n===0)var u=0;else{var c=a.suspendedLanes,r=a.pingedLanes;u=(1<<31-it(42|e)+1)-1,u&=n&~(c&~r),u=u&201326741?u&201326741|1:u?u|2:0}u!==0&&(l=!0,bd(a,u))}else u=ce,u=Vn(a,a===Ee?u:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(u&3)===0||Ga(a,u)||(l=!0,bd(a,u));a=a.next}while(l);ff=!1}}function jv(){pd()}function pd(){Gu=cf=!1;var e=0;Tl!==0&&Xv()&&(e=Tl);for(var t=nt(),l=null,a=Yu;a!==null;){var n=a.next,u=gd(a,t);u===0?(a.next=null,l===null?Yu=n:l.next=n,n===null&&(ja=l)):(l=a,(e!==0||(u&3)!==0)&&(Gu=!0)),a=n}Le!==0&&Le!==5||En(e),Tl!==0&&(Tl=0)}function gd(e,t){for(var l=e.suspendedLanes,a=e.pingedLanes,n=e.expirationTimes,u=e.pendingLanes&-62914561;0r)break;var O=v.transferSize,C=v.initiatorType;O&&Rd(C)&&(v=v.responseEnd,c+=O*(v"u"?null:document;function Gd(e,t,l){var a=Da;if(a&&typeof t=="string"&&t){var n=gt(t);n='link[rel="'+e+'"][href="'+n+'"]',typeof l=="string"&&(n+='[crossorigin="'+l+'"]'),Yd.has(n)||(Yd.add(n),e={rel:e,crossOrigin:l,href:t},a.querySelector(n)===null&&(t=a.createElement("link"),we(t,"link",e),Ye(t),a.head.appendChild(t)))}}function kv(e){al.D(e),Gd("dns-prefetch",e,null)}function Fv(e,t){al.C(e,t),Gd("preconnect",e,t)}function Iv(e,t,l){al.L(e,t,l);var a=Da;if(a&&e&&t){var n='link[rel="preload"][as="'+gt(t)+'"]';t==="image"&&l&&l.imageSrcSet?(n+='[imagesrcset="'+gt(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(n+='[imagesizes="'+gt(l.imageSizes)+'"]')):n+='[href="'+gt(e)+'"]';var u=n;switch(t){case"style":u=Ma(e);break;case"script":u=Ca(e)}zt.has(u)||(e=A({rel:"preload",href:t==="image"&&l&&l.imageSrcSet?void 0:e,as:t},l),zt.set(u,e),a.querySelector(n)!==null||t==="style"&&a.querySelector(zn(u))||t==="script"&&a.querySelector(Nn(u))||(t=a.createElement("link"),we(t,"link",e),Ye(t),a.head.appendChild(t)))}}function Pv(e,t){al.m(e,t);var l=Da;if(l&&e){var a=t&&typeof t.as=="string"?t.as:"script",n='link[rel="modulepreload"][as="'+gt(a)+'"][href="'+gt(e)+'"]',u=n;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":u=Ca(e)}if(!zt.has(u)&&(e=A({rel:"modulepreload",href:e},t),zt.set(u,e),l.querySelector(n)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(Nn(u)))return}a=l.createElement("link"),we(a,"link",e),Ye(a),l.head.appendChild(a)}}}function ey(e,t,l){al.S(e,t,l);var a=Da;if(a&&e){var n=ea(a).hoistableStyles,u=Ma(e);t=t||"default";var c=n.get(u);if(!c){var r={loading:0,preload:null};if(c=a.querySelector(zn(u)))r.loading=5;else{e=A({rel:"stylesheet",href:e,"data-precedence":t},l),(l=zt.get(u))&&xf(e,l);var v=c=a.createElement("link");Ye(v),we(v,"link",e),v._p=new Promise(function(x,O){v.onload=x,v.onerror=O}),v.addEventListener("load",function(){r.loading|=1}),v.addEventListener("error",function(){r.loading|=2}),r.loading|=4,wu(c,t,a)}c={type:"stylesheet",instance:c,count:1,state:r},n.set(u,c)}}}function ty(e,t){al.X(e,t);var l=Da;if(l&&e){var a=ea(l).hoistableScripts,n=Ca(e),u=a.get(n);u||(u=l.querySelector(Nn(n)),u||(e=A({src:e,async:!0},t),(t=zt.get(n))&&Af(e,t),u=l.createElement("script"),Ye(u),we(u,"link",e),l.head.appendChild(u)),u={type:"script",instance:u,count:1,state:null},a.set(n,u))}}function ly(e,t){al.M(e,t);var l=Da;if(l&&e){var a=ea(l).hoistableScripts,n=Ca(e),u=a.get(n);u||(u=l.querySelector(Nn(n)),u||(e=A({src:e,async:!0,type:"module"},t),(t=zt.get(n))&&Af(e,t),u=l.createElement("script"),Ye(u),we(u,"link",e),l.head.appendChild(u)),u={type:"script",instance:u,count:1,state:null},a.set(n,u))}}function Xd(e,t,l,a){var n=(n=ne.current)?Vu(n):null;if(!n)throw Error(f(446));switch(e){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(t=Ma(l.href),l=ea(n).hoistableStyles,a=l.get(t),a||(a={type:"style",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){e=Ma(l.href);var u=ea(n).hoistableStyles,c=u.get(e);if(c||(n=n.ownerDocument||n,c={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},u.set(e,c),(u=n.querySelector(zn(e)))&&!u._p&&(c.instance=u,c.state.loading=5),zt.has(e)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},zt.set(e,l),u||ay(n,e,l,c.state))),t&&a===null)throw Error(f(528,""));return c}if(t&&a!==null)throw Error(f(529,""));return null;case"script":return t=l.async,l=l.src,typeof l=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=Ca(l),l=ea(n).hoistableScripts,a=l.get(t),a||(a={type:"script",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(f(444,e))}}function Ma(e){return'href="'+gt(e)+'"'}function zn(e){return'link[rel="stylesheet"]['+e+"]"}function Qd(e){return A({},e,{"data-precedence":e.precedence,precedence:null})}function ay(e,t,l,a){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?a.loading=1:(t=e.createElement("link"),a.preload=t,t.addEventListener("load",function(){return a.loading|=1}),t.addEventListener("error",function(){return a.loading|=2}),we(t,"link",l),Ye(t),e.head.appendChild(t))}function Ca(e){return'[src="'+gt(e)+'"]'}function Nn(e){return"script[async]"+e}function Zd(e,t,l){if(t.count++,t.instance===null)switch(t.type){case"style":var a=e.querySelector('style[data-href~="'+gt(l.href)+'"]');if(a)return t.instance=a,Ye(a),a;var n=A({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(e.ownerDocument||e).createElement("style"),Ye(a),we(a,"style",n),wu(a,l.precedence,e),t.instance=a;case"stylesheet":n=Ma(l.href);var u=e.querySelector(zn(n));if(u)return t.state.loading|=4,t.instance=u,Ye(u),u;a=Qd(l),(n=zt.get(n))&&xf(a,n),u=(e.ownerDocument||e).createElement("link"),Ye(u);var c=u;return c._p=new Promise(function(r,v){c.onload=r,c.onerror=v}),we(u,"link",a),t.state.loading|=4,wu(u,l.precedence,e),t.instance=u;case"script":return u=Ca(l.src),(n=e.querySelector(Nn(u)))?(t.instance=n,Ye(n),n):(a=l,(n=zt.get(u))&&(a=A({},l),Af(a,n)),e=e.ownerDocument||e,n=e.createElement("script"),Ye(n),we(n,"link",a),e.head.appendChild(n),t.instance=n);case"void":return null;default:throw Error(f(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(a=t.instance,t.state.loading|=4,wu(a,l.precedence,e));return t.instance}function wu(e,t,l){for(var a=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),n=a.length?a[a.length-1]:null,u=n,c=0;c title"):null)}function ny(e,t,l){if(l===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;return t.rel==="stylesheet"?(e=t.disabled,typeof t.precedence=="string"&&e==null):!0;case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Kd(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function uy(e,t,l,a){if(l.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var n=Ma(a.href),u=t.querySelector(zn(n));if(u){t=u._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=Ju.bind(e),t.then(e,e)),l.state.loading|=4,l.instance=u,Ye(u);return}u=t.ownerDocument||t,a=Qd(a),(n=zt.get(n))&&xf(a,n),u=u.createElement("link"),Ye(u);var c=u;c._p=new Promise(function(r,v){c.onload=r,c.onerror=v}),we(u,"link",a),l.instance=u}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(l,t),(t=l.state.preload)&&(l.state.loading&3)===0&&(e.count++,l=Ju.bind(e),t.addEventListener("load",l),t.addEventListener("error",l))}}var zf=0;function iy(e,t){return e.stylesheets&&e.count===0&&Wu(e,e.stylesheets),0zf?50:800)+t);return e.unsuspend=l,function(){e.unsuspend=null,clearTimeout(a),clearTimeout(n)}}:null}function Ju(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Wu(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var $u=null;function Wu(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,$u=new Map,t.forEach(cy,e),$u=null,Ju.call(e))}function cy(e,t){if(!(t.state.loading&4)){var l=$u.get(e);if(l)var a=l.get(null);else{l=new Map,$u.set(e,l);for(var n=e.querySelectorAll("link[data-precedence],style[data-precedence]"),u=0;u"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(i)}catch(s){console.error(s)}}return i(),Hf.exports=Ty(),Hf.exports}var Ay=xy();var ym="popstate";function pm(i){return typeof i=="object"&&i!=null&&"pathname"in i&&"search"in i&&"hash"in i&&"state"in i&&"key"in i}function zy(i={}){function s(d,h){let{pathname:b="/",search:N="",hash:S=""}=kl(d.location.hash.substring(1));return!b.startsWith("/")&&!b.startsWith(".")&&(b="/"+b),Kf("",{pathname:b,search:N,hash:S},h.state&&h.state.usr||null,h.state&&h.state.key||"default")}function o(d,h){let b=d.document.querySelector("base"),N="";if(b&&b.getAttribute("href")){let S=d.location.href,y=S.indexOf("#");N=y===-1?S:S.slice(0,y)}return N+"#"+(typeof h=="string"?h:Hn(h))}function f(d,h){Nt(d.pathname.charAt(0)==="/",`relative pathnames are not supported in hash history.push(${JSON.stringify(h)})`)}return Ry(s,o,f,i)}function ze(i,s){if(i===!1||i===null||typeof i>"u")throw new Error(s)}function Nt(i,s){if(!i){typeof console<"u"&&console.warn(s);try{throw new Error(s)}catch{}}}function Ny(){return Math.random().toString(36).substring(2,10)}function gm(i,s){return{usr:i.state,key:i.key,idx:s,masked:i.unstable_mask?{pathname:i.pathname,search:i.search,hash:i.hash}:void 0}}function Kf(i,s,o=null,f,d){return{pathname:typeof i=="string"?i:i.pathname,search:"",hash:"",...typeof s=="string"?kl(s):s,state:o,key:s&&s.key||f||Ny(),unstable_mask:d}}function Hn({pathname:i="/",search:s="",hash:o=""}){return s&&s!=="?"&&(i+=s.charAt(0)==="?"?s:"?"+s),o&&o!=="#"&&(i+=o.charAt(0)==="#"?o:"#"+o),i}function kl(i){let s={};if(i){let o=i.indexOf("#");o>=0&&(s.hash=i.substring(o),i=i.substring(0,o));let f=i.indexOf("?");f>=0&&(s.search=i.substring(f),i=i.substring(0,f)),i&&(s.pathname=i)}return s}function Ry(i,s,o,f={}){let{window:d=document.defaultView,v5Compat:h=!1}=f,b=d.history,N="POP",S=null,y=j();y==null&&(y=0,b.replaceState({...b.state,idx:y},""));function j(){return(b.state||{idx:null}).idx}function A(){N="POP";let B=j(),Q=B==null?null:B-y;y=B,S&&S({action:N,location:G.location,delta:Q})}function q(B,Q){N="PUSH";let V=pm(B)?B:Kf(G.location,B,Q);o&&o(V,B),y=j()+1;let $=gm(V,y),F=G.createHref(V.unstable_mask||V);try{b.pushState($,"",F)}catch(le){if(le instanceof DOMException&&le.name==="DataCloneError")throw le;d.location.assign(F)}h&&S&&S({action:N,location:G.location,delta:1})}function H(B,Q){N="REPLACE";let V=pm(B)?B:Kf(G.location,B,Q);o&&o(V,B),y=j();let $=gm(V,y),F=G.createHref(V.unstable_mask||V);b.replaceState($,"",F),h&&S&&S({action:N,location:G.location,delta:0})}function Z(B){return Oy(B)}let G={get action(){return N},get location(){return i(d,b)},listen(B){if(S)throw new Error("A history only accepts one active listener");return d.addEventListener(ym,A),S=B,()=>{d.removeEventListener(ym,A),S=null}},createHref(B){return s(d,B)},createURL:Z,encodeLocation(B){let Q=Z(B);return{pathname:Q.pathname,search:Q.search,hash:Q.hash}},push:q,replace:H,go(B){return b.go(B)}};return G}function Oy(i,s=!1){let o="http://localhost";typeof window<"u"&&(o=window.location.origin!=="null"?window.location.origin:window.location.href),ze(o,"No window.location.(origin|href) available to create URL");let f=typeof i=="string"?i:Hn(i);return f=f.replace(/ $/,"%20"),!s&&f.startsWith("//")&&(f=o+f),new URL(f,o)}function xm(i,s,o="/"){return jy(i,s,o,!1)}function jy(i,s,o,f){let d=typeof s=="string"?kl(s):s,h=nl(d.pathname||"/",o);if(h==null)return null;let b=Am(i);Dy(b);let N=null;for(let S=0;N==null&&S{let j={relativePath:y===void 0?b.path||"":y,caseSensitive:b.caseSensitive===!0,childrenIndex:N,route:b};if(j.relativePath.startsWith("/")){if(!j.relativePath.startsWith(f)&&S)return;ze(j.relativePath.startsWith(f),`Absolute route path "${j.relativePath}" nested under path "${f}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),j.relativePath=j.relativePath.slice(f.length)}let A=Dt([f,j.relativePath]),q=o.concat(j);b.children&&b.children.length>0&&(ze(b.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${A}".`),Am(b.children,s,q,A,S)),!(b.path==null&&!b.index)&&s.push({path:A,score:Ly(A,b.index),routesMeta:q})};return i.forEach((b,N)=>{if(b.path===""||!b.path?.includes("?"))h(b,N);else for(let S of zm(b.path))h(b,N,!0,S)}),s}function zm(i){let s=i.split("/");if(s.length===0)return[];let[o,...f]=s,d=o.endsWith("?"),h=o.replace(/\?$/,"");if(f.length===0)return d?[h,""]:[h];let b=zm(f.join("/")),N=[];return N.push(...b.map(S=>S===""?h:[h,S].join("/"))),d&&N.push(...b),N.map(S=>i.startsWith("/")&&S===""?"/":S)}function Dy(i){i.sort((s,o)=>s.score!==o.score?o.score-s.score:Yy(s.routesMeta.map(f=>f.childrenIndex),o.routesMeta.map(f=>f.childrenIndex)))}var My=/^:[\w-]+$/,Cy=3,Uy=2,Hy=1,By=10,qy=-2,Sm=i=>i==="*";function Ly(i,s){let o=i.split("/"),f=o.length;return o.some(Sm)&&(f+=qy),s&&(f+=Uy),o.filter(d=>!Sm(d)).reduce((d,h)=>d+(My.test(h)?Cy:h===""?Hy:By),f)}function Yy(i,s){return i.length===s.length&&i.slice(0,-1).every((f,d)=>f===s[d])?i[i.length-1]-s[s.length-1]:0}function Gy(i,s,o=!1){let{routesMeta:f}=i,d={},h="/",b=[];for(let N=0;N{if(j==="*"){let Z=N[q]||"";b=h.slice(0,h.length-Z.length).replace(/(.)\/+$/,"$1")}const H=N[q];return A&&!H?y[j]=void 0:y[j]=(H||"").replace(/%2F/g,"/"),y},{}),pathname:h,pathnameBase:b,pattern:i}}function Xy(i,s=!1,o=!0){Nt(i==="*"||!i.endsWith("*")||i.endsWith("/*"),`Route path "${i}" will be treated as if it were "${i.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${i.replace(/\*$/,"/*")}".`);let f=[],d="^"+i.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(b,N,S,y,j)=>{if(f.push({paramName:N,isOptional:S!=null}),S){let A=j.charAt(y+b.length);return A&&A!=="/"?"/([^\\/]*)":"(?:/([^\\/]*))?"}return"/([^\\/]+)"}).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return i.endsWith("*")?(f.push({paramName:"*"}),d+=i==="*"||i==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):o?d+="\\/*$":i!==""&&i!=="/"&&(d+="(?:(?=\\/|$))"),[new RegExp(d,s?void 0:"i"),f]}function Qy(i){try{return i.split("/").map(s=>decodeURIComponent(s).replace(/\//g,"%2F")).join("/")}catch(s){return Nt(!1,`The URL path "${i}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${s}).`),i}}function nl(i,s){if(s==="/")return i;if(!i.toLowerCase().startsWith(s.toLowerCase()))return null;let o=s.endsWith("/")?s.length-1:s.length,f=i.charAt(o);return f&&f!=="/"?null:i.slice(o)||"/"}var Zy=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;function Vy(i,s="/"){let{pathname:o,search:f="",hash:d=""}=typeof i=="string"?kl(i):i,h;return o?(o=Nm(o),o.startsWith("/")?h=bm(o.substring(1),"/"):h=bm(o,s)):h=s,{pathname:h,search:Jy(f),hash:$y(d)}}function bm(i,s){let o=si(s).split("/");return i.split("/").forEach(d=>{d===".."?o.length>1&&o.pop():d!=="."&&o.push(d)}),o.length>1?o.join("/"):"/"}function Yf(i,s,o,f){return`Cannot include a '${i}' character in a manually specified \`to.${s}\` field [${JSON.stringify(f)}]. Please separate it out to the \`to.${o}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function wy(i){return i.filter((s,o)=>o===0||s.route.path&&s.route.path.length>0)}function Wf(i){let s=wy(i);return s.map((o,f)=>f===s.length-1?o.pathname:o.pathnameBase)}function oi(i,s,o,f=!1){let d;typeof i=="string"?d=kl(i):(d={...i},ze(!d.pathname||!d.pathname.includes("?"),Yf("?","pathname","search",d)),ze(!d.pathname||!d.pathname.includes("#"),Yf("#","pathname","hash",d)),ze(!d.search||!d.search.includes("#"),Yf("#","search","hash",d)));let h=i===""||d.pathname==="",b=h?"/":d.pathname,N;if(b==null)N=o;else{let A=s.length-1;if(!f&&b.startsWith("..")){let q=b.split("/");for(;q[0]==="..";)q.shift(),A-=1;d.pathname=q.join("/")}N=A>=0?s[A]:"/"}let S=Vy(d,N),y=b&&b!=="/"&&b.endsWith("/"),j=(h||b===".")&&o.endsWith("/");return!S.pathname.endsWith("/")&&(y||j)&&(S.pathname+="/"),S}var Nm=i=>i.replace(/\/\/+/g,"/"),Dt=i=>Nm(i.join("/")),si=i=>i.replace(/\/+$/,""),Ky=i=>si(i).replace(/^\/*/,"/"),Jy=i=>!i||i==="?"?"":i.startsWith("?")?i:"?"+i,$y=i=>!i||i==="#"?"":i.startsWith("#")?i:"#"+i,Wy=class{constructor(i,s,o,f=!1){this.status=i,this.statusText=s||"",this.internal=f,o instanceof Error?(this.data=o.toString(),this.error=o):this.data=o}};function ky(i){return i!=null&&typeof i.status=="number"&&typeof i.statusText=="string"&&typeof i.internal=="boolean"&&"data"in i}function Fy(i){let s=i.map(o=>o.route.path).filter(Boolean);return Dt(s)||"/"}var Rm=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function Om(i,s){let o=i;if(typeof o!="string"||!Zy.test(o))return{absoluteURL:void 0,isExternal:!1,to:o};let f=o,d=!1;if(Rm)try{let h=new URL(window.location.href),b=o.startsWith("//")?new URL(h.protocol+o):new URL(o),N=nl(b.pathname,s);b.origin===h.origin&&N!=null?o=N+b.search+b.hash:d=!0}catch{Nt(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:f,isExternal:d,to:o}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var jm=["POST","PUT","PATCH","DELETE"];new Set(jm);var Iy=["GET",...jm];new Set(Iy);var Ba=E.createContext(null);Ba.displayName="DataRouter";var di=E.createContext(null);di.displayName="DataRouterState";var Dm=E.createContext(!1);function Py(){return E.useContext(Dm)}var Mm=E.createContext({isTransitioning:!1});Mm.displayName="ViewTransition";var e0=E.createContext(new Map);e0.displayName="Fetchers";var t0=E.createContext(null);t0.displayName="Await";var ht=E.createContext(null);ht.displayName="Navigation";var qn=E.createContext(null);qn.displayName="Location";var Mt=E.createContext({outlet:null,matches:[],isDataRoute:!1});Mt.displayName="Route";var kf=E.createContext(null);kf.displayName="RouteError";var Cm="REACT_ROUTER_ERROR",l0="REDIRECT",a0="ROUTE_ERROR_RESPONSE";function n0(i){if(i.startsWith(`${Cm}:${l0}:{`))try{let s=JSON.parse(i.slice(28));if(typeof s=="object"&&s&&typeof s.status=="number"&&typeof s.statusText=="string"&&typeof s.location=="string"&&typeof s.reloadDocument=="boolean"&&typeof s.replace=="boolean")return s}catch{}}function u0(i){if(i.startsWith(`${Cm}:${a0}:{`))try{let s=JSON.parse(i.slice(40));if(typeof s=="object"&&s&&typeof s.status=="number"&&typeof s.statusText=="string")return new Wy(s.status,s.statusText,s.data)}catch{}}function i0(i,{relative:s}={}){ze(qa(),"useHref() may be used only in the context of a component.");let{basename:o,navigator:f}=E.useContext(ht),{hash:d,pathname:h,search:b}=Ln(i,{relative:s}),N=h;return o!=="/"&&(N=h==="/"?o:Dt([o,h])),f.createHref({pathname:N,search:b,hash:d})}function qa(){return E.useContext(qn)!=null}function Yt(){return ze(qa(),"useLocation() may be used only in the context of a component."),E.useContext(qn).location}var Um="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function Hm(i){E.useContext(ht).static||E.useLayoutEffect(i)}function Bm(){let{isDataRoute:i}=E.useContext(Mt);return i?_0():c0()}function c0(){ze(qa(),"useNavigate() may be used only in the context of a component.");let i=E.useContext(Ba),{basename:s,navigator:o}=E.useContext(ht),{matches:f}=E.useContext(Mt),{pathname:d}=Yt(),h=JSON.stringify(Wf(f)),b=E.useRef(!1);return Hm(()=>{b.current=!0}),E.useCallback((S,y={})=>{if(Nt(b.current,Um),!b.current)return;if(typeof S=="number"){o.go(S);return}let j=oi(S,JSON.parse(h),d,y.relative==="path");i==null&&s!=="/"&&(j.pathname=j.pathname==="/"?s:Dt([s,j.pathname])),(y.replace?o.replace:o.push)(j,y.state,y)},[s,o,h,d,i])}var f0=E.createContext(null);function s0(i){let s=E.useContext(Mt).outlet;return E.useMemo(()=>s&&E.createElement(f0.Provider,{value:i},s),[s,i])}function Ln(i,{relative:s}={}){let{matches:o}=E.useContext(Mt),{pathname:f}=Yt(),d=JSON.stringify(Wf(o));return E.useMemo(()=>oi(i,JSON.parse(d),f,s==="path"),[i,d,f,s])}function r0(i,s){return qm(i,s)}function qm(i,s,o){ze(qa(),"useRoutes() may be used only in the context of a component.");let{navigator:f}=E.useContext(ht),{matches:d}=E.useContext(Mt),h=d[d.length-1],b=h?h.params:{},N=h?h.pathname:"/",S=h?h.pathnameBase:"/",y=h&&h.route;{let B=y&&y.path||"";Ym(N,!y||B.endsWith("*")||B.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${N}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. +`+a.stack}}var gi=Object.prototype.hasOwnProperty,pi=i.unstable_scheduleCallback,Si=i.unstable_cancelCallback,$m=i.unstable_shouldYield,Wm=i.unstable_requestPaint,nt=i.unstable_now,km=i.unstable_getCurrentPriorityLevel,is=i.unstable_ImmediatePriority,cs=i.unstable_UserBlockingPriority,Gn=i.unstable_NormalPriority,Fm=i.unstable_LowPriority,fs=i.unstable_IdlePriority,Im=i.log,Pm=i.unstable_setDisableYieldValue,Ga=null,ut=null;function ul(e){if(typeof Im=="function"&&Pm(e),ut&&typeof ut.setStrictMode=="function")try{ut.setStrictMode(Ga,e)}catch{}}var it=Math.clz32?Math.clz32:lh,eh=Math.log,th=Math.LN2;function lh(e){return e>>>=0,e===0?32:31-(eh(e)/th|0)|0}var Xn=256,Qn=262144,Zn=4194304;function Cl(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Vn(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var n=0,u=e.suspendedLanes,c=e.pingedLanes;e=e.warmLanes;var r=a&134217727;return r!==0?(a=r&~u,a!==0?n=Cl(a):(c&=r,c!==0?n=Cl(c):l||(l=r&~e,l!==0&&(n=Cl(l))))):(r=a&~u,r!==0?n=Cl(r):c!==0?n=Cl(c):l||(l=a&~e,l!==0&&(n=Cl(l)))),n===0?0:t!==0&&t!==n&&(t&u)===0&&(u=n&-n,l=t&-t,u>=l||u===32&&(l&4194048)!==0)?t:n}function Xa(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function ah(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function ss(){var e=Zn;return Zn<<=1,(Zn&62914560)===0&&(Zn=4194304),e}function bi(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function Qa(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function nh(e,t,l,a,n,u){var c=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var r=e.entanglements,y=e.expirationTimes,x=e.hiddenUpdates;for(l=c&~l;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var rh=/[\n"\\]/g;function pt(e){return e.replace(rh,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function zi(e,t,l,a,n,u,c,r){e.name="",c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"?e.type=c:e.removeAttribute("type"),t!=null?c==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+gt(t)):e.value!==""+gt(t)&&(e.value=""+gt(t)):c!=="submit"&&c!=="reset"||e.removeAttribute("value"),t!=null?Ni(e,c,gt(t)):l!=null?Ni(e,c,gt(l)):a!=null&&e.removeAttribute("value"),n==null&&u!=null&&(e.defaultChecked=!!u),n!=null&&(e.checked=n&&typeof n!="function"&&typeof n!="symbol"),r!=null&&typeof r!="function"&&typeof r!="symbol"&&typeof r!="boolean"?e.name=""+gt(r):e.removeAttribute("name")}function Es(e,t,l,a,n,u,c,r){if(u!=null&&typeof u!="function"&&typeof u!="symbol"&&typeof u!="boolean"&&(e.type=u),t!=null||l!=null){if(!(u!=="submit"&&u!=="reset"||t!=null)){Ai(e);return}l=l!=null?""+gt(l):"",t=t!=null?""+gt(t):l,r||t===e.value||(e.value=t),e.defaultValue=t}a=a??n,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=r?e.checked:!!a,e.defaultChecked=!!a,c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"&&(e.name=c),Ai(e)}function Ni(e,t,l){t==="number"&&Jn(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function la(e,t,l,a){if(e=e.options,t){t={};for(var n=0;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Di=!1;if(Qt)try{var Ka={};Object.defineProperty(Ka,"passive",{get:function(){Di=!0}}),window.addEventListener("test",Ka,Ka),window.removeEventListener("test",Ka,Ka)}catch{Di=!1}var cl=null,Mi=null,Wn=null;function Os(){if(Wn)return Wn;var e,t=Mi,l=t.length,a,n="value"in cl?cl.value:cl.textContent,u=n.length;for(e=0;e=Wa),Hs=" ",Bs=!1;function qs(e,t){switch(e){case"keyup":return Lh.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Ls(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var ia=!1;function Gh(e,t){switch(e){case"compositionend":return Ls(t);case"keypress":return t.which!==32?null:(Bs=!0,Hs);case"textInput":return e=t.data,e===Hs&&Bs?null:e;default:return null}}function Xh(e,t){if(ia)return e==="compositionend"||!Li&&qs(e,t)?(e=Os(),Wn=Mi=cl=null,ia=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=a}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Ks(l)}}function $s(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?$s(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Ws(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Jn(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=Jn(e.document)}return t}function Xi(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var Wh=Qt&&"documentMode"in document&&11>=document.documentMode,ca=null,Qi=null,Pa=null,Zi=!1;function ks(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;Zi||ca==null||ca!==Jn(a)||(a=ca,"selectionStart"in a&&Xi(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),Pa&&Ia(Pa,a)||(Pa=a,a=Qu(Qi,"onSelect"),0>=c,n-=c,Ht=1<<32-it(t)+n|l<ae?(fe=$,$=null):fe=$.sibling;var oe=z(_,$,T[ae],D);if(oe===null){$===null&&($=fe);break}e&&$&&oe.alternate===null&&t(_,$),g=u(oe,g,ae),re===null?k=oe:re.sibling=oe,re=oe,$=fe}if(ae===T.length)return l(_,$),se&&Vt(_,ae),k;if($===null){for(;aeae?(fe=$,$=null):fe=$.sibling;var Ol=z(_,$,oe.value,D);if(Ol===null){$===null&&($=fe);break}e&&$&&Ol.alternate===null&&t(_,$),g=u(Ol,g,ae),re===null?k=Ol:re.sibling=Ol,re=Ol,$=fe}if(oe.done)return l(_,$),se&&Vt(_,ae),k;if($===null){for(;!oe.done;ae++,oe=T.next())oe=M(_,oe.value,D),oe!==null&&(g=u(oe,g,ae),re===null?k=oe:re.sibling=oe,re=oe);return se&&Vt(_,ae),k}for($=a($);!oe.done;ae++,oe=T.next())oe=R($,_,ae,oe.value,D),oe!==null&&(e&&oe.alternate!==null&&$.delete(oe.key===null?ae:oe.key),g=u(oe,g,ae),re===null?k=oe:re.sibling=oe,re=oe);return e&&$.forEach(function(vy){return t(_,vy)}),se&&Vt(_,ae),k}function Se(_,g,T,D){if(typeof T=="object"&&T!==null&&T.type===X&&T.key===null&&(T=T.props.children),typeof T=="object"&&T!==null){switch(T.$$typeof){case H:e:{for(var k=T.key;g!==null;){if(g.key===k){if(k=T.type,k===X){if(g.tag===7){l(_,g.sibling),D=n(g,T.props.children),D.return=_,_=D;break e}}else if(g.elementType===k||typeof k=="object"&&k!==null&&k.$$typeof===Ne&&Ql(k)===g.type){l(_,g.sibling),D=n(g,T.props),un(D,T),D.return=_,_=D;break e}l(_,g);break}else t(_,g);g=g.sibling}T.type===X?(D=ql(T.props.children,_.mode,D,T.key),D.return=_,_=D):(D=uu(T.type,T.key,T.props,null,_.mode,D),un(D,T),D.return=_,_=D)}return c(_);case V:e:{for(k=T.key;g!==null;){if(g.key===k)if(g.tag===4&&g.stateNode.containerInfo===T.containerInfo&&g.stateNode.implementation===T.implementation){l(_,g.sibling),D=n(g,T.children||[]),D.return=_,_=D;break e}else{l(_,g);break}else t(_,g);g=g.sibling}D=ki(T,_.mode,D),D.return=_,_=D}return c(_);case Ne:return T=Ql(T),Se(_,g,T,D)}if(Me(T))return K(_,g,T,D);if(Je(T)){if(k=Je(T),typeof k!="function")throw Error(f(150));return T=k.call(T),F(_,g,T,D)}if(typeof T.then=="function")return Se(_,g,du(T),D);if(T.$$typeof===W)return Se(_,g,fu(_,T),D);mu(_,T)}return typeof T=="string"&&T!==""||typeof T=="number"||typeof T=="bigint"?(T=""+T,g!==null&&g.tag===6?(l(_,g.sibling),D=n(g,T),D.return=_,_=D):(l(_,g),D=Wi(T,_.mode,D),D.return=_,_=D),c(_)):l(_,g)}return function(_,g,T,D){try{nn=0;var k=Se(_,g,T,D);return pa=null,k}catch($){if($===ga||$===ru)throw $;var re=ft(29,$,null,_.mode);return re.lanes=D,re.return=_,re}}}var Vl=Sr(!0),br=Sr(!1),dl=!1;function fc(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function sc(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function ml(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function hl(e,t,l){var a=e.updateQueue;if(a===null)return null;if(a=a.shared,(de&2)!==0){var n=a.pending;return n===null?t.next=t:(t.next=n.next,n.next=t),a.pending=t,t=nu(e),ar(e,null,l),t}return au(e,a,t,l),nu(e)}function cn(e,t,l){if(t=t.updateQueue,t!==null&&(t=t.shared,(l&4194048)!==0)){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,os(e,l)}}function rc(e,t){var l=e.updateQueue,a=e.alternate;if(a!==null&&(a=a.updateQueue,l===a)){var n=null,u=null;if(l=l.firstBaseUpdate,l!==null){do{var c={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};u===null?n=u=c:u=u.next=c,l=l.next}while(l!==null);u===null?n=u=t:u=u.next=t}else n=u=t;l={baseState:a.baseState,firstBaseUpdate:n,lastBaseUpdate:u,shared:a.shared,callbacks:a.callbacks},e.updateQueue=l;return}e=l.lastBaseUpdate,e===null?l.firstBaseUpdate=t:e.next=t,l.lastBaseUpdate=t}var oc=!1;function fn(){if(oc){var e=ya;if(e!==null)throw e}}function sn(e,t,l,a){oc=!1;var n=e.updateQueue;dl=!1;var u=n.firstBaseUpdate,c=n.lastBaseUpdate,r=n.shared.pending;if(r!==null){n.shared.pending=null;var y=r,x=y.next;y.next=null,c===null?u=x:c.next=x,c=y;var O=e.alternate;O!==null&&(O=O.updateQueue,r=O.lastBaseUpdate,r!==c&&(r===null?O.firstBaseUpdate=x:r.next=x,O.lastBaseUpdate=y))}if(u!==null){var M=n.baseState;c=0,O=x=y=null,r=u;do{var z=r.lane&-536870913,R=z!==r.lane;if(R?(ce&z)===z:(a&z)===z){z!==0&&z===va&&(oc=!0),O!==null&&(O=O.next={lane:0,tag:r.tag,payload:r.payload,callback:null,next:null});e:{var K=e,F=r;z=t;var Se=l;switch(F.tag){case 1:if(K=F.payload,typeof K=="function"){M=K.call(Se,M,z);break e}M=K;break e;case 3:K.flags=K.flags&-65537|128;case 0:if(K=F.payload,z=typeof K=="function"?K.call(Se,M,z):K,z==null)break e;M=A({},M,z);break e;case 2:dl=!0}}z=r.callback,z!==null&&(e.flags|=64,R&&(e.flags|=8192),R=n.callbacks,R===null?n.callbacks=[z]:R.push(z))}else R={lane:z,tag:r.tag,payload:r.payload,callback:r.callback,next:null},O===null?(x=O=R,y=M):O=O.next=R,c|=z;if(r=r.next,r===null){if(r=n.shared.pending,r===null)break;R=r,r=R.next,R.next=null,n.lastBaseUpdate=R,n.shared.pending=null}}while(!0);O===null&&(y=M),n.baseState=y,n.firstBaseUpdate=x,n.lastBaseUpdate=O,u===null&&(n.shared.lanes=0),Sl|=c,e.lanes=c,e.memoizedState=M}}function _r(e,t){if(typeof e!="function")throw Error(f(191,e));e.call(t)}function Er(e,t){var l=e.callbacks;if(l!==null)for(e.callbacks=null,e=0;eu?u:8;var c=C.T,r={};C.T=r,jc(e,!1,t,l);try{var y=n(),x=C.S;if(x!==null&&x(r,y),y!==null&&typeof y=="object"&&typeof y.then=="function"){var O=nv(y,a);dn(e,t,O,mt(e))}else dn(e,t,a,mt(e))}catch(M){dn(e,t,{then:function(){},status:"rejected",reason:M},mt())}finally{Y.p=u,c!==null&&r.types!==null&&(c.types=r.types),C.T=c}}function rv(){}function Rc(e,t,l,a){if(e.tag!==5)throw Error(f(476));var n=eo(e).queue;Pr(e,n,t,I,l===null?rv:function(){return to(e),l(a)})}function eo(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:I,baseState:I,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:$t,lastRenderedState:I},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:$t,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function to(e){var t=eo(e);t.next===null&&(t=e.alternate.memoizedState),dn(e,t.next.queue,{},mt())}function Oc(){return Ze(On)}function lo(){return De().memoizedState}function ao(){return De().memoizedState}function ov(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=mt();e=ml(l);var a=hl(t,e,l);a!==null&&(at(a,t,l),cn(a,t,l)),t={cache:nc()},e.payload=t;return}t=t.return}}function dv(e,t,l){var a=mt();l={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},Tu(e)?uo(t,l):(l=Ji(e,t,l,a),l!==null&&(at(l,e,a),io(l,t,a)))}function no(e,t,l){var a=mt();dn(e,t,l,a)}function dn(e,t,l,a){var n={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(Tu(e))uo(t,n);else{var u=e.alternate;if(e.lanes===0&&(u===null||u.lanes===0)&&(u=t.lastRenderedReducer,u!==null))try{var c=t.lastRenderedState,r=u(c,l);if(n.hasEagerState=!0,n.eagerState=r,ct(r,c))return au(e,t,n,0),Ee===null&&lu(),!1}catch{}if(l=Ji(e,t,n,a),l!==null)return at(l,e,a),io(l,t,a),!0}return!1}function jc(e,t,l,a){if(a={lane:2,revertLane:sf(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},Tu(e)){if(t)throw Error(f(479))}else t=Ji(e,l,a,2),t!==null&&at(t,e,2)}function Tu(e){var t=e.alternate;return e===te||t!==null&&t===te}function uo(e,t){ba=yu=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function io(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,os(e,l)}}var mn={readContext:Ze,use:Su,useCallback:Re,useContext:Re,useEffect:Re,useImperativeHandle:Re,useLayoutEffect:Re,useInsertionEffect:Re,useMemo:Re,useReducer:Re,useRef:Re,useState:Re,useDebugValue:Re,useDeferredValue:Re,useTransition:Re,useSyncExternalStore:Re,useId:Re,useHostTransitionStatus:Re,useFormState:Re,useActionState:Re,useOptimistic:Re,useMemoCache:Re,useCacheRefresh:Re};mn.useEffectEvent=Re;var co={readContext:Ze,use:Su,useCallback:function(e,t){return ke().memoizedState=[e,t===void 0?null:t],e},useContext:Ze,useEffect:Vr,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,_u(4194308,4,$r.bind(null,t,e),l)},useLayoutEffect:function(e,t){return _u(4194308,4,e,t)},useInsertionEffect:function(e,t){_u(4,2,e,t)},useMemo:function(e,t){var l=ke();t=t===void 0?null:t;var a=e();if(wl){ul(!0);try{e()}finally{ul(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=ke();if(l!==void 0){var n=l(t);if(wl){ul(!0);try{l(t)}finally{ul(!1)}}}else n=t;return a.memoizedState=a.baseState=n,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:n},a.queue=e,e=e.dispatch=dv.bind(null,te,e),[a.memoizedState,e]},useRef:function(e){var t=ke();return e={current:e},t.memoizedState=e},useState:function(e){e=Tc(e);var t=e.queue,l=no.bind(null,te,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:zc,useDeferredValue:function(e,t){var l=ke();return Nc(l,e,t)},useTransition:function(){var e=Tc(!1);return e=Pr.bind(null,te,e.queue,!0,!1),ke().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=te,n=ke();if(se){if(l===void 0)throw Error(f(407));l=l()}else{if(l=t(),Ee===null)throw Error(f(349));(ce&127)!==0||Rr(a,t,l)}n.memoizedState=l;var u={value:l,getSnapshot:t};return n.queue=u,Vr(jr.bind(null,a,u,e),[e]),a.flags|=2048,Ea(9,{destroy:void 0},Or.bind(null,a,u,l,t),null),l},useId:function(){var e=ke(),t=Ee.identifierPrefix;if(se){var l=Bt,a=Ht;l=(a&~(1<<32-it(a)-1)).toString(32)+l,t="_"+t+"R_"+l,l=gu++,0<\/script>",u=u.removeChild(u.firstChild);break;case"select":u=typeof a.is=="string"?c.createElement("select",{is:a.is}):c.createElement("select"),a.multiple?u.multiple=!0:a.size&&(u.size=a.size);break;default:u=typeof a.is=="string"?c.createElement(n,{is:a.is}):c.createElement(n)}}u[Xe]=t,u[Fe]=a;e:for(c=t.child;c!==null;){if(c.tag===5||c.tag===6)u.appendChild(c.stateNode);else if(c.tag!==4&&c.tag!==27&&c.child!==null){c.child.return=c,c=c.child;continue}if(c===t)break e;for(;c.sibling===null;){if(c.return===null||c.return===t)break e;c=c.return}c.sibling.return=c.return,c=c.sibling}t.stateNode=u;e:switch(we(u,n,a),n){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break e;case"img":a=!0;break e;default:a=!1}a&&kt(t)}}return xe(t),Vc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,l),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==a&&kt(t);else{if(typeof a!="string"&&t.stateNode===null)throw Error(f(166));if(e=ne.current,ma(t)){if(e=t.stateNode,l=t.memoizedProps,a=null,n=Qe,n!==null)switch(n.tag){case 27:case 5:a=n.memoizedProps}e[Xe]=t,e=!!(e.nodeValue===l||a!==null&&a.suppressHydrationWarning===!0||Nd(e.nodeValue,l)),e||rl(t,!0)}else e=Zu(e).createTextNode(a),e[Xe]=t,t.stateNode=e}return xe(t),null;case 31:if(l=t.memoizedState,e===null||e.memoizedState!==null){if(a=ma(t),l!==null){if(e===null){if(!a)throw Error(f(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(f(557));e[Xe]=t}else Ll(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;xe(t),e=!1}else l=ec(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),e=!0;if(!e)return t.flags&256?(rt(t),t):(rt(t),null);if((t.flags&128)!==0)throw Error(f(558))}return xe(t),null;case 13:if(a=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(n=ma(t),a!==null&&a.dehydrated!==null){if(e===null){if(!n)throw Error(f(318));if(n=t.memoizedState,n=n!==null?n.dehydrated:null,!n)throw Error(f(317));n[Xe]=t}else Ll(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;xe(t),n=!1}else n=ec(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),n=!0;if(!n)return t.flags&256?(rt(t),t):(rt(t),null)}return rt(t),(t.flags&128)!==0?(t.lanes=l,t):(l=a!==null,e=e!==null&&e.memoizedState!==null,l&&(a=t.child,n=null,a.alternate!==null&&a.alternate.memoizedState!==null&&a.alternate.memoizedState.cachePool!==null&&(n=a.alternate.memoizedState.cachePool.pool),u=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(u=a.memoizedState.cachePool.pool),u!==n&&(a.flags|=2048)),l!==e&&l&&(t.child.flags|=8192),Ru(t,t.updateQueue),xe(t),null);case 4:return je(),e===null&&mf(t.stateNode.containerInfo),xe(t),null;case 10:return Kt(t.type),xe(t),null;case 19:if(U(Ce),a=t.memoizedState,a===null)return xe(t),null;if(n=(t.flags&128)!==0,u=a.rendering,u===null)if(n)vn(a,!1);else{if(Oe!==0||e!==null&&(e.flags&128)!==0)for(e=t.child;e!==null;){if(u=vu(e),u!==null){for(t.flags|=128,vn(a,!1),e=u.updateQueue,t.updateQueue=e,Ru(t,e),t.subtreeFlags=0,e=l,l=t.child;l!==null;)nr(l,e),l=l.sibling;return G(Ce,Ce.current&1|2),se&&Vt(t,a.treeForkCount),t.child}e=e.sibling}a.tail!==null&&nt()>Mu&&(t.flags|=128,n=!0,vn(a,!1),t.lanes=4194304)}else{if(!n)if(e=vu(u),e!==null){if(t.flags|=128,n=!0,e=e.updateQueue,t.updateQueue=e,Ru(t,e),vn(a,!0),a.tail===null&&a.tailMode==="hidden"&&!u.alternate&&!se)return xe(t),null}else 2*nt()-a.renderingStartTime>Mu&&l!==536870912&&(t.flags|=128,n=!0,vn(a,!1),t.lanes=4194304);a.isBackwards?(u.sibling=t.child,t.child=u):(e=a.last,e!==null?e.sibling=u:t.child=u,a.last=u)}return a.tail!==null?(e=a.tail,a.rendering=e,a.tail=e.sibling,a.renderingStartTime=nt(),e.sibling=null,l=Ce.current,G(Ce,n?l&1|2:l&1),se&&Vt(t,a.treeForkCount),e):(xe(t),null);case 22:case 23:return rt(t),mc(),a=t.memoizedState!==null,e!==null?e.memoizedState!==null!==a&&(t.flags|=8192):a&&(t.flags|=8192),a?(l&536870912)!==0&&(t.flags&128)===0&&(xe(t),t.subtreeFlags&6&&(t.flags|=8192)):xe(t),l=t.updateQueue,l!==null&&Ru(t,l.retryQueue),l=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(l=e.memoizedState.cachePool.pool),a=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(a=t.memoizedState.cachePool.pool),a!==l&&(t.flags|=2048),e!==null&&U(Xl),null;case 24:return l=null,e!==null&&(l=e.memoizedState.cache),t.memoizedState.cache!==l&&(t.flags|=2048),Kt(Ue),xe(t),null;case 25:return null;case 30:return null}throw Error(f(156,t.tag))}function gv(e,t){switch(Ii(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Kt(Ue),je(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return Yn(t),null;case 31:if(t.memoizedState!==null){if(rt(t),t.alternate===null)throw Error(f(340));Ll()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(rt(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(f(340));Ll()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return U(Ce),null;case 4:return je(),null;case 10:return Kt(t.type),null;case 22:case 23:return rt(t),mc(),e!==null&&U(Xl),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Kt(Ue),null;case 25:return null;default:return null}}function Do(e,t){switch(Ii(t),t.tag){case 3:Kt(Ue),je();break;case 26:case 27:case 5:Yn(t);break;case 4:je();break;case 31:t.memoizedState!==null&&rt(t);break;case 13:rt(t);break;case 19:U(Ce);break;case 10:Kt(t.type);break;case 22:case 23:rt(t),mc(),e!==null&&U(Xl);break;case 24:Kt(Ue)}}function yn(e,t){try{var l=t.updateQueue,a=l!==null?l.lastEffect:null;if(a!==null){var n=a.next;l=n;do{if((l.tag&e)===e){a=void 0;var u=l.create,c=l.inst;a=u(),c.destroy=a}l=l.next}while(l!==n)}}catch(r){ve(t,t.return,r)}}function gl(e,t,l){try{var a=t.updateQueue,n=a!==null?a.lastEffect:null;if(n!==null){var u=n.next;a=u;do{if((a.tag&e)===e){var c=a.inst,r=c.destroy;if(r!==void 0){c.destroy=void 0,n=t;var y=l,x=r;try{x()}catch(O){ve(n,y,O)}}}a=a.next}while(a!==u)}}catch(O){ve(t,t.return,O)}}function Mo(e){var t=e.updateQueue;if(t!==null){var l=e.stateNode;try{Er(t,l)}catch(a){ve(e,e.return,a)}}}function Uo(e,t,l){l.props=Kl(e.type,e.memoizedProps),l.state=e.memoizedState;try{l.componentWillUnmount()}catch(a){ve(e,t,a)}}function gn(e,t){try{var l=e.ref;if(l!==null){switch(e.tag){case 26:case 27:case 5:var a=e.stateNode;break;case 30:a=e.stateNode;break;default:a=e.stateNode}typeof l=="function"?e.refCleanup=l(a):l.current=a}}catch(n){ve(e,t,n)}}function qt(e,t){var l=e.ref,a=e.refCleanup;if(l!==null)if(typeof a=="function")try{a()}catch(n){ve(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(n){ve(e,t,n)}else l.current=null}function Ho(e){var t=e.type,l=e.memoizedProps,a=e.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":l.autoFocus&&a.focus();break e;case"img":l.src?a.src=l.src:l.srcSet&&(a.srcset=l.srcSet)}}catch(n){ve(e,e.return,n)}}function wc(e,t,l){try{var a=e.stateNode;Yv(a,e.type,l,t),a[Fe]=t}catch(n){ve(e,e.return,n)}}function Bo(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&xl(e.type)||e.tag===4}function Kc(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Bo(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&xl(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Jc(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(e,t):(t=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,t.appendChild(e),l=l._reactRootContainer,l!=null||t.onclick!==null||(t.onclick=Xt));else if(a!==4&&(a===27&&xl(e.type)&&(l=e.stateNode,t=null),e=e.child,e!==null))for(Jc(e,t,l),e=e.sibling;e!==null;)Jc(e,t,l),e=e.sibling}function Ou(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?l.insertBefore(e,t):l.appendChild(e);else if(a!==4&&(a===27&&xl(e.type)&&(l=e.stateNode),e=e.child,e!==null))for(Ou(e,t,l),e=e.sibling;e!==null;)Ou(e,t,l),e=e.sibling}function qo(e){var t=e.stateNode,l=e.memoizedProps;try{for(var a=e.type,n=t.attributes;n.length;)t.removeAttributeNode(n[0]);we(t,a,l),t[Xe]=e,t[Fe]=l}catch(u){ve(e,e.return,u)}}var Ft=!1,qe=!1,$c=!1,Lo=typeof WeakSet=="function"?WeakSet:Set,Ge=null;function pv(e,t){if(e=e.containerInfo,yf=ku,e=Ws(e),Xi(e)){if("selectionStart"in e)var l={start:e.selectionStart,end:e.selectionEnd};else e:{l=(l=e.ownerDocument)&&l.defaultView||window;var a=l.getSelection&&l.getSelection();if(a&&a.rangeCount!==0){l=a.anchorNode;var n=a.anchorOffset,u=a.focusNode;a=a.focusOffset;try{l.nodeType,u.nodeType}catch{l=null;break e}var c=0,r=-1,y=-1,x=0,O=0,M=e,z=null;t:for(;;){for(var R;M!==l||n!==0&&M.nodeType!==3||(r=c+n),M!==u||a!==0&&M.nodeType!==3||(y=c+a),M.nodeType===3&&(c+=M.nodeValue.length),(R=M.firstChild)!==null;)z=M,M=R;for(;;){if(M===e)break t;if(z===l&&++x===n&&(r=c),z===u&&++O===a&&(y=c),(R=M.nextSibling)!==null)break;M=z,z=M.parentNode}M=R}l=r===-1||y===-1?null:{start:r,end:y}}else l=null}l=l||{start:0,end:0}}else l=null;for(gf={focusedElem:e,selectionRange:l},ku=!1,Ge=t;Ge!==null;)if(t=Ge,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,Ge=e;else for(;Ge!==null;){switch(t=Ge,u=t.alternate,e=t.flags,t.tag){case 0:if((e&4)!==0&&(e=t.updateQueue,e=e!==null?e.events:null,e!==null))for(l=0;l title"))),we(u,a,l),u[Xe]=e,Ye(u),a=u;break e;case"link":var c=Vd("link","href",n).get(a+(l.href||""));if(c){for(var r=0;rSe&&(c=Se,Se=F,F=c);var _=Js(r,F),g=Js(r,Se);if(_&&g&&(R.rangeCount!==1||R.anchorNode!==_.node||R.anchorOffset!==_.offset||R.focusNode!==g.node||R.focusOffset!==g.offset)){var T=M.createRange();T.setStart(_.node,_.offset),R.removeAllRanges(),F>Se?(R.addRange(T),R.extend(g.node,g.offset)):(T.setEnd(g.node,g.offset),R.addRange(T))}}}}for(M=[],R=r;R=R.parentNode;)R.nodeType===1&&M.push({element:R,left:R.scrollLeft,top:R.scrollTop});for(typeof r.focus=="function"&&r.focus(),r=0;rl?32:l,C.T=null,l=tf,tf=null;var u=_l,c=ll;if(Le=0,Na=_l=null,ll=0,(de&6)!==0)throw Error(f(331));var r=de;if(de|=4,Wo(u.current),Ko(u,u.current,c,l),de=r,Tn(0,!1),ut&&typeof ut.onPostCommitFiberRoot=="function")try{ut.onPostCommitFiberRoot(Ga,u)}catch{}return!0}finally{Y.p=n,C.T=a,md(e,t)}}function vd(e,t,l){t=bt(l,t),t=Uc(e.stateNode,t,2),e=hl(e,t,2),e!==null&&(Qa(e,2),Lt(e))}function ve(e,t,l){if(e.tag===3)vd(e,e,l);else for(;t!==null;){if(t.tag===3){vd(t,e,l);break}else if(t.tag===1){var a=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(bl===null||!bl.has(a))){e=bt(l,e),l=yo(2),a=hl(t,l,2),a!==null&&(go(l,a,t,e),Qa(a,2),Lt(a));break}}t=t.return}}function uf(e,t,l){var a=e.pingCache;if(a===null){a=e.pingCache=new _v;var n=new Set;a.set(t,n)}else n=a.get(t),n===void 0&&(n=new Set,a.set(t,n));n.has(l)||(Fc=!0,n.add(l),e=zv.bind(null,e,t,l),t.then(e,e))}function zv(e,t,l){var a=e.pingCache;a!==null&&a.delete(t),e.pingedLanes|=e.suspendedLanes&l,e.warmLanes&=~l,Ee===e&&(ce&l)===l&&(Oe===4||Oe===3&&(ce&62914560)===ce&&300>nt()-Du?(de&2)===0&&Ra(e,0):Ic|=l,za===ce&&(za=0)),Lt(e)}function yd(e,t){t===0&&(t=ss()),e=Bl(e,t),e!==null&&(Qa(e,t),Lt(e))}function Nv(e){var t=e.memoizedState,l=0;t!==null&&(l=t.retryLane),yd(e,l)}function Rv(e,t){var l=0;switch(e.tag){case 31:case 13:var a=e.stateNode,n=e.memoizedState;n!==null&&(l=n.retryLane);break;case 19:a=e.stateNode;break;case 22:a=e.stateNode._retryCache;break;default:throw Error(f(314))}a!==null&&a.delete(t),yd(e,l)}function Ov(e,t){return pi(e,t)}var Yu=null,ja=null,cf=!1,Gu=!1,ff=!1,Tl=0;function Lt(e){e!==ja&&e.next===null&&(ja===null?Yu=ja=e:ja=ja.next=e),Gu=!0,cf||(cf=!0,Cv())}function Tn(e,t){if(!ff&&Gu){ff=!0;do for(var l=!1,a=Yu;a!==null;){if(e!==0){var n=a.pendingLanes;if(n===0)var u=0;else{var c=a.suspendedLanes,r=a.pingedLanes;u=(1<<31-it(42|e)+1)-1,u&=n&~(c&~r),u=u&201326741?u&201326741|1:u?u|2:0}u!==0&&(l=!0,bd(a,u))}else u=ce,u=Vn(a,a===Ee?u:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(u&3)===0||Xa(a,u)||(l=!0,bd(a,u));a=a.next}while(l);ff=!1}}function jv(){gd()}function gd(){Gu=cf=!1;var e=0;Tl!==0&&Xv()&&(e=Tl);for(var t=nt(),l=null,a=Yu;a!==null;){var n=a.next,u=pd(a,t);u===0?(a.next=null,l===null?Yu=n:l.next=n,n===null&&(ja=l)):(l=a,(e!==0||(u&3)!==0)&&(Gu=!0)),a=n}Le!==0&&Le!==5||Tn(e),Tl!==0&&(Tl=0)}function pd(e,t){for(var l=e.suspendedLanes,a=e.pingedLanes,n=e.expirationTimes,u=e.pendingLanes&-62914561;0r)break;var O=y.transferSize,M=y.initiatorType;O&&Rd(M)&&(y=y.responseEnd,c+=O*(y"u"?null:document;function Gd(e,t,l){var a=Ca;if(a&&typeof t=="string"&&t){var n=pt(t);n='link[rel="'+e+'"][href="'+n+'"]',typeof l=="string"&&(n+='[crossorigin="'+l+'"]'),Yd.has(n)||(Yd.add(n),e={rel:e,crossOrigin:l,href:t},a.querySelector(n)===null&&(t=a.createElement("link"),we(t,"link",e),Ye(t),a.head.appendChild(t)))}}function kv(e){al.D(e),Gd("dns-prefetch",e,null)}function Fv(e,t){al.C(e,t),Gd("preconnect",e,t)}function Iv(e,t,l){al.L(e,t,l);var a=Ca;if(a&&e&&t){var n='link[rel="preload"][as="'+pt(t)+'"]';t==="image"&&l&&l.imageSrcSet?(n+='[imagesrcset="'+pt(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(n+='[imagesizes="'+pt(l.imageSizes)+'"]')):n+='[href="'+pt(e)+'"]';var u=n;switch(t){case"style":u=Da(e);break;case"script":u=Ma(e)}zt.has(u)||(e=A({rel:"preload",href:t==="image"&&l&&l.imageSrcSet?void 0:e,as:t},l),zt.set(u,e),a.querySelector(n)!==null||t==="style"&&a.querySelector(Nn(u))||t==="script"&&a.querySelector(Rn(u))||(t=a.createElement("link"),we(t,"link",e),Ye(t),a.head.appendChild(t)))}}function Pv(e,t){al.m(e,t);var l=Ca;if(l&&e){var a=t&&typeof t.as=="string"?t.as:"script",n='link[rel="modulepreload"][as="'+pt(a)+'"][href="'+pt(e)+'"]',u=n;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":u=Ma(e)}if(!zt.has(u)&&(e=A({rel:"modulepreload",href:e},t),zt.set(u,e),l.querySelector(n)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(Rn(u)))return}a=l.createElement("link"),we(a,"link",e),Ye(a),l.head.appendChild(a)}}}function ey(e,t,l){al.S(e,t,l);var a=Ca;if(a&&e){var n=ea(a).hoistableStyles,u=Da(e);t=t||"default";var c=n.get(u);if(!c){var r={loading:0,preload:null};if(c=a.querySelector(Nn(u)))r.loading=5;else{e=A({rel:"stylesheet",href:e,"data-precedence":t},l),(l=zt.get(u))&&xf(e,l);var y=c=a.createElement("link");Ye(y),we(y,"link",e),y._p=new Promise(function(x,O){y.onload=x,y.onerror=O}),y.addEventListener("load",function(){r.loading|=1}),y.addEventListener("error",function(){r.loading|=2}),r.loading|=4,wu(c,t,a)}c={type:"stylesheet",instance:c,count:1,state:r},n.set(u,c)}}}function ty(e,t){al.X(e,t);var l=Ca;if(l&&e){var a=ea(l).hoistableScripts,n=Ma(e),u=a.get(n);u||(u=l.querySelector(Rn(n)),u||(e=A({src:e,async:!0},t),(t=zt.get(n))&&Af(e,t),u=l.createElement("script"),Ye(u),we(u,"link",e),l.head.appendChild(u)),u={type:"script",instance:u,count:1,state:null},a.set(n,u))}}function ly(e,t){al.M(e,t);var l=Ca;if(l&&e){var a=ea(l).hoistableScripts,n=Ma(e),u=a.get(n);u||(u=l.querySelector(Rn(n)),u||(e=A({src:e,async:!0,type:"module"},t),(t=zt.get(n))&&Af(e,t),u=l.createElement("script"),Ye(u),we(u,"link",e),l.head.appendChild(u)),u={type:"script",instance:u,count:1,state:null},a.set(n,u))}}function Xd(e,t,l,a){var n=(n=ne.current)?Vu(n):null;if(!n)throw Error(f(446));switch(e){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(t=Da(l.href),l=ea(n).hoistableStyles,a=l.get(t),a||(a={type:"style",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){e=Da(l.href);var u=ea(n).hoistableStyles,c=u.get(e);if(c||(n=n.ownerDocument||n,c={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},u.set(e,c),(u=n.querySelector(Nn(e)))&&!u._p&&(c.instance=u,c.state.loading=5),zt.has(e)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},zt.set(e,l),u||ay(n,e,l,c.state))),t&&a===null)throw Error(f(528,""));return c}if(t&&a!==null)throw Error(f(529,""));return null;case"script":return t=l.async,l=l.src,typeof l=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=Ma(l),l=ea(n).hoistableScripts,a=l.get(t),a||(a={type:"script",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(f(444,e))}}function Da(e){return'href="'+pt(e)+'"'}function Nn(e){return'link[rel="stylesheet"]['+e+"]"}function Qd(e){return A({},e,{"data-precedence":e.precedence,precedence:null})}function ay(e,t,l,a){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?a.loading=1:(t=e.createElement("link"),a.preload=t,t.addEventListener("load",function(){return a.loading|=1}),t.addEventListener("error",function(){return a.loading|=2}),we(t,"link",l),Ye(t),e.head.appendChild(t))}function Ma(e){return'[src="'+pt(e)+'"]'}function Rn(e){return"script[async]"+e}function Zd(e,t,l){if(t.count++,t.instance===null)switch(t.type){case"style":var a=e.querySelector('style[data-href~="'+pt(l.href)+'"]');if(a)return t.instance=a,Ye(a),a;var n=A({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(e.ownerDocument||e).createElement("style"),Ye(a),we(a,"style",n),wu(a,l.precedence,e),t.instance=a;case"stylesheet":n=Da(l.href);var u=e.querySelector(Nn(n));if(u)return t.state.loading|=4,t.instance=u,Ye(u),u;a=Qd(l),(n=zt.get(n))&&xf(a,n),u=(e.ownerDocument||e).createElement("link"),Ye(u);var c=u;return c._p=new Promise(function(r,y){c.onload=r,c.onerror=y}),we(u,"link",a),t.state.loading|=4,wu(u,l.precedence,e),t.instance=u;case"script":return u=Ma(l.src),(n=e.querySelector(Rn(u)))?(t.instance=n,Ye(n),n):(a=l,(n=zt.get(u))&&(a=A({},l),Af(a,n)),e=e.ownerDocument||e,n=e.createElement("script"),Ye(n),we(n,"link",a),e.head.appendChild(n),t.instance=n);case"void":return null;default:throw Error(f(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(a=t.instance,t.state.loading|=4,wu(a,l.precedence,e));return t.instance}function wu(e,t,l){for(var a=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),n=a.length?a[a.length-1]:null,u=n,c=0;c title"):null)}function ny(e,t,l){if(l===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;return t.rel==="stylesheet"?(e=t.disabled,typeof t.precedence=="string"&&e==null):!0;case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Kd(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function uy(e,t,l,a){if(l.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var n=Da(a.href),u=t.querySelector(Nn(n));if(u){t=u._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=Ju.bind(e),t.then(e,e)),l.state.loading|=4,l.instance=u,Ye(u);return}u=t.ownerDocument||t,a=Qd(a),(n=zt.get(n))&&xf(a,n),u=u.createElement("link"),Ye(u);var c=u;c._p=new Promise(function(r,y){c.onload=r,c.onerror=y}),we(u,"link",a),l.instance=u}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(l,t),(t=l.state.preload)&&(l.state.loading&3)===0&&(e.count++,l=Ju.bind(e),t.addEventListener("load",l),t.addEventListener("error",l))}}var zf=0;function iy(e,t){return e.stylesheets&&e.count===0&&Wu(e,e.stylesheets),0zf?50:800)+t);return e.unsuspend=l,function(){e.unsuspend=null,clearTimeout(a),clearTimeout(n)}}:null}function Ju(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Wu(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var $u=null;function Wu(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,$u=new Map,t.forEach(cy,e),$u=null,Ju.call(e))}function cy(e,t){if(!(t.state.loading&4)){var l=$u.get(e);if(l)var a=l.get(null);else{l=new Map,$u.set(e,l);for(var n=e.querySelectorAll("link[data-precedence],style[data-precedence]"),u=0;u"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(i)}catch(s){console.error(s)}}return i(),Hf.exports=Ty(),Hf.exports}var Ay=xy();var ym="popstate";function gm(i){return typeof i=="object"&&i!=null&&"pathname"in i&&"search"in i&&"hash"in i&&"state"in i&&"key"in i}function zy(i={}){function s(m,h){let{pathname:b="/",search:N="",hash:S=""}=kl(m.location.hash.substring(1));return!b.startsWith("/")&&!b.startsWith(".")&&(b="/"+b),Kf("",{pathname:b,search:N,hash:S},h.state&&h.state.usr||null,h.state&&h.state.key||"default")}function o(m,h){let b=m.document.querySelector("base"),N="";if(b&&b.getAttribute("href")){let S=m.location.href,v=S.indexOf("#");N=v===-1?S:S.slice(0,v)}return N+"#"+(typeof h=="string"?h:Bn(h))}function f(m,h){Nt(m.pathname.charAt(0)==="/",`relative pathnames are not supported in hash history.push(${JSON.stringify(h)})`)}return Ry(s,o,f,i)}function ze(i,s){if(i===!1||i===null||typeof i>"u")throw new Error(s)}function Nt(i,s){if(!i){typeof console<"u"&&console.warn(s);try{throw new Error(s)}catch{}}}function Ny(){return Math.random().toString(36).substring(2,10)}function pm(i,s){return{usr:i.state,key:i.key,idx:s,masked:i.unstable_mask?{pathname:i.pathname,search:i.search,hash:i.hash}:void 0}}function Kf(i,s,o=null,f,m){return{pathname:typeof i=="string"?i:i.pathname,search:"",hash:"",...typeof s=="string"?kl(s):s,state:o,key:s&&s.key||f||Ny(),unstable_mask:m}}function Bn({pathname:i="/",search:s="",hash:o=""}){return s&&s!=="?"&&(i+=s.charAt(0)==="?"?s:"?"+s),o&&o!=="#"&&(i+=o.charAt(0)==="#"?o:"#"+o),i}function kl(i){let s={};if(i){let o=i.indexOf("#");o>=0&&(s.hash=i.substring(o),i=i.substring(0,o));let f=i.indexOf("?");f>=0&&(s.search=i.substring(f),i=i.substring(0,f)),i&&(s.pathname=i)}return s}function Ry(i,s,o,f={}){let{window:m=document.defaultView,v5Compat:h=!1}=f,b=m.history,N="POP",S=null,v=j();v==null&&(v=0,b.replaceState({...b.state,idx:v},""));function j(){return(b.state||{idx:null}).idx}function A(){N="POP";let B=j(),Z=B==null?null:B-v;v=B,S&&S({action:N,location:X.location,delta:Z})}function q(B,Z){N="PUSH";let w=gm(B)?B:Kf(X.location,B,Z);o&&o(w,B),v=j()+1;let W=pm(w,v),Q=X.createHref(w.unstable_mask||w);try{b.pushState(W,"",Q)}catch(le){if(le instanceof DOMException&&le.name==="DataCloneError")throw le;m.location.assign(Q)}h&&S&&S({action:N,location:X.location,delta:1})}function H(B,Z){N="REPLACE";let w=gm(B)?B:Kf(X.location,B,Z);o&&o(w,B),v=j();let W=pm(w,v),Q=X.createHref(w.unstable_mask||w);b.replaceState(W,"",Q),h&&S&&S({action:N,location:X.location,delta:0})}function V(B){return Oy(B)}let X={get action(){return N},get location(){return i(m,b)},listen(B){if(S)throw new Error("A history only accepts one active listener");return m.addEventListener(ym,A),S=B,()=>{m.removeEventListener(ym,A),S=null}},createHref(B){return s(m,B)},createURL:V,encodeLocation(B){let Z=V(B);return{pathname:Z.pathname,search:Z.search,hash:Z.hash}},push:q,replace:H,go(B){return b.go(B)}};return X}function Oy(i,s=!1){let o="http://localhost";typeof window<"u"&&(o=window.location.origin!=="null"?window.location.origin:window.location.href),ze(o,"No window.location.(origin|href) available to create URL");let f=typeof i=="string"?i:Bn(i);return f=f.replace(/ $/,"%20"),!s&&f.startsWith("//")&&(f=o+f),new URL(f,o)}function xm(i,s,o="/"){return jy(i,s,o,!1)}function jy(i,s,o,f){let m=typeof s=="string"?kl(s):s,h=nl(m.pathname||"/",o);if(h==null)return null;let b=Am(i);Cy(b);let N=null;for(let S=0;N==null&&S{let j={relativePath:v===void 0?b.path||"":v,caseSensitive:b.caseSensitive===!0,childrenIndex:N,route:b};if(j.relativePath.startsWith("/")){if(!j.relativePath.startsWith(f)&&S)return;ze(j.relativePath.startsWith(f),`Absolute route path "${j.relativePath}" nested under path "${f}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),j.relativePath=j.relativePath.slice(f.length)}let A=Ct([f,j.relativePath]),q=o.concat(j);b.children&&b.children.length>0&&(ze(b.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${A}".`),Am(b.children,s,q,A,S)),!(b.path==null&&!b.index)&&s.push({path:A,score:Ly(A,b.index),routesMeta:q})};return i.forEach((b,N)=>{if(b.path===""||!b.path?.includes("?"))h(b,N);else for(let S of zm(b.path))h(b,N,!0,S)}),s}function zm(i){let s=i.split("/");if(s.length===0)return[];let[o,...f]=s,m=o.endsWith("?"),h=o.replace(/\?$/,"");if(f.length===0)return m?[h,""]:[h];let b=zm(f.join("/")),N=[];return N.push(...b.map(S=>S===""?h:[h,S].join("/"))),m&&N.push(...b),N.map(S=>i.startsWith("/")&&S===""?"/":S)}function Cy(i){i.sort((s,o)=>s.score!==o.score?o.score-s.score:Yy(s.routesMeta.map(f=>f.childrenIndex),o.routesMeta.map(f=>f.childrenIndex)))}var Dy=/^:[\w-]+$/,My=3,Uy=2,Hy=1,By=10,qy=-2,Sm=i=>i==="*";function Ly(i,s){let o=i.split("/"),f=o.length;return o.some(Sm)&&(f+=qy),s&&(f+=Uy),o.filter(m=>!Sm(m)).reduce((m,h)=>m+(Dy.test(h)?My:h===""?Hy:By),f)}function Yy(i,s){return i.length===s.length&&i.slice(0,-1).every((f,m)=>f===s[m])?i[i.length-1]-s[s.length-1]:0}function Gy(i,s,o=!1){let{routesMeta:f}=i,m={},h="/",b=[];for(let N=0;N{if(j==="*"){let V=N[q]||"";b=h.slice(0,h.length-V.length).replace(/(.)\/+$/,"$1")}const H=N[q];return A&&!H?v[j]=void 0:v[j]=(H||"").replace(/%2F/g,"/"),v},{}),pathname:h,pathnameBase:b,pattern:i}}function Xy(i,s=!1,o=!0){Nt(i==="*"||!i.endsWith("*")||i.endsWith("/*"),`Route path "${i}" will be treated as if it were "${i.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${i.replace(/\*$/,"/*")}".`);let f=[],m="^"+i.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(b,N,S,v,j)=>{if(f.push({paramName:N,isOptional:S!=null}),S){let A=j.charAt(v+b.length);return A&&A!=="/"?"/([^\\/]*)":"(?:/([^\\/]*))?"}return"/([^\\/]+)"}).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return i.endsWith("*")?(f.push({paramName:"*"}),m+=i==="*"||i==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):o?m+="\\/*$":i!==""&&i!=="/"&&(m+="(?:(?=\\/|$))"),[new RegExp(m,s?void 0:"i"),f]}function Qy(i){try{return i.split("/").map(s=>decodeURIComponent(s).replace(/\//g,"%2F")).join("/")}catch(s){return Nt(!1,`The URL path "${i}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${s}).`),i}}function nl(i,s){if(s==="/")return i;if(!i.toLowerCase().startsWith(s.toLowerCase()))return null;let o=s.endsWith("/")?s.length-1:s.length,f=i.charAt(o);return f&&f!=="/"?null:i.slice(o)||"/"}var Zy=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;function Vy(i,s="/"){let{pathname:o,search:f="",hash:m=""}=typeof i=="string"?kl(i):i,h;return o?(o=Nm(o),o.startsWith("/")?h=bm(o.substring(1),"/"):h=bm(o,s)):h=s,{pathname:h,search:Jy(f),hash:$y(m)}}function bm(i,s){let o=si(s).split("/");return i.split("/").forEach(m=>{m===".."?o.length>1&&o.pop():m!=="."&&o.push(m)}),o.length>1?o.join("/"):"/"}function Yf(i,s,o,f){return`Cannot include a '${i}' character in a manually specified \`to.${s}\` field [${JSON.stringify(f)}]. Please separate it out to the \`to.${o}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function wy(i){return i.filter((s,o)=>o===0||s.route.path&&s.route.path.length>0)}function Wf(i){let s=wy(i);return s.map((o,f)=>f===s.length-1?o.pathname:o.pathnameBase)}function oi(i,s,o,f=!1){let m;typeof i=="string"?m=kl(i):(m={...i},ze(!m.pathname||!m.pathname.includes("?"),Yf("?","pathname","search",m)),ze(!m.pathname||!m.pathname.includes("#"),Yf("#","pathname","hash",m)),ze(!m.search||!m.search.includes("#"),Yf("#","search","hash",m)));let h=i===""||m.pathname==="",b=h?"/":m.pathname,N;if(b==null)N=o;else{let A=s.length-1;if(!f&&b.startsWith("..")){let q=b.split("/");for(;q[0]==="..";)q.shift(),A-=1;m.pathname=q.join("/")}N=A>=0?s[A]:"/"}let S=Vy(m,N),v=b&&b!=="/"&&b.endsWith("/"),j=(h||b===".")&&o.endsWith("/");return!S.pathname.endsWith("/")&&(v||j)&&(S.pathname+="/"),S}var Nm=i=>i.replace(/\/\/+/g,"/"),Ct=i=>Nm(i.join("/")),si=i=>i.replace(/\/+$/,""),Ky=i=>si(i).replace(/^\/*/,"/"),Jy=i=>!i||i==="?"?"":i.startsWith("?")?i:"?"+i,$y=i=>!i||i==="#"?"":i.startsWith("#")?i:"#"+i,Wy=class{constructor(i,s,o,f=!1){this.status=i,this.statusText=s||"",this.internal=f,o instanceof Error?(this.data=o.toString(),this.error=o):this.data=o}};function ky(i){return i!=null&&typeof i.status=="number"&&typeof i.statusText=="string"&&typeof i.internal=="boolean"&&"data"in i}function Fy(i){let s=i.map(o=>o.route.path).filter(Boolean);return Ct(s)||"/"}var Rm=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function Om(i,s){let o=i;if(typeof o!="string"||!Zy.test(o))return{absoluteURL:void 0,isExternal:!1,to:o};let f=o,m=!1;if(Rm)try{let h=new URL(window.location.href),b=o.startsWith("//")?new URL(h.protocol+o):new URL(o),N=nl(b.pathname,s);b.origin===h.origin&&N!=null?o=N+b.search+b.hash:m=!0}catch{Nt(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:f,isExternal:m,to:o}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var jm=["POST","PUT","PATCH","DELETE"];new Set(jm);var Iy=["GET",...jm];new Set(Iy);var qa=E.createContext(null);qa.displayName="DataRouter";var di=E.createContext(null);di.displayName="DataRouterState";var Cm=E.createContext(!1);function Py(){return E.useContext(Cm)}var Dm=E.createContext({isTransitioning:!1});Dm.displayName="ViewTransition";var e0=E.createContext(new Map);e0.displayName="Fetchers";var t0=E.createContext(null);t0.displayName="Await";var ht=E.createContext(null);ht.displayName="Navigation";var qn=E.createContext(null);qn.displayName="Location";var Dt=E.createContext({outlet:null,matches:[],isDataRoute:!1});Dt.displayName="Route";var kf=E.createContext(null);kf.displayName="RouteError";var Mm="REACT_ROUTER_ERROR",l0="REDIRECT",a0="ROUTE_ERROR_RESPONSE";function n0(i){if(i.startsWith(`${Mm}:${l0}:{`))try{let s=JSON.parse(i.slice(28));if(typeof s=="object"&&s&&typeof s.status=="number"&&typeof s.statusText=="string"&&typeof s.location=="string"&&typeof s.reloadDocument=="boolean"&&typeof s.replace=="boolean")return s}catch{}}function u0(i){if(i.startsWith(`${Mm}:${a0}:{`))try{let s=JSON.parse(i.slice(40));if(typeof s=="object"&&s&&typeof s.status=="number"&&typeof s.statusText=="string")return new Wy(s.status,s.statusText,s.data)}catch{}}function i0(i,{relative:s}={}){ze(La(),"useHref() may be used only in the context of a component.");let{basename:o,navigator:f}=E.useContext(ht),{hash:m,pathname:h,search:b}=Ln(i,{relative:s}),N=h;return o!=="/"&&(N=h==="/"?o:Ct([o,h])),f.createHref({pathname:N,search:b,hash:m})}function La(){return E.useContext(qn)!=null}function Yt(){return ze(La(),"useLocation() may be used only in the context of a component."),E.useContext(qn).location}var Um="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function Hm(i){E.useContext(ht).static||E.useLayoutEffect(i)}function Bm(){let{isDataRoute:i}=E.useContext(Dt);return i?_0():c0()}function c0(){ze(La(),"useNavigate() may be used only in the context of a component.");let i=E.useContext(qa),{basename:s,navigator:o}=E.useContext(ht),{matches:f}=E.useContext(Dt),{pathname:m}=Yt(),h=JSON.stringify(Wf(f)),b=E.useRef(!1);return Hm(()=>{b.current=!0}),E.useCallback((S,v={})=>{if(Nt(b.current,Um),!b.current)return;if(typeof S=="number"){o.go(S);return}let j=oi(S,JSON.parse(h),m,v.relative==="path");i==null&&s!=="/"&&(j.pathname=j.pathname==="/"?s:Ct([s,j.pathname])),(v.replace?o.replace:o.push)(j,v.state,v)},[s,o,h,m,i])}var f0=E.createContext(null);function s0(i){let s=E.useContext(Dt).outlet;return E.useMemo(()=>s&&E.createElement(f0.Provider,{value:i},s),[s,i])}function Ln(i,{relative:s}={}){let{matches:o}=E.useContext(Dt),{pathname:f}=Yt(),m=JSON.stringify(Wf(o));return E.useMemo(()=>oi(i,JSON.parse(m),f,s==="path"),[i,m,f,s])}function r0(i,s){return qm(i,s)}function qm(i,s,o){ze(La(),"useRoutes() may be used only in the context of a component.");let{navigator:f}=E.useContext(ht),{matches:m}=E.useContext(Dt),h=m[m.length-1],b=h?h.params:{},N=h?h.pathname:"/",S=h?h.pathnameBase:"/",v=h&&h.route;{let B=v&&v.path||"";Ym(N,!v||B.endsWith("*")||B.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${N}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. -Please change the parent to .`)}let j=Yt(),A;if(s){let B=typeof s=="string"?kl(s):s;ze(S==="/"||B.pathname?.startsWith(S),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${S}" but pathname "${B.pathname}" was given in the \`location\` prop.`),A=B}else A=j;let q=A.pathname||"/",H=q;if(S!=="/"){let B=S.replace(/^\//,"").split("/");H="/"+q.replace(/^\//,"").split("/").slice(B.length).join("/")}let Z=xm(i,{pathname:H});Nt(y||Z!=null,`No routes matched location "${A.pathname}${A.search}${A.hash}" `),Nt(Z==null||Z[Z.length-1].route.element!==void 0||Z[Z.length-1].route.Component!==void 0||Z[Z.length-1].route.lazy!==void 0,`Matched leaf route at location "${A.pathname}${A.search}${A.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let G=v0(Z&&Z.map(B=>Object.assign({},B,{params:Object.assign({},b,B.params),pathname:Dt([S,f.encodeLocation?f.encodeLocation(B.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:B.pathname]),pathnameBase:B.pathnameBase==="/"?S:Dt([S,f.encodeLocation?f.encodeLocation(B.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:B.pathnameBase])})),d,o);return s&&G?E.createElement(qn.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",unstable_mask:void 0,...A},navigationType:"POP"}},G):G}function o0(){let i=b0(),s=ky(i)?`${i.status} ${i.statusText}`:i instanceof Error?i.message:JSON.stringify(i),o=i instanceof Error?i.stack:null,f="rgba(200,200,200, 0.5)",d={padding:"0.5rem",backgroundColor:f},h={padding:"2px 4px",backgroundColor:f},b=null;return console.error("Error handled by React Router default ErrorBoundary:",i),b=E.createElement(E.Fragment,null,E.createElement("p",null,"💿 Hey developer 👋"),E.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",E.createElement("code",{style:h},"ErrorBoundary")," or"," ",E.createElement("code",{style:h},"errorElement")," prop on your route.")),E.createElement(E.Fragment,null,E.createElement("h2",null,"Unexpected Application Error!"),E.createElement("h3",{style:{fontStyle:"italic"}},s),o?E.createElement("pre",{style:d},o):null,b)}var d0=E.createElement(o0,null),Lm=class extends E.Component{constructor(i){super(i),this.state={location:i.location,revalidation:i.revalidation,error:i.error}}static getDerivedStateFromError(i){return{error:i}}static getDerivedStateFromProps(i,s){return s.location!==i.location||s.revalidation!=="idle"&&i.revalidation==="idle"?{error:i.error,location:i.location,revalidation:i.revalidation}:{error:i.error!==void 0?i.error:s.error,location:s.location,revalidation:i.revalidation||s.revalidation}}componentDidCatch(i,s){this.props.onError?this.props.onError(i,s):console.error("React Router caught the following error during render",i)}render(){let i=this.state.error;if(this.context&&typeof i=="object"&&i&&"digest"in i&&typeof i.digest=="string"){const o=u0(i.digest);o&&(i=o)}let s=i!==void 0?E.createElement(Mt.Provider,{value:this.props.routeContext},E.createElement(kf.Provider,{value:i,children:this.props.component})):this.props.children;return this.context?E.createElement(m0,{error:i},s):s}};Lm.contextType=Dm;var Gf=new WeakMap;function m0({children:i,error:s}){let{basename:o}=E.useContext(ht);if(typeof s=="object"&&s&&"digest"in s&&typeof s.digest=="string"){let f=n0(s.digest);if(f){let d=Gf.get(s);if(d)throw d;let h=Om(f.location,o);if(Rm&&!Gf.get(s))if(h.isExternal||f.reloadDocument)window.location.href=h.absoluteURL||h.to;else{const b=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(h.to,{replace:f.replace}));throw Gf.set(s,b),b}return E.createElement("meta",{httpEquiv:"refresh",content:`0;url=${h.absoluteURL||h.to}`})}}return i}function h0({routeContext:i,match:s,children:o}){let f=E.useContext(Ba);return f&&f.static&&f.staticContext&&(s.route.errorElement||s.route.ErrorBoundary)&&(f.staticContext._deepestRenderedBoundaryId=s.route.id),E.createElement(Mt.Provider,{value:i},o)}function v0(i,s=[],o){let f=o?.state;if(i==null){if(!f)return null;if(f.errors)i=f.matches;else if(s.length===0&&!f.initialized&&f.matches.length>0)i=f.matches;else return null}let d=i,h=f?.errors;if(h!=null){let j=d.findIndex(A=>A.route.id&&h?.[A.route.id]!==void 0);ze(j>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(h).join(",")}`),d=d.slice(0,Math.min(d.length,j+1))}let b=!1,N=-1;if(o&&f){b=f.renderFallback;for(let j=0;j=0?d=d.slice(0,N+1):d=[d[0]];break}}}}let S=o?.onError,y=f&&S?(j,A)=>{S(j,{location:f.location,params:f.matches?.[0]?.params??{},unstable_pattern:Fy(f.matches),errorInfo:A})}:void 0;return d.reduceRight((j,A,q)=>{let H,Z=!1,G=null,B=null;f&&(H=h&&A.route.id?h[A.route.id]:void 0,G=A.route.errorElement||d0,b&&(N<0&&q===0?(Ym("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),Z=!0,B=null):N===q&&(Z=!0,B=A.route.hydrateFallbackElement||null)));let Q=s.concat(d.slice(0,q+1)),V=()=>{let $;return H?$=G:Z?$=B:A.route.Component?$=E.createElement(A.route.Component,null):A.route.element?$=A.route.element:$=j,E.createElement(h0,{match:A,routeContext:{outlet:j,matches:Q,isDataRoute:f!=null},children:$})};return f&&(A.route.ErrorBoundary||A.route.errorElement||q===0)?E.createElement(Lm,{location:f.location,revalidation:f.revalidation,component:G,error:H,children:V(),routeContext:{outlet:null,matches:Q,isDataRoute:!0},onError:y}):V()},null)}function Ff(i){return`${i} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function y0(i){let s=E.useContext(Ba);return ze(s,Ff(i)),s}function p0(i){let s=E.useContext(di);return ze(s,Ff(i)),s}function g0(i){let s=E.useContext(Mt);return ze(s,Ff(i)),s}function If(i){let s=g0(i),o=s.matches[s.matches.length-1];return ze(o.route.id,`${i} can only be used on routes that contain a unique "id"`),o.route.id}function S0(){return If("useRouteId")}function b0(){let i=E.useContext(kf),s=p0("useRouteError"),o=If("useRouteError");return i!==void 0?i:s.errors?.[o]}function _0(){let{router:i}=y0("useNavigate"),s=If("useNavigate"),o=E.useRef(!1);return Hm(()=>{o.current=!0}),E.useCallback(async(d,h={})=>{Nt(o.current,Um),o.current&&(typeof d=="number"?await i.navigate(d):await i.navigate(d,{fromRouteId:s,...h}))},[i,s])}var _m={};function Ym(i,s,o){!s&&!_m[i]&&(_m[i]=!0,Nt(!1,o))}E.memo(E0);function E0({routes:i,future:s,state:o,isStatic:f,onError:d}){return qm(i,void 0,{state:o,isStatic:f,onError:d})}function T0({to:i,replace:s,state:o,relative:f}){ze(qa()," may be used only in the context of a component.");let{static:d}=E.useContext(ht);Nt(!d," must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.");let{matches:h}=E.useContext(Mt),{pathname:b}=Yt(),N=Bm(),S=oi(i,Wf(h),b,f==="path"),y=JSON.stringify(S);return E.useEffect(()=>{N(JSON.parse(y),{replace:s,state:o,relative:f})},[N,y,f,s,o]),null}function x0(i){return s0(i.context)}function Ha(i){ze(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function A0({basename:i="/",children:s=null,location:o,navigationType:f="POP",navigator:d,static:h=!1,unstable_useTransitions:b}){ze(!qa(),"You cannot render a inside another . You should never have more than one in your app.");let N=i.replace(/^\/*/,"/"),S=E.useMemo(()=>({basename:N,navigator:d,static:h,unstable_useTransitions:b,future:{}}),[N,d,h,b]);typeof o=="string"&&(o=kl(o));let{pathname:y="/",search:j="",hash:A="",state:q=null,key:H="default",unstable_mask:Z}=o,G=E.useMemo(()=>{let B=nl(y,N);return B==null?null:{location:{pathname:B,search:j,hash:A,state:q,key:H,unstable_mask:Z},navigationType:f}},[N,y,j,A,q,H,f,Z]);return Nt(G!=null,` is not able to match the URL "${y}${j}${A}" because it does not start with the basename, so the won't render anything.`),G==null?null:E.createElement(ht.Provider,{value:S},E.createElement(qn.Provider,{children:s,value:G}))}function z0({children:i,location:s}){return r0(Jf(i),s)}function Jf(i,s=[]){let o=[];return E.Children.forEach(i,(f,d)=>{if(!E.isValidElement(f))return;let h=[...s,d];if(f.type===E.Fragment){o.push.apply(o,Jf(f.props.children,h));return}ze(f.type===Ha,`[${typeof f.type=="string"?f.type:f.type.name}] is not a component. All component children of must be a or `),ze(!f.props.index||!f.props.children,"An index route cannot have child routes.");let b={id:f.props.id||h.join("-"),caseSensitive:f.props.caseSensitive,element:f.props.element,Component:f.props.Component,index:f.props.index,path:f.props.path,middleware:f.props.middleware,loader:f.props.loader,action:f.props.action,hydrateFallbackElement:f.props.hydrateFallbackElement,HydrateFallback:f.props.HydrateFallback,errorElement:f.props.errorElement,ErrorBoundary:f.props.ErrorBoundary,hasErrorBoundary:f.props.hasErrorBoundary===!0||f.props.ErrorBoundary!=null||f.props.errorElement!=null,shouldRevalidate:f.props.shouldRevalidate,handle:f.props.handle,lazy:f.props.lazy};f.props.children&&(b.children=Jf(f.props.children,h)),o.push(b)}),o}var ui="get",ii="application/x-www-form-urlencoded";function mi(i){return typeof HTMLElement<"u"&&i instanceof HTMLElement}function N0(i){return mi(i)&&i.tagName.toLowerCase()==="button"}function R0(i){return mi(i)&&i.tagName.toLowerCase()==="form"}function O0(i){return mi(i)&&i.tagName.toLowerCase()==="input"}function j0(i){return!!(i.metaKey||i.altKey||i.ctrlKey||i.shiftKey)}function D0(i,s){return i.button===0&&(!s||s==="_self")&&!j0(i)}var ai=null;function M0(){if(ai===null)try{new FormData(document.createElement("form"),0),ai=!1}catch{ai=!0}return ai}var C0=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function Xf(i){return i!=null&&!C0.has(i)?(Nt(!1,`"${i}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${ii}"`),null):i}function U0(i,s){let o,f,d,h,b;if(R0(i)){let N=i.getAttribute("action");f=N?nl(N,s):null,o=i.getAttribute("method")||ui,d=Xf(i.getAttribute("enctype"))||ii,h=new FormData(i)}else if(N0(i)||O0(i)&&(i.type==="submit"||i.type==="image")){let N=i.form;if(N==null)throw new Error('Cannot submit a