diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ed8770..b6204d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This project follows [Semantic Versioning](https://semver.org/). From **v1.0.0** ### Added +- **Web UI (`flightdeck serve`):** **`/#/settings`** for appearance (Light / Dark / System, **`flightdeck-theme`**); collapsible sidebar (**`flightdeck-sidebar-collapsed`**); **offline system font stack** (no remote font CSS); sidebar + favicon use **bundled** **`/assets/flightdeck-icon-*.png`** with stable **`GET /flightdeck-icon.png`** fallback; **`html[data-theme="dark"]`** tokens and Playwright **`web/e2e/`** (`smoke` icon checks, `theme.spec.ts`, `sidebar.spec.ts`). - **`flightdeck pricing check`** — reports **`flightdeck-bundled-*`** snapshot age vs **`--max-age-days`** (default **90**); **`--fail`** for CI. **`release diff`** / **`POST /v1/diff`** append **`pricing.warnings`** when bundled snapshots exceed the same age threshold. - **`flightdeck.integrations.telemetry.configure_otel_tracing()`** — optional OTLP HTTP **`TracerProvider`** wiring when the **`telemetry`** extra is installed (see **`docs/sdk-integrations.md`**). - **SDK:** **`flightdeck.sdk.http_common`** shared serializers and retry policy; parity tests keep sync/async clients aligned. **`pytest-cov`** no longer omits **`sdk/client.py`**. diff --git a/README.md b/README.md index 49ca963..8501379 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,21 @@ **Ship AI agents safely with release diffs, runtime evidence, and policy gates.** -FlightDeck is **local-first** (CLI + SQLite + optional **`flightdeck serve`** UI): run evidence, pricing tables, and the ledger **stay on disk in your environment** by default—**no data leaves your infrastructure** for FlightDeck’s own product telemetry (there is no vendor backend that ingests your runs or tariffs). **No trace or billing payload is sent to FlightDeck as a vendor.** That posture matters for **regulated**, **air-gapped**, and **data-sovereignty** teams that cannot ship telemetry to a third-party SaaS observability backend. It is not an agent framework, prompt IDE, tracing dashboard, or gateway — it is where **what shipped**, **what ran**, **what it cost**, and **whether promote is allowed** are recorded and compared. +Local-first **CLI + SQLite**. Optional **`flightdeck serve`** exposes a small web UI and **`/v1`** JSON API—data stays on your machine unless you change that. + +**Core loop:** register releases → ingest run evidence → diff baseline vs candidate → promote or rollback under policy (optional human approval). + +## Product snapshot + +![FlightDeck — AI release governance (illustrative)](docs/images/flightdeck-overview.png) + +*Illustrative composite, not a screenshot of the shipped UI.* Policy is threshold-based on rollups from ingested runs—not built-in PII scanners. [Theming notes](docs/web-ui.md#theming-and-brand-alignment) + +| | FlightDeck | Tracing SaaS | Git/CI alone | +|--|--------------|----------------|--------------| +| Focus | Release + promote governance | Sessions / traces / evals | Source + pipelines | +| Versioned release artifact | Yes | No | DIY | +| Cost/latency diff + policy gate | Yes | Different lens | DIY | ## In ~20 seconds @@ -11,21 +25,24 @@ FlightDeck is **local-first** (CLI + SQLite + optional **`flightdeck serve`** UI 3. **Diff** baseline vs candidate: cost, latency, errors, and confidence (optional **pricing catalog** lines on top). 4. **Promote** only when policy passes; optional **human approval** (request → confirm) before the ledger moves. -## Example outcome +## Why it exists -You ship a candidate whose **system prompt drifts by a handful of tokens**; under your tariffs the diff shows **cost per run up ~31%** while policy caps spend. **`flightdeck release promote`** (or the HTTP promote path) **stays blocked** until you change the model, relax policy with intent, or widen evidence — not because CI is slow, but because the **governed ledger** says no. (The **~31%** story uses the **two custom pricing YAMLs** in **[examples/quickstart/](examples/quickstart/)**; **`flightdeck init`** alone seeds a **bundled snapshot** so your **first** cost-aware diff does not start from an empty pricing ledger.) +Small prompt or model changes can move **cost**, **latency**, and **error rate** in ways that are easy to miss. FlightDeck turns those into **explicit promote decisions** backed by ingested runs—before production pointers advance. ## Who should use this? -- **Growth-stage ICP:** **Platform or ML engineering teams** (often **5–30** people) at companies shipping **two or more** **LLM agents** to production—especially after a **cost** or **regression** incident from a **prompt** or **model** change—who need a **fast, governed** promote path without standing up a hosted observability product. -- **Regulated / enterprise ICP:** **Platform and SRE teams** in **healthcare, fintech, and similar** environments where buying criteria center on **data residency**, **audit trails**, and **provable control** over evidence and pricing data—**local-first** defaults and optional self-hosted **`flightdeck serve`** match a compliance-led evaluation, not only a velocity-led one. -- Teams that **version agent builds** (prompts, tools, model pins) and need a **durable audit trail**. -- Engineers who want **one command** to answer “is this candidate safe to roll forward?” with **numbers**, not gut feel. -- Anyone who has outgrown **ad hoc** folder diffs or **spreadsheet** promote checklists. +- **Platform or ML engineering** teams shipping **multiple LLM agents** to production—especially after a **cost** or **regression** tied to a **prompt** or **model** change—who want a **governed promote** path without treating a tracing SaaS as their release gate. +- **Regulated or compliance-sensitive** teams (healthcare, fintech, and similar) where **data residency**, **audit trails**, and **control over evidence and pricing data** matter; **local-first** defaults and optional self-hosted **`flightdeck serve`** fit that posture. +- Teams that **version agent builds** (prompts, tools, model pins) and need a **durable audit trail** for what shipped and what ran. +- Engineers who want a **straightforward workflow** to answer “is this candidate safe to roll forward?” with **numbers and policy**, not only gut feel or spreadsheet checklists. + +## Example outcome + +You ship a candidate whose **prompt or model** shifts slightly; under your tariffs the diff shows **cost per run** rising while policy caps spend. **`flightdeck release promote`** (or the HTTP promote path) **stays blocked** until you change the model, adjust policy with intent, or gather more evidence—not because CI is slow, but because the **ledger** says no. The **~31%** style story in [examples/quickstart/](examples/quickstart/) uses **two custom pricing YAMLs**; **`flightdeck init`** alone seeds a **bundled** snapshot so your first cost-aware diff is not empty. -## How FlightDeck fits your stack +## How it fits your stack -FlightDeck sits **next to** your agent runtime (not in the inference hot path): emit evidence, run **`flightdeck`** from a laptop or CI, gate **promote** with policy (and optional approval). +FlightDeck sits **next to** your agent runtime (not in the inference hot path): emit evidence, run **`flightdeck`** from a laptop or CI, gate **promote** with policy. ```mermaid flowchart LR @@ -48,92 +65,30 @@ flowchart LR ci -->|"policy pass"| promote ``` -## Comparison at a glance - -| | **FlightDeck** | **Langfuse** | **Arize Phoenix / Cloud** | **Git / CI alone** | -|--|----------------|----------------|---------------------------|---------------------| -| **Primary job** | **Release + promote governance** for agents (ledger, diff, policy) | Tracing, sessions, evals, LLM observability | ML / model observability and monitoring | Source control and generic pipelines | -| **Immutable release artifact** | Yes (`release.yaml` + checksum) | No | No | Only if you build it | -| **Evidence + cost/latency diff** | Yes (runs + pricing tables / optional catalog) | Different lens (trace-level) | Different lens | DIY | -| **Default data residency** | **On your machine** (CLI / SQLite / local HTTP) | Typically SaaS-hosted | Cloud offerings | Your repo | -| **Policy gate on promote** | First-class | No | No | DIY | - -**Try the UI:** run **`flightdeck serve`**, then open **http://127.0.0.1:8765/** — Overview, Diff, and Actions (see [docs/web-ui.md](docs/web-ui.md)). - -## Why it exists - -Small prompt or model changes can silently move **cost**, **latency**, and **error rate**. FlightDeck turns those moves into **explicit promote decisions** backed by ingested runs — before production pointers advance. - -**Current local spine:** versioned **`release.yaml`** + checksums · **`RunEvent`** ingest (JSONL or arrays) · **bundled default pricing** on **`flightdeck init`** (plus optional **`pricing import`**) · **`flightdeck release diff`** · policy-gated **`release promote`** / rollback · full **audit history**. - -## Status - -FlightDeck is **local-first** and ships as a Python CLI backed by SQLite. - -**v1.0.0** froze **SemVer-stable public contracts** for the documented CLI, committed **`schemas/v1/`**, -and **`POST /v1/events`** with **`api_version` `v1`**. **v1.1.x** adds catalog-aware diffs, approval flows, and forensics slices (optional pricing catalog on diffs, -promotion request/confirm, read-only runs listing, **`GET /v1/workspace`** for UI and automation, Helm/fleet examples) -without breaking those v1.0 shapes. **v1.2.0** raises the Python floor to **3.11+**, tightens **Bearer** gating for **`POST /v1/events`** and **`GET /v1/*`** when **`FLIGHTDECK_LOCAL_API_TOKEN`** is set, adds optional **PostgreSQL**, **bundled default pricing** on **`flightdeck init`**, and experimental **`flightdeck.integrations`**. See **[RELEASE_NOTES.md](RELEASE_NOTES.md)** and **[CHANGELOG.md](CHANGELOG.md)**. -The product scope is still intentionally narrow (release governance, not a hosted agent platform). - -**Maintenance and sustainability:** the project is **Apache-2.0** with **no required commercial license**. If FlightDeck matters to your production stack, use **[SUPPORT.md](SUPPORT.md)** for security, commercial, and sponsorship pointers, and the **Sponsor** affordance on **[github.com/flightdeckdev/flightdeck](https://github.com/flightdeckdev/flightdeck)** when it is enabled—signals like that answer “what happens if maintenance stops?” more credibly than roadmap prose alone. +--- -Not implemented yet: - -- hosted control plane -- automated traffic routing -- tool-cost pricing -- OpenTelemetry: optional **`telemetry`** extra installs OTLP-capable SDK packages; call **`flightdeck.integrations.telemetry.configure_otel_tracing()`** once to wire an OTLP span exporter to **your** collector (see **[docs/sdk-integrations.md](docs/sdk-integrations.md)**) - -Shipped locally: - -- `flightdeck serve` + JSON routes under `/v1/*` (read + diff/promote/rollback + event ingest); see **Local HTTP API** below -- minimal Python SDK (`flightdeck.sdk.client`) -- `flightdeck release rollback` (policy-gated, audited) -- optional **`promotion_requires_approval`** in `flightdeck.yaml` with **`POST /v1/promote/request`** and **`POST /v1/promote/confirm`** - -### Local HTTP API - -With **`flightdeck serve`** (default bind **127.0.0.1**), the app exposes **`GET /health`**, **`GET /v1/workspace`** -(read-only workspace flags for scripts and the bundled UI), **`GET /v1/metrics`**, **`GET /v1/releases`**, **`GET /v1/promoted`**, **`GET /v1/actions`**, **`GET /v1/promotion-requests`**, **`GET /v1/runs`**, **`POST /v1/events`**, **`POST /v1/diff`**, **`POST /v1/promote`**, **`POST /v1/promote/request`**, **`POST /v1/promote/confirm`**, and **`POST /v1/rollback`**. **`POST /v1/promote`**, **`POST /v1/promote/request`**, **`POST /v1/promote/confirm`**, **`POST /v1/rollback`**, and **`POST /v1/events`** accept requests only from loopback clients unless **`FLIGHTDECK_LOCAL_API_TOKEN`** is set, in which case callers must send **`Authorization: Bearer `**; when that token is set, the same Bearer header is required for **`GET /v1/*`** read APIs (bundled UI via **`VITE_FLIGHTDECK_LOCAL_API_TOKEN`**). **`POST /v1/diff`** stays unauthenticated. See **[docs/http-api.md](docs/http-api.md)** and **[SECURITY.md](SECURITY.md)**. - -## Quickstart - -Install **[uv](https://docs.astral.sh/uv/getting-started/installation/)**, then from the repo root: +## Install and smoke-test ```bash uv sync --extra dev uv run flightdeck --help -``` - -Or with **pip** and a venv: - -```bash -python -m venv .venv -python -m pip install -e ".[dev]" -flightdeck --help -``` - -Run the cross-platform quickstart smoke (same as CI): - -```bash uv run flightdeck-quickstart-verify ``` -(or **`python -m flightdeck.quickstart_smoke`** / **`python scripts/quickstart_smoke.py`** inside an activated venv) +**pip, Windows, CI:** [DEVELOPMENT.md](DEVELOPMENT.md) -Or use the bash wrapper (Git Bash / WSL on Windows): +**Web UI:** `uv run flightdeck serve` → **http://127.0.0.1:8765/** · [docs/web-ui.md](docs/web-ui.md) -```bash -./scripts/smoke.sh -``` +The UI may show a **loopback / no Bearer** status line—that is **what the server is doing**, not something you execute. Bearer mode = you set a **shared secret** on the server (`FLIGHTDECK_LOCAL_API_TOKEN`) and the same value for the UI (`VITE_FLIGHTDECK_LOCAL_API_TOKEN` or `web/.env.local` with `npm run dev`). [SECURITY.md](SECURITY.md) · [docs/http-api.md](docs/http-api.md) -**Bundled pricing (default `init`):** **`flightdeck init`** migrates the ledger, imports **OpenAI**, **Anthropic**, and **Google** (Gemini-class) tables at **`pricing_version` `flightdeck-bundled-2026-05`**, and writes **`.flightdeck/pricing-catalog.yaml`** with **`pricing_catalog_path`** set in **`flightdeck.yaml`**. In **`release.yaml`**, set **`spec.pricing_reference`** to `{ provider: openai | anthropic | google, pricing_version: flightdeck-bundled-2026-05 }` to get **per-table** and **catalog** cost lines on diffs without authoring YAML. These rates are a **convenience snapshot**, not live vendor billing—**`flightdeck pricing import`** your own files for production. Use **`flightdeck init --no-bundled-pricing`** for an empty ledger. Official list-pricing URLs are referenced in comments atop the bundled YAML under **`src/flightdeck/bundled_pricing/`**. **`flightdeck pricing check`** flags bundled snapshots older than **90 days** (use **`--fail`** in CI); **`release diff`** adds **`pricing.warnings`** for the same condition so cost lines do not go silently stale. **Release policy:** bundled tables are **refreshed with each minor release** when vendor public list pricing changes materially (see **[ROADMAP.md](ROADMAP.md)**). +--- -Or walk through the **full quickstart** (policy + **two** custom tariffs for the **~31%** narrative—same flow CI runs): +## Example workflow (policy + two tariffs) + +Substitute release IDs in the JSONL or rely on `flightdeck-quickstart-verify` for the same checks CI runs. ```bash -flightdeck init # omit --no-bundled-pricing; bundled tables are additive with the imports below +flightdeck init flightdeck pricing import examples/quickstart/pricing-baseline.yaml flightdeck pricing import examples/quickstart/pricing-candidate.yaml flightdeck policy set examples/quickstart/policy.yaml @@ -152,31 +107,32 @@ flightdeck release promote "$BASELINE" --env local --window 7d --reason "initial flightdeck release history --agent agent_support --env local ``` -The static event files in `examples/quickstart` use placeholder release IDs so the repo can ship stable examples. -Substitute them before ingestion, or run **`uv run flightdeck-quickstart-verify`** / **`python -m flightdeck.quickstart_smoke`** (venv) or **`./scripts/smoke.sh`** from Git Bash/WSL on Windows. +Bundled pricing from `init` is a **convenience snapshot**—`flightdeck pricing import` for production. [docs/release-artifact.md](docs/release-artifact.md) · [RELEASE_NOTES.md](RELEASE_NOTES.md) + +**More examples:** [examples/quickstart/](examples/quickstart/) · [examples/ci/](examples/ci/) · [examples/deploy/](examples/deploy/) · [examples/integration/](examples/integration/) -**Examples:** [examples/quickstart/](examples/quickstart/) · [examples/ci/](examples/ci/) (policy gate + Actions) · [examples/deploy/](examples/deploy/) (`serve` via Docker/Compose) · [examples/integration/](examples/integration/) (HTTP event emitter) · [examples/integration/adoption/](examples/integration/adoption/) (framework hooks). +--- ## Documentation -- [CLI reference](docs/cli.md) — all commands, flags, arguments, and exit codes -- [HTTP API reference](docs/http-api.md) — all `/v1/*` routes, request/response shapes, auth, `RunEvent` field reference -- [Python SDK](docs/sdk.md) — `FlightdeckClient` / `AsyncFlightdeckClient` usage guide -- [Runtime integrations (experimental)](docs/sdk-integrations.md) — optional `flightdeck.integrations` mappers (LangChain, OpenAI Agents, Temporal, etc.) -- [Operations and policy](docs/operations-and-policy.md) — diff, promote, rollback internals; policy model and confidence tiers -- [Release artifacts and pricing](docs/release-artifact.md) — `release.yaml` format, bundle layout, checksum algorithm, workspace config, pricing tables -- [Pricing catalog](docs/pricing-catalog.md) — optional `pricing_catalog_path`, catalog vs imported tables, troubleshooting -- [JSON Schemas](schemas/v1/) -- [Release notes (maintainer)](RELEASE_NOTES.md) -- [Roadmap](ROADMAP.md) -- [Versioning](VERSIONING.md) -- [Development](DEVELOPMENT.md) -- [Contributing](CONTRIBUTING.md) -- [Security](SECURITY.md) -- [Support and sustainability](SUPPORT.md) -- [CLAUDE.md](CLAUDE.md) and [AGENTS.md](AGENTS.md) - -## Development +| Area | Links | +|------|--------| +| CLI | [docs/cli.md](docs/cli.md) | +| HTTP API (routes, auth) | [docs/http-api.md](docs/http-api.md) | +| Security / trust model | [SECURITY.md](SECURITY.md) | +| Python SDK | [docs/sdk.md](docs/sdk.md) | +| Policy, diff, promote | [docs/operations-and-policy.md](docs/operations-and-policy.md) | +| `release.yaml`, pricing, checksums | [docs/release-artifact.md](docs/release-artifact.md) | +| Pricing catalog | [docs/pricing-catalog.md](docs/pricing-catalog.md) | +| Integrations (experimental) | [docs/sdk-integrations.md](docs/sdk-integrations.md) | +| Wire schemas | [schemas/v1/](schemas/v1/) | +| Changelog · roadmap · contributing | [CHANGELOG.md](CHANGELOG.md) · [ROADMAP.md](ROADMAP.md) · [CONTRIBUTING.md](CONTRIBUTING.md) | +| Maintainer / agent rules | [AGENTS.md](AGENTS.md) · [CLAUDE.md](CLAUDE.md) | +| Support | [SUPPORT.md](SUPPORT.md) | + +--- + +## Contributing (quick CI match) ```bash uv sync --frozen --extra dev @@ -186,12 +142,12 @@ uv run flightdeck-quickstart-verify uv run flightdeck --help ``` -If you change **`web/`** or **Pydantic models**, also run the **`static/`** and **`schemas/`** drift checks from **[DEVELOPMENT.md](DEVELOPMENT.md)** (same gates as **`.github/workflows/ci.yml`**). **[AGENTS.md](AGENTS.md)** and **[`.cursor/rules/flightdeck-ci-artifacts.mdc`](.cursor/rules/flightdeck-ci-artifacts.mdc)** summarize them for humans and Cursor. +Full gates (web static, schemas, e2e): [DEVELOPMENT.md](DEVELOPMENT.md) -See [DEVELOPMENT.md](DEVELOPMENT.md) for **uv** and **pip** setup, verification, troubleshooting, and **PyPI releases** (tag-driven; not on merge to `main`). +--- ## License -FlightDeck is licensed under the **Apache License, Version 2.0** — see [`LICENSE`](LICENSE) and [`NOTICE`](NOTICE). +Apache-2.0 — [LICENSE](LICENSE) · [NOTICE](NOTICE) -The canonical public repository: [https://github.com/flightdeckdev/flightdeck](https://github.com/flightdeckdev/flightdeck). +Canonical: [github.com/flightdeckdev/flightdeck](https://github.com/flightdeckdev/flightdeck) diff --git a/ROADMAP.md b/ROADMAP.md index 5615ae3..af77e12 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -58,7 +58,14 @@ These map to **What is next** items **1**, **2**, and **5**; ship notes stay in **Explicit UI deferrals** -Out of scope for the near-term web app: custom themes or theme marketplaces; embedded arbitrary log viewers; full observability or fleet consoles in the browser; multi-workspace UI (follows conditional **Fleet / cross-workspace** in **What is next**). +Out of scope for the near-term web app: arbitrary third-party themes or theme marketplaces; embedded arbitrary log viewers; full observability or fleet consoles in the browser; multi-workspace UI (follows conditional **Fleet / cross-workspace** in **What is next**). A **single built-in dark palette** (plus system preference) aligned with operator ergonomics and brand art is **not** a “custom theme product”—see **[docs/web-ui.md — Theming and brand alignment](docs/web-ui.md#theming-and-brand-alignment)** for the phased plan vs the marketing composite. + +**Deferred until APIs or contracts exist (then revisit UX)** + +- **Identity for HTTP and UI beyond shared-secret Bearer:** today **`FLIGHTDECK_LOCAL_API_TOKEN`** / **`VITE_FLIGHTDECK_LOCAL_API_TOKEN`** are an **operator-chosen static secret** for this server’s JSON API (and the bundled UI when configured). **OAuth2/OIDC**, per-user sessions, API key rotation, and enterprise SSO in front of **`flightdeck serve`** are **not** shipped in core; expect **reverse-proxy or gateway** patterns until a future design explicitly extends the trust model. Revisit when there is a concrete contract (token issuance, audience, rotation) that fits local-first operation. +- **Environment / promotion pipeline visualization** (for example DEV → STAGING → PROD lanes with per-stage policy state): today the ledger uses a single `environment` string and CLI/API fields—not a first-class multi-stage graph. Revisit when the server exposes enough structure to render without inventing state. +- **Dense “evidence-first release card”** on Diff (token deltas, tool lists, synthetic safety rows): ship only fields the diff and catalog payloads actually provide; expand the card when optional aggregates or provenance hooks land in the API. +- **README / social preview hero** (marketing composites, category positioning): tracked with docs and release comms, not as a substitute for honest in-app surfaces. --- @@ -71,7 +78,7 @@ Gaps between “works locally” and “easy to use across production services. | **Event pipeline** | Reliable `RunEvent` emission from app/agent runtimes. | Near term: reference integration examples; operator owns final runtime wiring. | | **CI/GitOps flow** | Register → ingest → diff → gate → promote in pipelines. | Near term: maintained CI examples/templates. | | **Deployment unit** | Repeatable `serve` packaging, health checks, process supervision. | Near term: container/compose guidance; still local-first by default. | -| **Identity and access** | Strong auth beyond loopback + optional bearer token. | Mid term: documented hardened patterns; first-class enterprise auth is a longer arc. | +| **Identity and access** | Strong auth beyond loopback + optional static Bearer (operator-chosen secret for HTTP API). | Mid term: documented proxy/gateway patterns; interactive OAuth/OIDC for the bundled UI is a **longer / conditional** arc (see **Deferred until APIs** above). | | **Storage/availability** | Backup/restore, scaling, HA story. | Operator-owned today; improve docs and patterns. | | **Observability integration** | Correlated telemetry export and operational visibility. | Mid term: OTLP-oriented integration paths (not an APM/dashboard product). | | **Multi-workspace/fleet** | Cross-workspace views and policy coordination. | Long term and conditional; one workspace = one ledger today. | diff --git a/SECURITY.md b/SECURITY.md index 5f83f52..2f6104f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -36,6 +36,12 @@ See **[CONTRIBUTING.md](CONTRIBUTING.md)** for a pre-push checklist aligned with ## Local HTTP API (`flightdeck serve`) +### `FLIGHTDECK_LOCAL_API_TOKEN` — what it is (and is not) + +- **You choose the value.** FlightDeck does **not** generate, mint, or rotate this string for you. It is a **shared secret** you set in the server environment (same idea as a static API key). A typical choice is a long random value (for example `openssl rand -hex 32` as in **[docs/http-api.md](docs/http-api.md)**). +- **What it gates:** access to this process’s **HTTP JSON API** (`GET /v1/*` when set, plus ledger writes and ingest) via the **`Authorization: Bearer …`** header. SDKs use **`api_token=`**; scripts and agents send the header explicitly; the **bundled React UI** uses **`VITE_FLIGHTDECK_LOCAL_API_TOKEN`** at build time (or **`web/.env.local`** under `npm run dev`) so the browser can send the **same** secret — see **[docs/web-ui.md](docs/web-ui.md)**. +- **What it is not:** end-user login, OAuth/OIDC, SSO, or per-person identity inside FlightDeck. Those are **not** part of today’s core product; the roadmap treats stronger identity as a longer arc (see **[ROADMAP.md](ROADMAP.md)**). + The bundled server is intended for **local development and demos**. **`POST /v1/promote`**, **`POST /v1/promote/request`**, **`POST /v1/promote/confirm`**, **`POST /v1/rollback`**, and **`POST /v1/events`** (run event ingest) share one **ledger-write** access model in server code: with no token configured, only **loopback** clients (`127.0.0.1`, `::1`, `localhost`, and the Starlette test client) may call them. If you set **`FLIGHTDECK_LOCAL_API_TOKEN`**, every such request must include **`Authorization: Bearer `**; use a strong random value and treat it like a local secret. Remote emitters (agents, sidecars) must use the Bearer path when the server listens beyond loopback. **Human approval** (`promotion_requires_approval: true` in `flightdeck.yaml`) adds a **second actor step** before a promote is applied: **`POST /v1/promote/request`** creates a pending row; **`POST /v1/promote/confirm`** completes it. **Policy still runs on confirm** — approval is not a bypass; a request that fails policy remains blocked with the same HTTP **409** outcome as a direct promote. diff --git a/docs/http-api.md b/docs/http-api.md index ec2cf72..d6704eb 100644 --- a/docs/http-api.md +++ b/docs/http-api.md @@ -18,6 +18,8 @@ first if it does not exist. ## Authentication and access control +**Credential model:** `FLIGHTDECK_LOCAL_API_TOKEN` is an **operator-chosen shared secret** for this server instance. FlightDeck does **not** issue it. It gates **HTTP access** to the local API (reads and/or writes per the table below). It is **not** OAuth, SSO, or per-user identity — see **[SECURITY.md](../SECURITY.md#local-http-api-flightdeck-serve)** and **[ROADMAP.md](../ROADMAP.md)** for scope and future directions. + Two access tiers: | Route | No token configured | `FLIGHTDECK_LOCAL_API_TOKEN` set | diff --git a/docs/images/flightdeck-overview.png b/docs/images/flightdeck-overview.png new file mode 100644 index 0000000..15f1efb Binary files /dev/null and b/docs/images/flightdeck-overview.png differ diff --git a/docs/web-ui.md b/docs/web-ui.md index 6aaf080..5dd4df4 100644 --- a/docs/web-ui.md +++ b/docs/web-ui.md @@ -10,17 +10,54 @@ For setup, dev workflow, build commands, and Playwright E2E instructions see --- +## Theming and brand alignment + +### Desired state (disclaimer) + +The **[README product overview](../README.md#product-overview)** image is a **marketing composite**: dark chrome, dense “dashboard” cards, and narrative labels that **do not** map one-to-one to shipped pages. The bundled **hex mark** (`web/public/flightdeck-icon.png`) matches that art direction (cyan–purple accent, dark ground). **This document and the operator UI** stay grounded in real **`/v1/*`** data—visual work should **not** invent panels (for example a synthetic “release blocked” hero) until the APIs and product decisions exist. + +### What we can borrow from the art (incremental) + +| Art direction | Application in this repo | +|---------------|---------------------------| +| Dark navy / near-black shell | **`html[data-theme="dark"]`** in `web/src/index.css` mirrors semantic tokens; **Appearance** control in the sidebar defaults to **Light** (stored under **`localStorage`** key **`flightdeck-theme`**). | +| Cyan → purple gradient | CSS variables (for example `--fd-accent-gradient`) for **active nav**, **primary buttons**, and **focus-visible** accents—used sparingly so trust/safety UI stays calm. | +| High-contrast titles | Tune `--fd-type-*` and weights under dark mode; avoid shrinking body text for density. | +| “Neon” feel | Reserve for **interactive** states, not large background fills. | +| Geometric sans | **Shipped:** offline **system UI stack** in `index.css` (`--fd-font`). Optional: install **Inter** locally if you want that face without bundling remote CSS. | + +### Phased implementation plan + +1. **Token foundation** — Extend `:root` with any missing semantics (`--fd-surface-elevated`, gradient stops, optional `--fd-bg-subtle`). Replace scattered literals in `web/src/index.css` (for example warning callout backgrounds) with variables so dark mode does not require hunting hex values. +2. **`[data-theme="dark"]` block** — Mirror every semantic token used by `.fd-shell`, sidebar, cards, tables, `Badge`, drawers, and `JsonPanel`; set `color-scheme: dark` on `html` when active. Validate **WCAG AA** for body text and links. +3. **Preference UI** — **`/#/settings`** (and room for more prefs later): **Light** / **Dark** / **System**; listen to `prefers-color-scheme` when System is selected. Persist `localStorage` key **`flightdeck-theme`** (`light` \| `dark` \| `system`). +4. **Brand accents** — Apply the gradient token to **active** `.fd-nav__link--active` (left rail) and primary submit-style buttons; keep destructive actions on existing red semantics. +5. **Light theme polish** — Even before dark ships: align spacing rhythm and card shadows with the same tokens so both themes stay maintainable. +6. **Verification** — From `web/`: **`npm ci`**, **`npm run build`**, commit **`src/flightdeck/server/static/`**; **`npm run test:e2e`** (includes **`e2e/theme.spec.ts`**: default light, dark persistence, system / `prefers-color-scheme`, overview smoke in dark). Manually smoke **Diff** and **Actions** in both themes (policy panels, JSON drawer, rollback affordances). + +### Explicit deferrals (still) + +- **Multi-theme marketplaces**, per-user arbitrary color pickers, or third-party skin systems — off mission. +- **Infographic-only widgets** (staged DEV→STAGING→PROD pipeline strip, sparkline grids) — wait for real APIs and **[ROADMAP](ROADMAP.md)** operator outcomes, not decorative parity with the poster. + +--- + ## Routing The app uses **HashRouter** (`react-router-dom`) so all navigation stays within the single `index.html` that FastAPI's static file mount serves. URLs look like `http://127.0.0.1:8765/#/diff`. No server-side route matching is required. +**Static UI assets:** hashed bundles are mounted at **`/assets/`**. The sidebar mark and tab icons use the **bundled** URL from `web/src/assets/flightdeck-icon.png` (emitted as **`/assets/flightdeck-icon-.png`**; `main.tsx` sets `` at runtime). A **stable** duplicate remains at **`GET /flightdeck-icon.png`** (from `web/public/` at build time + FastAPI `FileResponse`) for bookmarks, probes, and **`web/e2e/smoke.spec.ts`**. + +**Typography:** the UI uses an **offline-first system font stack** (no Google Fonts or other remote CSS). Install **Inter** locally if you want that face in dev tools without changing the bundle. + | Hash path | Component | HTTP calls | Notes | |-----------|-----------|-----------|-------| | `#/` | `OverviewPage` | `GET /v1/releases`, `GET /v1/promoted`, `GET /v1/actions`, `GET /v1/metrics` (parallel where applicable) | Ledger metrics (read-only); short per-counter hints; skeleton on first load; **auto-refresh** every 30s when the tab is visible + on timeline **`generation`** bump; links to Diff/Runs | | `#/diff` | `DiffPage` | `POST /v1/diff` | Sections: policy gate (incl. `evaluated_at`), evidence window, pricing/catalog/hints (incl. provider/version skew callout when sides differ), per-1k prices when present, cost/quality rollups; raw JSON panel | | `#/runs` | `RunsPage` | `GET /v1/releases` (for datalist), `GET /v1/runs`, `GET /v1/runs/export` | Forensics: filters, table (trace/status, trace band rows or **Group by trace_id**), **View** drawer (focus trap, session/span ids), typed **run-query error** card with **Retry**, empty/offset/truncation hints, NDJSON download | +| `#/settings` | `SettingsPage` | *(none)* | **Color theme** (Light / Dark / System) via `ThemeToggle`; more preferences later. | | `#/actions` | `ActionsPage` | `GET /v1/workspace`, `GET /v1/promotion-requests` (when `promotion_requires_approval`), `POST /v1/promote` **or** `POST /v1/promote/request` + `POST /v1/promote/confirm`, `POST /v1/rollback` | Workspace skeleton then strip; approval path: numbered steps, pending **Refresh list** / **Use for confirm**; **Rollback** danger-styled; see **ActionsPage** below | | `#/*` (any other) | — | Redirects to `#/` | | @@ -36,25 +73,25 @@ promote/rollback capability should be unavailable regardless of network placemen ## Component tree ``` -App (HashRouter) -└── AppShell (layout: left sidebar + main column) - └── TimelineRefreshProvider (context) - └── div.fd-shell - ├── aside.fd-sidebar (brand + primary nav) - └── div.fd-shell__content - ├── SecurityStatusBar - └── main#main-content → OverviewPage | DiffPage | RunsPage | ActionsPage +ThemePreferenceProvider (`App.tsx`) +└── HashRouter + └── Routes / AppShell layout route + └── TimelineRefreshProvider + └── div.fd-shell + ├── aside.fd-sidebar (brand, collapse chevron, primary nav, footer nav → Settings) + └── div.fd-shell__content + ├── SecurityStatusBar + └── main#main-content → OverviewPage | DiffPage | RunsPage | ActionsPage | SettingsPage ``` --- ## `AppShell` (`web/src/components/AppShell.tsx`) -Renders a fixed-width **left sidebar** (`aside.fd-sidebar`) with brand and vertical primary -nav (Langfuse-style rail), then a **`fd-shell__content`** column with `SecurityStatusBar` and +Renders a fixed-width **left sidebar** (`aside.fd-sidebar`) with brand (gradient **FlightDeck** wordmark, mark in a **raised tile**), a **collapse** control (SVG chevrons, `localStorage` **`flightdeck-sidebar-collapsed`**), a **primary** nav (inline SVG icons + labels; icon-only when collapsed), and a **footer** nav pinned to the bottom of the rail with **Settings** → `#/settings`. Then a **`fd-shell__content`** column with `SecurityStatusBar` and `
` wrapping an `` for the active page. On narrow viewports the sidebar stacks -above the content with a horizontal nav row. Wraps the subtree in `TimelineRefreshProvider` -so any descendant can access the refresh context. +above the content with a horizontal nav row; a **collapsed** rail is expanded back to full labels in that breakpoint. Wraps the subtree in `TimelineRefreshProvider` +so any descendant can access the refresh context. `ThemePreferenceProvider` (from `App.tsx`) wraps the router so `ThemeToggle` on **Settings** can read and update **`flightdeck-theme`**; `main.tsx` applies the effective theme before the first paint to avoid a flash of the wrong scheme. A **Skip to main content** link (class `fd-skip-link`) appears first in the shell; it uses `preventDefault` + `focus()` on `#main-content` so **HashRouter** hash URLs (`#/…`) are not @@ -233,7 +270,7 @@ After a successful **promote** or **rollback** (or **confirm**): 2. Outcome card shows policy badge, pointer badge, metric grid, and reasons list when applicable. 3. `notifyTimelineMutated()` runs so `OverviewPage` refetches. -**Auth:** `VITE_FLIGHTDECK_LOCAL_API_TOKEN` is sent on every `fetchJson` call, including **`POST /v1/promote/request`** and **`POST /v1/promote/confirm`**. See [http-api.md § Authentication](http-api.md#authentication-and-access-control). +**Auth:** `VITE_FLIGHTDECK_LOCAL_API_TOKEN` is sent on every `fetchJson` call, including **`POST /v1/promote/request`** and **`POST /v1/promote/confirm`**. It must **match** `FLIGHTDECK_LOCAL_API_TOKEN` on the server when the server enforces Bearer (see [http-api.md § Authentication](http-api.md#authentication-and-access-control)). FlightDeck does **not** mint this value: the operator chooses a shared secret for **HTTP API** access. It is baked in at **build time** for the committed static bundle; local Bearer testing normally uses **`web/.env.local`** + **`npm run dev`**. It is **not** OAuth or end-user SSO — see [SECURITY.md](../SECURITY.md) (**Local HTTP API**). **HTTP errors:** `fetchJson` formats FastAPI **`detail`** strings, validation arrays, and `{ message: … }` objects into a single `Error` message for the alert line. diff --git a/src/flightdeck/server/app.py b/src/flightdeck/server/app.py index 62eb7c6..04d8dfb 100644 --- a/src/flightdeck/server/app.py +++ b/src/flightdeck/server/app.py @@ -4,7 +4,7 @@ import os from pathlib import Path -from fastapi import FastAPI, Request +from fastapi import FastAPI, HTTPException, Request from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles @@ -52,4 +52,12 @@ def health(request: Request) -> dict[str, str]: def ui_index() -> FileResponse: return FileResponse(static_dir / "index.html") + @app.get("/flightdeck-icon.png") + def ui_app_icon() -> FileResponse: + """Shipped UI favicon / sidebar mark (copied from ``web/public`` at build time).""" + path = static_dir / "flightdeck-icon.png" + if not path.is_file(): + raise HTTPException(status_code=404, detail="UI icon not found (rebuild web bundle)") + return FileResponse(path, media_type="image/png") + return app diff --git a/src/flightdeck/server/static/assets/flightdeck-icon-D0ukMVNG.png b/src/flightdeck/server/static/assets/flightdeck-icon-D0ukMVNG.png new file mode 100644 index 0000000..b5e5797 Binary files /dev/null and b/src/flightdeck/server/static/assets/flightdeck-icon-D0ukMVNG.png differ diff --git a/src/flightdeck/server/static/assets/index-BMbVZO_a.js b/src/flightdeck/server/static/assets/index-BMbVZO_a.js deleted file mode 100644 index 0c29e82..0000000 --- a/src/flightdeck/server/static/assets/index-BMbVZO_a.js +++ /dev/null @@ -1,11 +0,0 @@ -(function(){const f=document.createElement("link").relList;if(f&&f.supports&&f.supports("modulepreload"))return;for(const m of document.querySelectorAll('link[rel="modulepreload"]'))r(m);new MutationObserver(m=>{for(const h of m)if(h.type==="childList")for(const _ of h.addedNodes)_.tagName==="LINK"&&_.rel==="modulepreload"&&r(_)}).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 r(m){if(m.ep)return;m.ep=!0;const h=o(m);fetch(m.href,h)}})();var Gs={exports:{}},Qn={};var mm;function Ry(){if(mm)return Qn;mm=1;var i=Symbol.for("react.transitional.element"),f=Symbol.for("react.fragment");function o(r,m,h){var _=null;if(h!==void 0&&(_=""+h),m.key!==void 0&&(_=""+m.key),"key"in m){h={};for(var R in m)R!=="key"&&(h[R]=m[R])}else h=m;return m=h.ref,{$$typeof:i,type:r,key:_,ref:m!==void 0?m:null,props:h}}return Qn.Fragment=f,Qn.jsx=o,Qn.jsxs=o,Qn}var hm;function Ay(){return hm||(hm=1,Gs.exports=Ry()),Gs.exports}var c=Ay(),Qs={exports:{}},ae={};var vm;function zy(){if(vm)return ae;vm=1;var i=Symbol.for("react.transitional.element"),f=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),m=Symbol.for("react.profiler"),h=Symbol.for("react.consumer"),_=Symbol.for("react.context"),R=Symbol.for("react.forward_ref"),S=Symbol.for("react.suspense"),y=Symbol.for("react.memo"),z=Symbol.for("react.lazy"),N=Symbol.for("react.activity"),L=Symbol.iterator;function w(b){return b===null||typeof b!="object"?null:(b=L&&b[L]||b["@@iterator"],typeof b=="function"?b:null)}var V={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Q=Object.assign,B={};function Z(b,M,X){this.props=b,this.context=M,this.refs=B,this.updater=X||V}Z.prototype.isReactComponent={},Z.prototype.setState=function(b,M){if(typeof b!="object"&&typeof b!="function"&&b!=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,b,M,"setState")},Z.prototype.forceUpdate=function(b){this.updater.enqueueForceUpdate(this,b,"forceUpdate")};function F(){}F.prototype=Z.prototype;function $(b,M,X){this.props=b,this.context=M,this.refs=B,this.updater=X||V}var G=$.prototype=new F;G.constructor=$,Q(G,Z.prototype),G.isPureReactComponent=!0;var ne=Array.isArray;function pe(){}var H={H:null,A:null,T:null,S:null},se=Object.prototype.hasOwnProperty;function He(b,M,X){var J=X.ref;return{$$typeof:i,type:b,key:M,ref:J!==void 0?J:null,props:X}}function de(b,M){return He(b.type,M,b.props)}function Qe(b){return typeof b=="object"&&b!==null&&b.$$typeof===i}function Se(b){var M={"=":"=0",":":"=2"};return"$"+b.replace(/[=:]/g,function(X){return M[X]})}var Ee=/\/+/g;function Ce(b,M){return typeof b=="object"&&b!==null&&b.key!=null?Se(""+b.key):M.toString(36)}function De(b){switch(b.status){case"fulfilled":return b.value;case"rejected":throw b.reason;default:switch(typeof b.status=="string"?b.then(pe,pe):(b.status="pending",b.then(function(M){b.status==="pending"&&(b.status="fulfilled",b.value=M)},function(M){b.status==="pending"&&(b.status="rejected",b.reason=M)})),b.status){case"fulfilled":return b.value;case"rejected":throw b.reason}}throw b}function O(b,M,X,J,le){var ue=typeof b;(ue==="undefined"||ue==="boolean")&&(b=null);var ge=!1;if(b===null)ge=!0;else switch(ue){case"bigint":case"string":case"number":ge=!0;break;case"object":switch(b.$$typeof){case i:case f:ge=!0;break;case z:return ge=b._init,O(ge(b._payload),M,X,J,le)}}if(ge)return le=le(b),ge=J===""?"."+Ce(b,0):J,ne(le)?(X="",ge!=null&&(X=ge.replace(Ee,"$&/")+"/"),O(le,M,X,"",function(oe){return oe})):le!=null&&(Qe(le)&&(le=de(le,X+(le.key==null||b&&b.key===le.key?"":(""+le.key).replace(Ee,"$&/")+"/")+ge)),M.push(le)),1;ge=0;var Ve=J===""?".":J+":";if(ne(b))for(var q=0;q>>1,ee=O[_e];if(0>>1;_em(X,P))Jm(le,X)?(O[_e]=le,O[J]=P,_e=J):(O[_e]=X,O[M]=P,_e=M);else if(Jm(le,P))O[_e]=le,O[J]=P,_e=J;else break e}}return Y}function m(O,Y){var P=O.sortIndex-Y.sortIndex;return P!==0?P:O.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 _=Date,R=_.now();i.unstable_now=function(){return _.now()-R}}var S=[],y=[],z=1,N=null,L=3,w=!1,V=!1,Q=!1,B=!1,Z=typeof setTimeout=="function"?setTimeout:null,F=typeof clearTimeout=="function"?clearTimeout:null,$=typeof setImmediate<"u"?setImmediate:null;function G(O){for(var Y=o(y);Y!==null;){if(Y.callback===null)r(y);else if(Y.startTime<=O)r(y),Y.sortIndex=Y.expirationTime,f(S,Y);else break;Y=o(y)}}function ne(O){if(Q=!1,G(O),!V)if(o(S)!==null)V=!0,pe||(pe=!0,Se());else{var Y=o(y);Y!==null&&De(ne,Y.startTime-O)}}var pe=!1,H=-1,se=5,He=-1;function de(){return B?!0:!(i.unstable_now()-HeO&&de());){var _e=N.callback;if(typeof _e=="function"){N.callback=null,L=N.priorityLevel;var ee=_e(N.expirationTime<=O);if(O=i.unstable_now(),typeof ee=="function"){N.callback=ee,G(O),Y=!0;break t}N===o(S)&&r(S),G(O)}else r(S);N=o(S)}if(N!==null)Y=!0;else{var b=o(y);b!==null&&De(ne,b.startTime-O),Y=!1}}break e}finally{N=null,L=P,w=!1}Y=void 0}}finally{Y?Se():pe=!1}}}var Se;if(typeof $=="function")Se=function(){$(Qe)};else if(typeof MessageChannel<"u"){var Ee=new MessageChannel,Ce=Ee.port2;Ee.port1.onmessage=Qe,Se=function(){Ce.postMessage(null)}}else Se=function(){Z(Qe,0)};function De(O,Y){H=Z(function(){O(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(O){O.callback=null},i.unstable_forceFrameRate=function(O){0>O||125_e?(O.sortIndex=P,f(y,O),o(S)===null&&O===o(y)&&(Q?(F(H),H=-1):Q=!0,De(ne,P-_e))):(O.sortIndex=ee,f(S,O),V||w||(V=!0,pe||(pe=!0,Se()))),O},i.unstable_shouldYield=de,i.unstable_wrapCallback=function(O){var Y=L;return function(){var P=L;L=Y;try{return O.apply(this,arguments)}finally{L=P}}}})(Vs)),Vs}var gm;function Cy(){return gm||(gm=1,Zs.exports=Oy()),Zs.exports}var Ks={exports:{}},it={};var bm;function Dy(){if(bm)return it;bm=1;var i=tf();function f(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(f){console.error(f)}}return i(),Ks.exports=Dy(),Ks.exports}var Sm;function Uy(){if(Sm)return Xn;Sm=1;var i=Cy(),f=tf(),o=My();function r(e){var t="https://react.dev/errors/"+e;if(1ee||(e.current=_e[ee],_e[ee]=null,ee--)}function X(e,t){ee++,_e[ee]=e.current,e.current=t}var J=b(null),le=b(null),ue=b(null),ge=b(null);function Ve(e,t){switch(X(ue,t),X(le,e),X(J,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?qd(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=qd(t),e=wd(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}M(J),X(J,e)}function q(){M(J),M(le),M(ue)}function oe(e){e.memoizedState!==null&&X(ge,e);var t=J.current,l=wd(t,e.type);t!==l&&(X(le,e),X(J,l))}function Ue(e){le.current===e&&(M(J),M(le)),ge.current===e&&(M(ge),Bn._currentValue=P)}var K,fe;function re(e){if(K===void 0)try{throw Error()}catch(l){var t=l.stack.trim().match(/\n( *(at )?)/);K=t&&t[1]||"",fe=-1)":-1n||v[a]!==E[n]){var C=` -`+v[a].replace(" at new "," at ");return e.displayName&&C.includes("")&&(C=C.replace("",e.displayName)),C}while(1<=a&&0<=n);break}}}finally{ut=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?re(l):""}function Pe(e,t){switch(e.tag){case 26:case 27:case 5:return re(e.type);case 16:return re("Lazy");case 13:return e.child!==t&&t!==null?re("Suspense Fallback"):re("Suspense");case 19:return re("SuspenseList");case 0:case 15:return st(e.type,!1);case 11:return st(e.type.render,!1);case 1:return st(e.type,!0);case 31:return re("Activity");default:return""}}function Fn(e){try{var t="",l=null;do t+=Pe(e,l),l=e,e=e.return;while(e);return t}catch(a){return` -Error generating stack: `+a.message+` -`+a.stack}}var Ti=Object.prototype.hasOwnProperty,Ri=i.unstable_scheduleCallback,Ai=i.unstable_cancelCallback,uh=i.unstable_shouldYield,ih=i.unstable_requestPaint,yt=i.unstable_now,ch=i.unstable_getCurrentPriorityLevel,mf=i.unstable_ImmediatePriority,hf=i.unstable_UserBlockingPriority,In=i.unstable_NormalPriority,sh=i.unstable_LowPriority,vf=i.unstable_IdlePriority,fh=i.log,rh=i.unstable_setDisableYieldValue,$a=null,pt=null;function hl(e){if(typeof fh=="function"&&rh(e),pt&&typeof pt.setStrictMode=="function")try{pt.setStrictMode($a,e)}catch{}}var gt=Math.clz32?Math.clz32:mh,oh=Math.log,dh=Math.LN2;function mh(e){return e>>>=0,e===0?32:31-(oh(e)/dh|0)|0}var Pn=256,eu=262144,tu=4194304;function Ll(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 lu(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var n=0,u=e.suspendedLanes,s=e.pingedLanes;e=e.warmLanes;var d=a&134217727;return d!==0?(a=d&~u,a!==0?n=Ll(a):(s&=d,s!==0?n=Ll(s):l||(l=d&~e,l!==0&&(n=Ll(l))))):(d=a&~u,d!==0?n=Ll(d):s!==0?n=Ll(s):l||(l=a&~e,l!==0&&(n=Ll(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 Wa(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function hh(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 yf(){var e=tu;return tu<<=1,(tu&62914560)===0&&(tu=4194304),e}function zi(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function Fa(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function vh(e,t,l,a,n,u){var s=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 d=e.entanglements,v=e.expirationTimes,E=e.hiddenUpdates;for(l=s&~l;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var Sh=/[\n"\\]/g;function At(e){return e.replace(Sh,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function Hi(e,t,l,a,n,u,s,d){e.name="",s!=null&&typeof s!="function"&&typeof s!="symbol"&&typeof s!="boolean"?e.type=s:e.removeAttribute("type"),t!=null?s==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+Rt(t)):e.value!==""+Rt(t)&&(e.value=""+Rt(t)):s!=="submit"&&s!=="reset"||e.removeAttribute("value"),t!=null?qi(e,s,Rt(t)):l!=null?qi(e,s,Rt(l)):a!=null&&e.removeAttribute("value"),n==null&&u!=null&&(e.defaultChecked=!!u),n!=null&&(e.checked=n&&typeof n!="function"&&typeof n!="symbol"),d!=null&&typeof d!="function"&&typeof d!="symbol"&&typeof d!="boolean"?e.name=""+Rt(d):e.removeAttribute("name")}function zf(e,t,l,a,n,u,s,d){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)){Ui(e);return}l=l!=null?""+Rt(l):"",t=t!=null?""+Rt(t):l,d||t===e.value||(e.value=t),e.defaultValue=t}a=a??n,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=d?e.checked:!!a,e.defaultChecked=!!a,s!=null&&typeof s!="function"&&typeof s!="symbol"&&typeof s!="boolean"&&(e.name=s),Ui(e)}function qi(e,t,l){t==="number"&&uu(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function oa(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"),Gi=!1;if(Ft)try{var tn={};Object.defineProperty(tn,"passive",{get:function(){Gi=!0}}),window.addEventListener("test",tn,tn),window.removeEventListener("test",tn,tn)}catch{Gi=!1}var yl=null,Qi=null,cu=null;function qf(){if(cu)return cu;var e,t=Qi,l=t.length,a,n="value"in yl?yl.value:yl.textContent,u=n.length;for(e=0;e=nn),Qf=" ",Xf=!1;function Zf(e,t){switch(e){case"keyup":return $h.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Vf(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var va=!1;function Fh(e,t){switch(e){case"compositionend":return Vf(t);case"keypress":return t.which!==32?null:(Xf=!0,Qf);case"textInput":return e=t.data,e===Qf&&Xf?null:e;default:return null}}function Ih(e,t){if(va)return e==="compositionend"||!Ji&&Zf(e,t)?(e=qf(),cu=Qi=yl=null,va=!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=Pf(l)}}function tr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?tr(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function lr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=uu(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=uu(e.document)}return t}function Wi(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 iv=Ft&&"documentMode"in document&&11>=document.documentMode,ya=null,Fi=null,fn=null,Ii=!1;function ar(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;Ii||ya==null||ya!==uu(a)||(a=ya,"selectionStart"in a&&Wi(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}),fn&&sn(fn,a)||(fn=a,a=ei(Fi,"onSelect"),0>=s,n-=s,Zt=1<<32-gt(t)+n|l<ce?(ye=W,W=null):ye=W.sibling;var je=T(x,W,j[ce],D);if(je===null){W===null&&(W=ye);break}e&&W&&je.alternate===null&&t(x,W),g=u(je,g,ce),xe===null?I=je:xe.sibling=je,xe=je,W=ye}if(ce===j.length)return l(x,W),be&&Pt(x,ce),I;if(W===null){for(;cece?(ye=W,W=null):ye=W.sibling;var Bl=T(x,W,je.value,D);if(Bl===null){W===null&&(W=ye);break}e&&W&&Bl.alternate===null&&t(x,W),g=u(Bl,g,ce),xe===null?I=Bl:xe.sibling=Bl,xe=Bl,W=ye}if(je.done)return l(x,W),be&&Pt(x,ce),I;if(W===null){for(;!je.done;ce++,je=j.next())je=U(x,je.value,D),je!==null&&(g=u(je,g,ce),xe===null?I=je:xe.sibling=je,xe=je);return be&&Pt(x,ce),I}for(W=a(W);!je.done;ce++,je=j.next())je=A(W,x,ce,je.value,D),je!==null&&(e&&je.alternate!==null&&W.delete(je.key===null?ce:je.key),g=u(je,g,ce),xe===null?I=je:xe.sibling=je,xe=je);return e&&W.forEach(function(Ty){return t(x,Ty)}),be&&Pt(x,ce),I}function Oe(x,g,j,D){if(typeof j=="object"&&j!==null&&j.type===Q&&j.key===null&&(j=j.props.children),typeof j=="object"&&j!==null){switch(j.$$typeof){case w:e:{for(var I=j.key;g!==null;){if(g.key===I){if(I=j.type,I===Q){if(g.tag===7){l(x,g.sibling),D=n(g,j.props.children),D.return=x,x=D;break e}}else if(g.elementType===I||typeof I=="object"&&I!==null&&I.$$typeof===se&&Wl(I)===g.type){l(x,g.sibling),D=n(g,j.props),vn(D,j),D.return=x,x=D;break e}l(x,g);break}else t(x,g);g=g.sibling}j.type===Q?(D=Vl(j.props.children,x.mode,D,j.key),D.return=x,x=D):(D=pu(j.type,j.key,j.props,null,x.mode,D),vn(D,j),D.return=x,x=D)}return s(x);case V:e:{for(I=j.key;g!==null;){if(g.key===I)if(g.tag===4&&g.stateNode.containerInfo===j.containerInfo&&g.stateNode.implementation===j.implementation){l(x,g.sibling),D=n(g,j.children||[]),D.return=x,x=D;break e}else{l(x,g);break}else t(x,g);g=g.sibling}D=uc(j,x.mode,D),D.return=x,x=D}return s(x);case se:return j=Wl(j),Oe(x,g,j,D)}if(De(j))return k(x,g,j,D);if(Se(j)){if(I=Se(j),typeof I!="function")throw Error(r(150));return j=I.call(j),te(x,g,j,D)}if(typeof j.then=="function")return Oe(x,g,Nu(j),D);if(j.$$typeof===$)return Oe(x,g,_u(x,j),D);Eu(x,j)}return typeof j=="string"&&j!==""||typeof j=="number"||typeof j=="bigint"?(j=""+j,g!==null&&g.tag===6?(l(x,g.sibling),D=n(g,j),D.return=x,x=D):(l(x,g),D=nc(j,x.mode,D),D.return=x,x=D),s(x)):l(x,g)}return function(x,g,j,D){try{hn=0;var I=Oe(x,g,j,D);return Ra=null,I}catch(W){if(W===Ta||W===xu)throw W;var xe=_t(29,W,null,x.mode);return xe.lanes=D,xe.return=x,xe}}}var Il=Tr(!0),Rr=Tr(!1),Sl=!1;function pc(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function gc(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 xl(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function jl(e,t,l){var a=e.updateQueue;if(a===null)return null;if(a=a.shared,(Ne&2)!==0){var n=a.pending;return n===null?t.next=t:(t.next=n.next,n.next=t),a.pending=t,t=yu(e),rr(e,null,l),t}return vu(e,a,t,l),yu(e)}function yn(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,gf(e,l)}}function bc(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 s={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};u===null?n=u=s:u=u.next=s,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 _c=!1;function pn(){if(_c){var e=Ea;if(e!==null)throw e}}function gn(e,t,l,a){_c=!1;var n=e.updateQueue;Sl=!1;var u=n.firstBaseUpdate,s=n.lastBaseUpdate,d=n.shared.pending;if(d!==null){n.shared.pending=null;var v=d,E=v.next;v.next=null,s===null?u=E:s.next=E,s=v;var C=e.alternate;C!==null&&(C=C.updateQueue,d=C.lastBaseUpdate,d!==s&&(d===null?C.firstBaseUpdate=E:d.next=E,C.lastBaseUpdate=v))}if(u!==null){var U=n.baseState;s=0,C=E=v=null,d=u;do{var T=d.lane&-536870913,A=T!==d.lane;if(A?(ve&T)===T:(a&T)===T){T!==0&&T===Na&&(_c=!0),C!==null&&(C=C.next={lane:0,tag:d.tag,payload:d.payload,callback:null,next:null});e:{var k=e,te=d;T=t;var Oe=l;switch(te.tag){case 1:if(k=te.payload,typeof k=="function"){U=k.call(Oe,U,T);break e}U=k;break e;case 3:k.flags=k.flags&-65537|128;case 0:if(k=te.payload,T=typeof k=="function"?k.call(Oe,U,T):k,T==null)break e;U=N({},U,T);break e;case 2:Sl=!0}}T=d.callback,T!==null&&(e.flags|=64,A&&(e.flags|=8192),A=n.callbacks,A===null?n.callbacks=[T]:A.push(T))}else A={lane:T,tag:d.tag,payload:d.payload,callback:d.callback,next:null},C===null?(E=C=A,v=U):C=C.next=A,s|=T;if(d=d.next,d===null){if(d=n.shared.pending,d===null)break;A=d,d=A.next,A.next=null,n.lastBaseUpdate=A,n.shared.pending=null}}while(!0);C===null&&(v=U),n.baseState=v,n.firstBaseUpdate=E,n.lastBaseUpdate=C,u===null&&(n.shared.lanes=0),Al|=s,e.lanes=s,e.memoizedState=U}}function Ar(e,t){if(typeof e!="function")throw Error(r(191,e));e.call(t)}function zr(e,t){var l=e.callbacks;if(l!==null)for(e.callbacks=null,e=0;eu?u:8;var s=O.T,d={};O.T=d,Lc(e,!1,t,l);try{var v=n(),E=O.S;if(E!==null&&E(d,v),v!==null&&typeof v=="object"&&typeof v.then=="function"){var C=vv(v,a);Sn(e,t,C,Et(e))}else Sn(e,t,a,Et(e))}catch(U){Sn(e,t,{then:function(){},status:"rejected",reason:U},Et())}finally{Y.p=u,s!==null&&d.types!==null&&(s.types=d.types),O.T=s}}function Sv(){}function wc(e,t,l,a){if(e.tag!==5)throw Error(r(476));var n=co(e).queue;io(e,n,t,P,l===null?Sv:function(){return so(e),l(a)})}function co(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:P,baseState:P,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:al,lastRenderedState:P},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:al,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function so(e){var t=co(e);t.next===null&&(t=e.alternate.memoizedState),Sn(e,t.next.queue,{},Et())}function Bc(){return lt(Bn)}function fo(){return Ze().memoizedState}function ro(){return Ze().memoizedState}function xv(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=Et();e=xl(l);var a=jl(t,e,l);a!==null&&(vt(a,t,l),yn(a,t,l)),t={cache:mc()},e.payload=t;return}t=t.return}}function jv(e,t,l){var a=Et();l={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},Hu(e)?mo(t,l):(l=lc(e,t,l,a),l!==null&&(vt(l,e,a),ho(l,t,a)))}function oo(e,t,l){var a=Et();Sn(e,t,l,a)}function Sn(e,t,l,a){var n={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(Hu(e))mo(t,n);else{var u=e.alternate;if(e.lanes===0&&(u===null||u.lanes===0)&&(u=t.lastRenderedReducer,u!==null))try{var s=t.lastRenderedState,d=u(s,l);if(n.hasEagerState=!0,n.eagerState=d,bt(d,s))return vu(e,t,n,0),Me===null&&hu(),!1}catch{}if(l=lc(e,t,n,a),l!==null)return vt(l,e,a),ho(l,t,a),!0}return!1}function Lc(e,t,l,a){if(a={lane:2,revertLane:ps(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},Hu(e)){if(t)throw Error(r(479))}else t=lc(e,l,a,2),t!==null&&vt(t,e,2)}function Hu(e){var t=e.alternate;return e===ie||t!==null&&t===ie}function mo(e,t){za=Au=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function ho(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,gf(e,l)}}var xn={readContext:lt,use:Cu,useCallback:Ye,useContext:Ye,useEffect:Ye,useImperativeHandle:Ye,useLayoutEffect:Ye,useInsertionEffect:Ye,useMemo:Ye,useReducer:Ye,useRef:Ye,useState:Ye,useDebugValue:Ye,useDeferredValue:Ye,useTransition:Ye,useSyncExternalStore:Ye,useId:Ye,useHostTransitionStatus:Ye,useFormState:Ye,useActionState:Ye,useOptimistic:Ye,useMemoCache:Ye,useCacheRefresh:Ye};xn.useEffectEvent=Ye;var vo={readContext:lt,use:Cu,useCallback:function(e,t){return ct().memoizedState=[e,t===void 0?null:t],e},useContext:lt,useEffect:Fr,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,Mu(4194308,4,to.bind(null,t,e),l)},useLayoutEffect:function(e,t){return Mu(4194308,4,e,t)},useInsertionEffect:function(e,t){Mu(4,2,e,t)},useMemo:function(e,t){var l=ct();t=t===void 0?null:t;var a=e();if(Pl){hl(!0);try{e()}finally{hl(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=ct();if(l!==void 0){var n=l(t);if(Pl){hl(!0);try{l(t)}finally{hl(!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=jv.bind(null,ie,e),[a.memoizedState,e]},useRef:function(e){var t=ct();return e={current:e},t.memoizedState=e},useState:function(e){e=Dc(e);var t=e.queue,l=oo.bind(null,ie,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:Hc,useDeferredValue:function(e,t){var l=ct();return qc(l,e,t)},useTransition:function(){var e=Dc(!1);return e=io.bind(null,ie,e.queue,!0,!1),ct().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=ie,n=ct();if(be){if(l===void 0)throw Error(r(407));l=l()}else{if(l=t(),Me===null)throw Error(r(349));(ve&127)!==0||Hr(a,t,l)}n.memoizedState=l;var u={value:l,getSnapshot:t};return n.queue=u,Fr(wr.bind(null,a,u,e),[e]),a.flags|=2048,Ca(9,{destroy:void 0},qr.bind(null,a,u,l,t),null),l},useId:function(){var e=ct(),t=Me.identifierPrefix;if(be){var l=Vt,a=Zt;l=(a&~(1<<32-gt(a)-1)).toString(32)+l,t="_"+t+"R_"+l,l=zu++,0<\/script>",u=u.removeChild(u.firstChild);break;case"select":u=typeof a.is=="string"?s.createElement("select",{is:a.is}):s.createElement("select"),a.multiple?u.multiple=!0:a.size&&(u.size=a.size);break;default:u=typeof a.is=="string"?s.createElement(n,{is:a.is}):s.createElement(n)}}u[et]=t,u[ft]=a;e:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)u.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break e;for(;s.sibling===null;){if(s.return===null||s.return===t)break e;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=u;e:switch(nt(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&&ul(t)}}return we(t),Pc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,l),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==a&&ul(t);else{if(typeof a!="string"&&t.stateNode===null)throw Error(r(166));if(e=ue.current,xa(t)){if(e=t.stateNode,l=t.memoizedProps,a=null,n=tt,n!==null)switch(n.tag){case 27:case 5:a=n.memoizedProps}e[et]=t,e=!!(e.nodeValue===l||a!==null&&a.suppressHydrationWarning===!0||Ud(e.nodeValue,l)),e||bl(t,!0)}else e=ti(e).createTextNode(a),e[et]=t,t.stateNode=e}return we(t),null;case 31:if(l=t.memoizedState,e===null||e.memoizedState!==null){if(a=xa(t),l!==null){if(e===null){if(!a)throw Error(r(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(r(557));e[et]=t}else Kl(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;we(t),e=!1}else l=fc(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),e=!0;if(!e)return t.flags&256?(xt(t),t):(xt(t),null);if((t.flags&128)!==0)throw Error(r(558))}return we(t),null;case 13:if(a=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(n=xa(t),a!==null&&a.dehydrated!==null){if(e===null){if(!n)throw Error(r(318));if(n=t.memoizedState,n=n!==null?n.dehydrated:null,!n)throw Error(r(317));n[et]=t}else Kl(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;we(t),n=!1}else n=fc(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),n=!0;if(!n)return t.flags&256?(xt(t),t):(xt(t),null)}return xt(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),Yu(t,t.updateQueue),we(t),null);case 4:return q(),e===null&&Ss(t.stateNode.containerInfo),we(t),null;case 10:return tl(t.type),we(t),null;case 19:if(M(Xe),a=t.memoizedState,a===null)return we(t),null;if(n=(t.flags&128)!==0,u=a.rendering,u===null)if(n)Nn(a,!1);else{if(Ge!==0||e!==null&&(e.flags&128)!==0)for(e=t.child;e!==null;){if(u=Ru(e),u!==null){for(t.flags|=128,Nn(a,!1),e=u.updateQueue,t.updateQueue=e,Yu(t,e),t.subtreeFlags=0,e=l,l=t.child;l!==null;)or(l,e),l=l.sibling;return X(Xe,Xe.current&1|2),be&&Pt(t,a.treeForkCount),t.child}e=e.sibling}a.tail!==null&&yt()>Vu&&(t.flags|=128,n=!0,Nn(a,!1),t.lanes=4194304)}else{if(!n)if(e=Ru(u),e!==null){if(t.flags|=128,n=!0,e=e.updateQueue,t.updateQueue=e,Yu(t,e),Nn(a,!0),a.tail===null&&a.tailMode==="hidden"&&!u.alternate&&!be)return we(t),null}else 2*yt()-a.renderingStartTime>Vu&&l!==536870912&&(t.flags|=128,n=!0,Nn(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=yt(),e.sibling=null,l=Xe.current,X(Xe,n?l&1|2:l&1),be&&Pt(t,a.treeForkCount),e):(we(t),null);case 22:case 23:return xt(t),xc(),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&&(we(t),t.subtreeFlags&6&&(t.flags|=8192)):we(t),l=t.updateQueue,l!==null&&Yu(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&&M($l),null;case 24:return l=null,e!==null&&(l=e.memoizedState.cache),t.memoizedState.cache!==l&&(t.flags|=2048),tl(Ke),we(t),null;case 25:return null;case 30:return null}throw Error(r(156,t.tag))}function Av(e,t){switch(cc(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return tl(Ke),q(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return Ue(t),null;case 31:if(t.memoizedState!==null){if(xt(t),t.alternate===null)throw Error(r(340));Kl()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(xt(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(r(340));Kl()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return M(Xe),null;case 4:return q(),null;case 10:return tl(t.type),null;case 22:case 23:return xt(t),xc(),e!==null&&M($l),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return tl(Ke),null;case 25:return null;default:return null}}function Lo(e,t){switch(cc(t),t.tag){case 3:tl(Ke),q();break;case 26:case 27:case 5:Ue(t);break;case 4:q();break;case 31:t.memoizedState!==null&&xt(t);break;case 13:xt(t);break;case 19:M(Xe);break;case 10:tl(t.type);break;case 22:case 23:xt(t),xc(),e!==null&&M($l);break;case 24:tl(Ke)}}function En(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,s=l.inst;a=u(),s.destroy=a}l=l.next}while(l!==n)}}catch(d){Re(t,t.return,d)}}function Tl(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 s=a.inst,d=s.destroy;if(d!==void 0){s.destroy=void 0,n=t;var v=l,E=d;try{E()}catch(C){Re(n,v,C)}}}a=a.next}while(a!==u)}}catch(C){Re(t,t.return,C)}}function Yo(e){var t=e.updateQueue;if(t!==null){var l=e.stateNode;try{zr(t,l)}catch(a){Re(e,e.return,a)}}}function Go(e,t,l){l.props=ea(e.type,e.memoizedProps),l.state=e.memoizedState;try{l.componentWillUnmount()}catch(a){Re(e,t,a)}}function Tn(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){Re(e,t,n)}}function Kt(e,t){var l=e.ref,a=e.refCleanup;if(l!==null)if(typeof a=="function")try{a()}catch(n){Re(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){Re(e,t,n)}else l.current=null}function Qo(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){Re(e,e.return,n)}}function es(e,t,l){try{var a=e.stateNode;Wv(a,e.type,l,t),a[ft]=t}catch(n){Re(e,e.return,n)}}function Xo(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Ml(e.type)||e.tag===4}function ts(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Xo(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&&Ml(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 ls(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=Wt));else if(a!==4&&(a===27&&Ml(e.type)&&(l=e.stateNode,t=null),e=e.child,e!==null))for(ls(e,t,l),e=e.sibling;e!==null;)ls(e,t,l),e=e.sibling}function Gu(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&&Ml(e.type)&&(l=e.stateNode),e=e.child,e!==null))for(Gu(e,t,l),e=e.sibling;e!==null;)Gu(e,t,l),e=e.sibling}function Zo(e){var t=e.stateNode,l=e.memoizedProps;try{for(var a=e.type,n=t.attributes;n.length;)t.removeAttributeNode(n[0]);nt(t,a,l),t[et]=e,t[ft]=l}catch(u){Re(e,e.return,u)}}var il=!1,$e=!1,as=!1,Vo=typeof WeakSet=="function"?WeakSet:Set,Ie=null;function zv(e,t){if(e=e.containerInfo,Ns=si,e=lr(e),Wi(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 s=0,d=-1,v=-1,E=0,C=0,U=e,T=null;t:for(;;){for(var A;U!==l||n!==0&&U.nodeType!==3||(d=s+n),U!==u||a!==0&&U.nodeType!==3||(v=s+a),U.nodeType===3&&(s+=U.nodeValue.length),(A=U.firstChild)!==null;)T=U,U=A;for(;;){if(U===e)break t;if(T===l&&++E===n&&(d=s),T===u&&++C===a&&(v=s),(A=U.nextSibling)!==null)break;U=T,T=U.parentNode}U=A}l=d===-1||v===-1?null:{start:d,end:v}}else l=null}l=l||{start:0,end:0}}else l=null;for(Es={focusedElem:e,selectionRange:l},si=!1,Ie=t;Ie!==null;)if(t=Ie,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,Ie=e;else for(;Ie!==null;){switch(t=Ie,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"))),nt(u,a,l),u[et]=e,Fe(u),a=u;break e;case"link":var s=Fd("link","href",n).get(a+(l.href||""));if(s){for(var d=0;dOe&&(s=Oe,Oe=te,te=s);var x=er(d,te),g=er(d,Oe);if(x&&g&&(A.rangeCount!==1||A.anchorNode!==x.node||A.anchorOffset!==x.offset||A.focusNode!==g.node||A.focusOffset!==g.offset)){var j=U.createRange();j.setStart(x.node,x.offset),A.removeAllRanges(),te>Oe?(A.addRange(j),A.extend(g.node,g.offset)):(j.setEnd(g.node,g.offset),A.addRange(j))}}}}for(U=[],A=d;A=A.parentNode;)A.nodeType===1&&U.push({element:A,left:A.scrollLeft,top:A.scrollTop});for(typeof d.focus=="function"&&d.focus(),d=0;dl?32:l,O.T=null,l=rs,rs=null;var u=Ol,s=ol;if(We=0,qa=Ol=null,ol=0,(Ne&6)!==0)throw Error(r(331));var d=Ne;if(Ne|=4,ld(u.current),Po(u,u.current,s,l),Ne=d,Dn(0,!1),pt&&typeof pt.onPostCommitFiberRoot=="function")try{pt.onPostCommitFiberRoot($a,u)}catch{}return!0}finally{Y.p=n,O.T=a,_d(e,t)}}function xd(e,t,l){t=Ot(l,t),t=Xc(e.stateNode,t,2),e=jl(e,t,2),e!==null&&(Fa(e,2),Jt(e))}function Re(e,t,l){if(e.tag===3)xd(e,e,l);else for(;t!==null;){if(t.tag===3){xd(t,e,l);break}else if(t.tag===1){var a=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(zl===null||!zl.has(a))){e=Ot(l,e),l=jo(2),a=jl(t,l,2),a!==null&&(No(l,a,t,e),Fa(a,2),Jt(a));break}}t=t.return}}function hs(e,t,l){var a=e.pingCache;if(a===null){a=e.pingCache=new Dv;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)||(is=!0,n.add(l),e=wv.bind(null,e,t,l),t.then(e,e))}function wv(e,t,l){var a=e.pingCache;a!==null&&a.delete(t),e.pingedLanes|=e.suspendedLanes&l,e.warmLanes&=~l,Me===e&&(ve&l)===l&&(Ge===4||Ge===3&&(ve&62914560)===ve&&300>yt()-Zu?(Ne&2)===0&&wa(e,0):cs|=l,Ha===ve&&(Ha=0)),Jt(e)}function jd(e,t){t===0&&(t=yf()),e=Zl(e,t),e!==null&&(Fa(e,t),Jt(e))}function Bv(e){var t=e.memoizedState,l=0;t!==null&&(l=t.retryLane),jd(e,l)}function Lv(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(r(314))}a!==null&&a.delete(t),jd(e,l)}function Yv(e,t){return Ri(e,t)}var Fu=null,La=null,vs=!1,Iu=!1,ys=!1,Dl=0;function Jt(e){e!==La&&e.next===null&&(La===null?Fu=La=e:La=La.next=e),Iu=!0,vs||(vs=!0,Qv())}function Dn(e,t){if(!ys&&Iu){ys=!0;do for(var l=!1,a=Fu;a!==null;){if(e!==0){var n=a.pendingLanes;if(n===0)var u=0;else{var s=a.suspendedLanes,d=a.pingedLanes;u=(1<<31-gt(42|e)+1)-1,u&=n&~(s&~d),u=u&201326741?u&201326741|1:u?u|2:0}u!==0&&(l=!0,Rd(a,u))}else u=ve,u=lu(a,a===Me?u:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(u&3)===0||Wa(a,u)||(l=!0,Rd(a,u));a=a.next}while(l);ys=!1}}function Gv(){Nd()}function Nd(){Iu=vs=!1;var e=0;Dl!==0&&Iv()&&(e=Dl);for(var t=yt(),l=null,a=Fu;a!==null;){var n=a.next,u=Ed(a,t);u===0?(a.next=null,l===null?Fu=n:l.next=n,n===null&&(La=l)):(l=a,(e!==0||(u&3)!==0)&&(Iu=!0)),a=n}We!==0&&We!==5||Dn(e),Dl!==0&&(Dl=0)}function Ed(e,t){for(var l=e.suspendedLanes,a=e.pingedLanes,n=e.expirationTimes,u=e.pendingLanes&-62914561;0d)break;var C=v.transferSize,U=v.initiatorType;C&&Hd(U)&&(v=v.responseEnd,s+=C*(v"u"?null:document;function Jd(e,t,l){var a=Ya;if(a&&typeof t=="string"&&t){var n=At(t);n='link[rel="'+e+'"][href="'+n+'"]',typeof l=="string"&&(n+='[crossorigin="'+l+'"]'),Kd.has(n)||(Kd.add(n),e={rel:e,crossOrigin:l,href:t},a.querySelector(n)===null&&(t=a.createElement("link"),nt(t,"link",e),Fe(t),a.head.appendChild(t)))}}function cy(e){dl.D(e),Jd("dns-prefetch",e,null)}function sy(e,t){dl.C(e,t),Jd("preconnect",e,t)}function fy(e,t,l){dl.L(e,t,l);var a=Ya;if(a&&e&&t){var n='link[rel="preload"][as="'+At(t)+'"]';t==="image"&&l&&l.imageSrcSet?(n+='[imagesrcset="'+At(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(n+='[imagesizes="'+At(l.imageSizes)+'"]')):n+='[href="'+At(e)+'"]';var u=n;switch(t){case"style":u=Ga(e);break;case"script":u=Qa(e)}qt.has(u)||(e=N({rel:"preload",href:t==="image"&&l&&l.imageSrcSet?void 0:e,as:t},l),qt.set(u,e),a.querySelector(n)!==null||t==="style"&&a.querySelector(qn(u))||t==="script"&&a.querySelector(wn(u))||(t=a.createElement("link"),nt(t,"link",e),Fe(t),a.head.appendChild(t)))}}function ry(e,t){dl.m(e,t);var l=Ya;if(l&&e){var a=t&&typeof t.as=="string"?t.as:"script",n='link[rel="modulepreload"][as="'+At(a)+'"][href="'+At(e)+'"]',u=n;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":u=Qa(e)}if(!qt.has(u)&&(e=N({rel:"modulepreload",href:e},t),qt.set(u,e),l.querySelector(n)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(wn(u)))return}a=l.createElement("link"),nt(a,"link",e),Fe(a),l.head.appendChild(a)}}}function oy(e,t,l){dl.S(e,t,l);var a=Ya;if(a&&e){var n=fa(a).hoistableStyles,u=Ga(e);t=t||"default";var s=n.get(u);if(!s){var d={loading:0,preload:null};if(s=a.querySelector(qn(u)))d.loading=5;else{e=N({rel:"stylesheet",href:e,"data-precedence":t},l),(l=qt.get(u))&&Ds(e,l);var v=s=a.createElement("link");Fe(v),nt(v,"link",e),v._p=new Promise(function(E,C){v.onload=E,v.onerror=C}),v.addEventListener("load",function(){d.loading|=1}),v.addEventListener("error",function(){d.loading|=2}),d.loading|=4,ai(s,t,a)}s={type:"stylesheet",instance:s,count:1,state:d},n.set(u,s)}}}function dy(e,t){dl.X(e,t);var l=Ya;if(l&&e){var a=fa(l).hoistableScripts,n=Qa(e),u=a.get(n);u||(u=l.querySelector(wn(n)),u||(e=N({src:e,async:!0},t),(t=qt.get(n))&&Ms(e,t),u=l.createElement("script"),Fe(u),nt(u,"link",e),l.head.appendChild(u)),u={type:"script",instance:u,count:1,state:null},a.set(n,u))}}function my(e,t){dl.M(e,t);var l=Ya;if(l&&e){var a=fa(l).hoistableScripts,n=Qa(e),u=a.get(n);u||(u=l.querySelector(wn(n)),u||(e=N({src:e,async:!0,type:"module"},t),(t=qt.get(n))&&Ms(e,t),u=l.createElement("script"),Fe(u),nt(u,"link",e),l.head.appendChild(u)),u={type:"script",instance:u,count:1,state:null},a.set(n,u))}}function kd(e,t,l,a){var n=(n=ue.current)?li(n):null;if(!n)throw Error(r(446));switch(e){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(t=Ga(l.href),l=fa(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=Ga(l.href);var u=fa(n).hoistableStyles,s=u.get(e);if(s||(n=n.ownerDocument||n,s={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},u.set(e,s),(u=n.querySelector(qn(e)))&&!u._p&&(s.instance=u,s.state.loading=5),qt.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},qt.set(e,l),u||hy(n,e,l,s.state))),t&&a===null)throw Error(r(528,""));return s}if(t&&a!==null)throw Error(r(529,""));return null;case"script":return t=l.async,l=l.src,typeof l=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=Qa(l),l=fa(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(r(444,e))}}function Ga(e){return'href="'+At(e)+'"'}function qn(e){return'link[rel="stylesheet"]['+e+"]"}function $d(e){return N({},e,{"data-precedence":e.precedence,precedence:null})}function hy(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}),nt(t,"link",l),Fe(t),e.head.appendChild(t))}function Qa(e){return'[src="'+At(e)+'"]'}function wn(e){return"script[async]"+e}function Wd(e,t,l){if(t.count++,t.instance===null)switch(t.type){case"style":var a=e.querySelector('style[data-href~="'+At(l.href)+'"]');if(a)return t.instance=a,Fe(a),a;var n=N({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(e.ownerDocument||e).createElement("style"),Fe(a),nt(a,"style",n),ai(a,l.precedence,e),t.instance=a;case"stylesheet":n=Ga(l.href);var u=e.querySelector(qn(n));if(u)return t.state.loading|=4,t.instance=u,Fe(u),u;a=$d(l),(n=qt.get(n))&&Ds(a,n),u=(e.ownerDocument||e).createElement("link"),Fe(u);var s=u;return s._p=new Promise(function(d,v){s.onload=d,s.onerror=v}),nt(u,"link",a),t.state.loading|=4,ai(u,l.precedence,e),t.instance=u;case"script":return u=Qa(l.src),(n=e.querySelector(wn(u)))?(t.instance=n,Fe(n),n):(a=l,(n=qt.get(u))&&(a=N({},l),Ms(a,n)),e=e.ownerDocument||e,n=e.createElement("script"),Fe(n),nt(n,"link",a),e.head.appendChild(n),t.instance=n);case"void":return null;default:throw Error(r(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(a=t.instance,t.state.loading|=4,ai(a,l.precedence,e));return t.instance}function ai(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,s=0;s title"):null)}function vy(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 Pd(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function yy(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=Ga(a.href),u=t.querySelector(qn(n));if(u){t=u._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=ui.bind(e),t.then(e,e)),l.state.loading|=4,l.instance=u,Fe(u);return}u=t.ownerDocument||t,a=$d(a),(n=qt.get(n))&&Ds(a,n),u=u.createElement("link"),Fe(u);var s=u;s._p=new Promise(function(d,v){s.onload=d,s.onerror=v}),nt(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=ui.bind(e),t.addEventListener("load",l),t.addEventListener("error",l))}}var Us=0;function py(e,t){return e.stylesheets&&e.count===0&&ci(e,e.stylesheets),0Us?50:800)+t);return e.unsuspend=l,function(){e.unsuspend=null,clearTimeout(a),clearTimeout(n)}}:null}function ui(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)ci(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var ii=null;function ci(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,ii=new Map,t.forEach(gy,e),ii=null,ui.call(e))}function gy(e,t){if(!(t.state.loading&4)){var l=ii.get(e);if(l)var a=l.get(null);else{l=new Map,ii.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(f){console.error(f)}}return i(),Xs.exports=Uy(),Xs.exports}var qy=Hy();var jm="popstate";function Nm(i){return typeof i=="object"&&i!=null&&"pathname"in i&&"search"in i&&"hash"in i&&"state"in i&&"key"in i}function wy(i={}){function f(m,h){let{pathname:_="/",search:R="",hash:S=""}=ua(m.location.hash.substring(1));return!_.startsWith("/")&&!_.startsWith(".")&&(_="/"+_),Is("",{pathname:_,search:R,hash:S},h.state&&h.state.usr||null,h.state&&h.state.key||"default")}function o(m,h){let _=m.document.querySelector("base"),R="";if(_&&_.getAttribute("href")){let S=m.location.href,y=S.indexOf("#");R=y===-1?S:S.slice(0,y)}return R+"#"+(typeof h=="string"?h:kn(h))}function r(m,h){Bt(m.pathname.charAt(0)==="/",`relative pathnames are not supported in hash history.push(${JSON.stringify(h)})`)}return Ly(f,o,r,i)}function Le(i,f){if(i===!1||i===null||typeof i>"u")throw new Error(f)}function Bt(i,f){if(!i){typeof console<"u"&&console.warn(f);try{throw new Error(f)}catch{}}}function By(){return Math.random().toString(36).substring(2,10)}function Em(i,f){return{usr:i.state,key:i.key,idx:f,masked:i.unstable_mask?{pathname:i.pathname,search:i.search,hash:i.hash}:void 0}}function Is(i,f,o=null,r,m){return{pathname:typeof i=="string"?i:i.pathname,search:"",hash:"",...typeof f=="string"?ua(f):f,state:o,key:f&&f.key||r||By(),unstable_mask:m}}function kn({pathname:i="/",search:f="",hash:o=""}){return f&&f!=="?"&&(i+=f.charAt(0)==="?"?f:"?"+f),o&&o!=="#"&&(i+=o.charAt(0)==="#"?o:"#"+o),i}function ua(i){let f={};if(i){let o=i.indexOf("#");o>=0&&(f.hash=i.substring(o),i=i.substring(0,o));let r=i.indexOf("?");r>=0&&(f.search=i.substring(r),i=i.substring(0,r)),i&&(f.pathname=i)}return f}function Ly(i,f,o,r={}){let{window:m=document.defaultView,v5Compat:h=!1}=r,_=m.history,R="POP",S=null,y=z();y==null&&(y=0,_.replaceState({..._.state,idx:y},""));function z(){return(_.state||{idx:null}).idx}function N(){R="POP";let B=z(),Z=B==null?null:B-y;y=B,S&&S({action:R,location:Q.location,delta:Z})}function L(B,Z){R="PUSH";let F=Nm(B)?B:Is(Q.location,B,Z);o&&o(F,B),y=z()+1;let $=Em(F,y),G=Q.createHref(F.unstable_mask||F);try{_.pushState($,"",G)}catch(ne){if(ne instanceof DOMException&&ne.name==="DataCloneError")throw ne;m.location.assign(G)}h&&S&&S({action:R,location:Q.location,delta:1})}function w(B,Z){R="REPLACE";let F=Nm(B)?B:Is(Q.location,B,Z);o&&o(F,B),y=z();let $=Em(F,y),G=Q.createHref(F.unstable_mask||F);_.replaceState($,"",G),h&&S&&S({action:R,location:Q.location,delta:0})}function V(B){return Yy(B)}let Q={get action(){return R},get location(){return i(m,_)},listen(B){if(S)throw new Error("A history only accepts one active listener");return m.addEventListener(jm,N),S=B,()=>{m.removeEventListener(jm,N),S=null}},createHref(B){return f(m,B)},createURL:V,encodeLocation(B){let Z=V(B);return{pathname:Z.pathname,search:Z.search,hash:Z.hash}},push:L,replace:w,go(B){return _.go(B)}};return Q}function Yy(i,f=!1){let o="http://localhost";typeof window<"u"&&(o=window.location.origin!=="null"?window.location.origin:window.location.href),Le(o,"No window.location.(origin|href) available to create URL");let r=typeof i=="string"?i:kn(i);return r=r.replace(/ $/,"%20"),!f&&r.startsWith("//")&&(r=o+r),new URL(r,o)}function Um(i,f,o="/"){return Gy(i,f,o,!1)}function Gy(i,f,o,r){let m=typeof f=="string"?ua(f):f,h=ml(m.pathname||"/",o);if(h==null)return null;let _=Hm(i);Qy(_);let R=null;for(let S=0;R==null&&S<_.length;++S){let y=Py(h);R=Fy(_[S],y,r)}return R}function Hm(i,f=[],o=[],r="",m=!1){let h=(_,R,S=m,y)=>{let z={relativePath:y===void 0?_.path||"":y,caseSensitive:_.caseSensitive===!0,childrenIndex:R,route:_};if(z.relativePath.startsWith("/")){if(!z.relativePath.startsWith(r)&&S)return;Le(z.relativePath.startsWith(r),`Absolute route path "${z.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),z.relativePath=z.relativePath.slice(r.length)}let N=Qt([r,z.relativePath]),L=o.concat(z);_.children&&_.children.length>0&&(Le(_.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${N}".`),Hm(_.children,f,L,N,S)),!(_.path==null&&!_.index)&&f.push({path:N,score:$y(N,_.index),routesMeta:L})};return i.forEach((_,R)=>{if(_.path===""||!_.path?.includes("?"))h(_,R);else for(let S of qm(_.path))h(_,R,!0,S)}),f}function qm(i){let f=i.split("/");if(f.length===0)return[];let[o,...r]=f,m=o.endsWith("?"),h=o.replace(/\?$/,"");if(r.length===0)return m?[h,""]:[h];let _=qm(r.join("/")),R=[];return R.push(..._.map(S=>S===""?h:[h,S].join("/"))),m&&R.push(..._),R.map(S=>i.startsWith("/")&&S===""?"/":S)}function Qy(i){i.sort((f,o)=>f.score!==o.score?o.score-f.score:Wy(f.routesMeta.map(r=>r.childrenIndex),o.routesMeta.map(r=>r.childrenIndex)))}var Xy=/^:[\w-]+$/,Zy=3,Vy=2,Ky=1,Jy=10,ky=-2,Tm=i=>i==="*";function $y(i,f){let o=i.split("/"),r=o.length;return o.some(Tm)&&(r+=ky),f&&(r+=Vy),o.filter(m=>!Tm(m)).reduce((m,h)=>m+(Xy.test(h)?Zy:h===""?Ky:Jy),r)}function Wy(i,f){return i.length===f.length&&i.slice(0,-1).every((r,m)=>r===f[m])?i[i.length-1]-f[f.length-1]:0}function Fy(i,f,o=!1){let{routesMeta:r}=i,m={},h="/",_=[];for(let R=0;R{if(z==="*"){let V=R[L]||"";_=h.slice(0,h.length-V.length).replace(/(.)\/+$/,"$1")}const w=R[L];return N&&!w?y[z]=void 0:y[z]=(w||"").replace(/%2F/g,"/"),y},{}),pathname:h,pathnameBase:_,pattern:i}}function Iy(i,f=!1,o=!0){Bt(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 r=[],m="^"+i.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(_,R,S,y,z)=>{if(r.push({paramName:R,isOptional:S!=null}),S){let N=z.charAt(y+_.length);return N&&N!=="/"?"/([^\\/]*)":"(?:/([^\\/]*))?"}return"/([^\\/]+)"}).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return i.endsWith("*")?(r.push({paramName:"*"}),m+=i==="*"||i==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):o?m+="\\/*$":i!==""&&i!=="/"&&(m+="(?:(?=\\/|$))"),[new RegExp(m,f?void 0:"i"),r]}function Py(i){try{return i.split("/").map(f=>decodeURIComponent(f).replace(/\//g,"%2F")).join("/")}catch(f){return Bt(!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 (${f}).`),i}}function ml(i,f){if(f==="/")return i;if(!i.toLowerCase().startsWith(f.toLowerCase()))return null;let o=f.endsWith("/")?f.length-1:f.length,r=i.charAt(o);return r&&r!=="/"?null:i.slice(o)||"/"}var ep=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;function tp(i,f="/"){let{pathname:o,search:r="",hash:m=""}=typeof i=="string"?ua(i):i,h;return o?(o=wm(o),o.startsWith("/")?h=Rm(o.substring(1),"/"):h=Rm(o,f)):h=f,{pathname:h,search:np(r),hash:up(m)}}function Rm(i,f){let o=xi(f).split("/");return i.split("/").forEach(m=>{m===".."?o.length>1&&o.pop():m!=="."&&o.push(m)}),o.length>1?o.join("/"):"/"}function Js(i,f,o,r){return`Cannot include a '${i}' character in a manually specified \`to.${f}\` field [${JSON.stringify(r)}]. 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 lp(i){return i.filter((f,o)=>o===0||f.route.path&&f.route.path.length>0)}function lf(i){let f=lp(i);return f.map((o,r)=>r===f.length-1?o.pathname:o.pathnameBase)}function ji(i,f,o,r=!1){let m;typeof i=="string"?m=ua(i):(m={...i},Le(!m.pathname||!m.pathname.includes("?"),Js("?","pathname","search",m)),Le(!m.pathname||!m.pathname.includes("#"),Js("#","pathname","hash",m)),Le(!m.search||!m.search.includes("#"),Js("#","search","hash",m)));let h=i===""||m.pathname==="",_=h?"/":m.pathname,R;if(_==null)R=o;else{let N=f.length-1;if(!r&&_.startsWith("..")){let L=_.split("/");for(;L[0]==="..";)L.shift(),N-=1;m.pathname=L.join("/")}R=N>=0?f[N]:"/"}let S=tp(m,R),y=_&&_!=="/"&&_.endsWith("/"),z=(h||_===".")&&o.endsWith("/");return!S.pathname.endsWith("/")&&(y||z)&&(S.pathname+="/"),S}var wm=i=>i.replace(/\/\/+/g,"/"),Qt=i=>wm(i.join("/")),xi=i=>i.replace(/\/+$/,""),ap=i=>xi(i).replace(/^\/*/,"/"),np=i=>!i||i==="?"?"":i.startsWith("?")?i:"?"+i,up=i=>!i||i==="#"?"":i.startsWith("#")?i:"#"+i,ip=class{constructor(i,f,o,r=!1){this.status=i,this.statusText=f||"",this.internal=r,o instanceof Error?(this.data=o.toString(),this.error=o):this.data=o}};function cp(i){return i!=null&&typeof i.status=="number"&&typeof i.statusText=="string"&&typeof i.internal=="boolean"&&"data"in i}function sp(i){let f=i.map(o=>o.route.path).filter(Boolean);return Qt(f)||"/"}var Bm=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function Lm(i,f){let o=i;if(typeof o!="string"||!ep.test(o))return{absoluteURL:void 0,isExternal:!1,to:o};let r=o,m=!1;if(Bm)try{let h=new URL(window.location.href),_=o.startsWith("//")?new URL(h.protocol+o):new URL(o),R=ml(_.pathname,f);_.origin===h.origin&&R!=null?o=R+_.search+_.hash:m=!0}catch{Bt(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:m,to:o}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var Ym=["POST","PUT","PATCH","DELETE"];new Set(Ym);var fp=["GET",...Ym];new Set(fp);var Ja=p.createContext(null);Ja.displayName="DataRouter";var Ni=p.createContext(null);Ni.displayName="DataRouterState";var Gm=p.createContext(!1);function rp(){return p.useContext(Gm)}var Qm=p.createContext({isTransitioning:!1});Qm.displayName="ViewTransition";var op=p.createContext(new Map);op.displayName="Fetchers";var dp=p.createContext(null);dp.displayName="Await";var Tt=p.createContext(null);Tt.displayName="Navigation";var $n=p.createContext(null);$n.displayName="Location";var Xt=p.createContext({outlet:null,matches:[],isDataRoute:!1});Xt.displayName="Route";var af=p.createContext(null);af.displayName="RouteError";var Xm="REACT_ROUTER_ERROR",mp="REDIRECT",hp="ROUTE_ERROR_RESPONSE";function vp(i){if(i.startsWith(`${Xm}:${mp}:{`))try{let f=JSON.parse(i.slice(28));if(typeof f=="object"&&f&&typeof f.status=="number"&&typeof f.statusText=="string"&&typeof f.location=="string"&&typeof f.reloadDocument=="boolean"&&typeof f.replace=="boolean")return f}catch{}}function yp(i){if(i.startsWith(`${Xm}:${hp}:{`))try{let f=JSON.parse(i.slice(40));if(typeof f=="object"&&f&&typeof f.status=="number"&&typeof f.statusText=="string")return new ip(f.status,f.statusText,f.data)}catch{}}function pp(i,{relative:f}={}){Le(ka(),"useHref() may be used only in the context of a component.");let{basename:o,navigator:r}=p.useContext(Tt),{hash:m,pathname:h,search:_}=Wn(i,{relative:f}),R=h;return o!=="/"&&(R=h==="/"?o:Qt([o,h])),r.createHref({pathname:R,search:_,hash:m})}function ka(){return p.useContext($n)!=null}function kt(){return Le(ka(),"useLocation() may be used only in the context of a component."),p.useContext($n).location}var Zm="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function Vm(i){p.useContext(Tt).static||p.useLayoutEffect(i)}function Km(){let{isDataRoute:i}=p.useContext(Xt);return i?Dp():gp()}function gp(){Le(ka(),"useNavigate() may be used only in the context of a component.");let i=p.useContext(Ja),{basename:f,navigator:o}=p.useContext(Tt),{matches:r}=p.useContext(Xt),{pathname:m}=kt(),h=JSON.stringify(lf(r)),_=p.useRef(!1);return Vm(()=>{_.current=!0}),p.useCallback((S,y={})=>{if(Bt(_.current,Zm),!_.current)return;if(typeof S=="number"){o.go(S);return}let z=ji(S,JSON.parse(h),m,y.relative==="path");i==null&&f!=="/"&&(z.pathname=z.pathname==="/"?f:Qt([f,z.pathname])),(y.replace?o.replace:o.push)(z,y.state,y)},[f,o,h,m,i])}var bp=p.createContext(null);function _p(i){let f=p.useContext(Xt).outlet;return p.useMemo(()=>f&&p.createElement(bp.Provider,{value:i},f),[f,i])}function Wn(i,{relative:f}={}){let{matches:o}=p.useContext(Xt),{pathname:r}=kt(),m=JSON.stringify(lf(o));return p.useMemo(()=>ji(i,JSON.parse(m),r,f==="path"),[i,m,r,f])}function Sp(i,f){return Jm(i,f)}function Jm(i,f,o){Le(ka(),"useRoutes() may be used only in the context of a component.");let{navigator:r}=p.useContext(Tt),{matches:m}=p.useContext(Xt),h=m[m.length-1],_=h?h.params:{},R=h?h.pathname:"/",S=h?h.pathnameBase:"/",y=h&&h.route;{let B=y&&y.path||"";$m(R,!y||B.endsWith("*")||B.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${R}" (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 z=kt(),N;if(f){let B=typeof f=="string"?ua(f):f;Le(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.`),N=B}else N=z;let L=N.pathname||"/",w=L;if(S!=="/"){let B=S.replace(/^\//,"").split("/");w="/"+L.replace(/^\//,"").split("/").slice(B.length).join("/")}let V=Um(i,{pathname:w});Bt(y||V!=null,`No routes matched location "${N.pathname}${N.search}${N.hash}" `),Bt(V==null||V[V.length-1].route.element!==void 0||V[V.length-1].route.Component!==void 0||V[V.length-1].route.lazy!==void 0,`Matched leaf route at location "${N.pathname}${N.search}${N.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 Q=Tp(V&&V.map(B=>Object.assign({},B,{params:Object.assign({},_,B.params),pathname:Qt([S,r.encodeLocation?r.encodeLocation(B.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:B.pathname]),pathnameBase:B.pathnameBase==="/"?S:Qt([S,r.encodeLocation?r.encodeLocation(B.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:B.pathnameBase])})),m,o);return f&&Q?p.createElement($n.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",unstable_mask:void 0,...N},navigationType:"POP"}},Q):Q}function xp(){let i=Cp(),f=cp(i)?`${i.status} ${i.statusText}`:i instanceof Error?i.message:JSON.stringify(i),o=i instanceof Error?i.stack:null,r="rgba(200,200,200, 0.5)",m={padding:"0.5rem",backgroundColor:r},h={padding:"2px 4px",backgroundColor:r},_=null;return console.error("Error handled by React Router default ErrorBoundary:",i),_=p.createElement(p.Fragment,null,p.createElement("p",null,"💿 Hey developer 👋"),p.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",p.createElement("code",{style:h},"ErrorBoundary")," or"," ",p.createElement("code",{style:h},"errorElement")," prop on your route.")),p.createElement(p.Fragment,null,p.createElement("h2",null,"Unexpected Application Error!"),p.createElement("h3",{style:{fontStyle:"italic"}},f),o?p.createElement("pre",{style:m},o):null,_)}var jp=p.createElement(xp,null),km=class extends p.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,f){return f.location!==i.location||f.revalidation!=="idle"&&i.revalidation==="idle"?{error:i.error,location:i.location,revalidation:i.revalidation}:{error:i.error!==void 0?i.error:f.error,location:f.location,revalidation:i.revalidation||f.revalidation}}componentDidCatch(i,f){this.props.onError?this.props.onError(i,f):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=yp(i.digest);o&&(i=o)}let f=i!==void 0?p.createElement(Xt.Provider,{value:this.props.routeContext},p.createElement(af.Provider,{value:i,children:this.props.component})):this.props.children;return this.context?p.createElement(Np,{error:i},f):f}};km.contextType=Gm;var ks=new WeakMap;function Np({children:i,error:f}){let{basename:o}=p.useContext(Tt);if(typeof f=="object"&&f&&"digest"in f&&typeof f.digest=="string"){let r=vp(f.digest);if(r){let m=ks.get(f);if(m)throw m;let h=Lm(r.location,o);if(Bm&&!ks.get(f))if(h.isExternal||r.reloadDocument)window.location.href=h.absoluteURL||h.to;else{const _=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(h.to,{replace:r.replace}));throw ks.set(f,_),_}return p.createElement("meta",{httpEquiv:"refresh",content:`0;url=${h.absoluteURL||h.to}`})}}return i}function Ep({routeContext:i,match:f,children:o}){let r=p.useContext(Ja);return r&&r.static&&r.staticContext&&(f.route.errorElement||f.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=f.route.id),p.createElement(Xt.Provider,{value:i},o)}function Tp(i,f=[],o){let r=o?.state;if(i==null){if(!r)return null;if(r.errors)i=r.matches;else if(f.length===0&&!r.initialized&&r.matches.length>0)i=r.matches;else return null}let m=i,h=r?.errors;if(h!=null){let z=m.findIndex(N=>N.route.id&&h?.[N.route.id]!==void 0);Le(z>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(h).join(",")}`),m=m.slice(0,Math.min(m.length,z+1))}let _=!1,R=-1;if(o&&r){_=r.renderFallback;for(let z=0;z=0?m=m.slice(0,R+1):m=[m[0]];break}}}}let S=o?.onError,y=r&&S?(z,N)=>{S(z,{location:r.location,params:r.matches?.[0]?.params??{},unstable_pattern:sp(r.matches),errorInfo:N})}:void 0;return m.reduceRight((z,N,L)=>{let w,V=!1,Q=null,B=null;r&&(w=h&&N.route.id?h[N.route.id]:void 0,Q=N.route.errorElement||jp,_&&(R<0&&L===0?($m("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),V=!0,B=null):R===L&&(V=!0,B=N.route.hydrateFallbackElement||null)));let Z=f.concat(m.slice(0,L+1)),F=()=>{let $;return w?$=Q:V?$=B:N.route.Component?$=p.createElement(N.route.Component,null):N.route.element?$=N.route.element:$=z,p.createElement(Ep,{match:N,routeContext:{outlet:z,matches:Z,isDataRoute:r!=null},children:$})};return r&&(N.route.ErrorBoundary||N.route.errorElement||L===0)?p.createElement(km,{location:r.location,revalidation:r.revalidation,component:Q,error:w,children:F(),routeContext:{outlet:null,matches:Z,isDataRoute:!0},onError:y}):F()},null)}function nf(i){return`${i} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function Rp(i){let f=p.useContext(Ja);return Le(f,nf(i)),f}function Ap(i){let f=p.useContext(Ni);return Le(f,nf(i)),f}function zp(i){let f=p.useContext(Xt);return Le(f,nf(i)),f}function uf(i){let f=zp(i),o=f.matches[f.matches.length-1];return Le(o.route.id,`${i} can only be used on routes that contain a unique "id"`),o.route.id}function Op(){return uf("useRouteId")}function Cp(){let i=p.useContext(af),f=Ap("useRouteError"),o=uf("useRouteError");return i!==void 0?i:f.errors?.[o]}function Dp(){let{router:i}=Rp("useNavigate"),f=uf("useNavigate"),o=p.useRef(!1);return Vm(()=>{o.current=!0}),p.useCallback(async(m,h={})=>{Bt(o.current,Zm),o.current&&(typeof m=="number"?await i.navigate(m):await i.navigate(m,{fromRouteId:f,...h}))},[i,f])}var Am={};function $m(i,f,o){!f&&!Am[i]&&(Am[i]=!0,Bt(!1,o))}p.memo(Mp);function Mp({routes:i,future:f,state:o,isStatic:r,onError:m}){return Jm(i,void 0,{state:o,isStatic:r,onError:m})}function Up({to:i,replace:f,state:o,relative:r}){Le(ka()," may be used only in the context of a component.");let{static:m}=p.useContext(Tt);Bt(!m," 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}=p.useContext(Xt),{pathname:_}=kt(),R=Km(),S=ji(i,lf(h),_,r==="path"),y=JSON.stringify(S);return p.useEffect(()=>{R(JSON.parse(y),{replace:f,state:o,relative:r})},[R,y,r,f,o]),null}function Hp(i){return _p(i.context)}function na(i){Le(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function qp({basename:i="/",children:f=null,location:o,navigationType:r="POP",navigator:m,static:h=!1,unstable_useTransitions:_}){Le(!ka(),"You cannot render a inside another . You should never have more than one in your app.");let R=i.replace(/^\/*/,"/"),S=p.useMemo(()=>({basename:R,navigator:m,static:h,unstable_useTransitions:_,future:{}}),[R,m,h,_]);typeof o=="string"&&(o=ua(o));let{pathname:y="/",search:z="",hash:N="",state:L=null,key:w="default",unstable_mask:V}=o,Q=p.useMemo(()=>{let B=ml(y,R);return B==null?null:{location:{pathname:B,search:z,hash:N,state:L,key:w,unstable_mask:V},navigationType:r}},[R,y,z,N,L,w,r,V]);return Bt(Q!=null,` is not able to match the URL "${y}${z}${N}" because it does not start with the basename, so the won't render anything.`),Q==null?null:p.createElement(Tt.Provider,{value:S},p.createElement($n.Provider,{children:f,value:Q}))}function wp({children:i,location:f}){return Sp(Ps(i),f)}function Ps(i,f=[]){let o=[];return p.Children.forEach(i,(r,m)=>{if(!p.isValidElement(r))return;let h=[...f,m];if(r.type===p.Fragment){o.push.apply(o,Ps(r.props.children,h));return}Le(r.type===na,`[${typeof r.type=="string"?r.type:r.type.name}] is not a component. All component children of must be a or `),Le(!r.props.index||!r.props.children,"An index route cannot have child routes.");let _={id:r.props.id||h.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,middleware:r.props.middleware,loader:r.props.loader,action:r.props.action,hydrateFallbackElement:r.props.hydrateFallbackElement,HydrateFallback:r.props.HydrateFallback,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.hasErrorBoundary===!0||r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(_.children=Ps(r.props.children,h)),o.push(_)}),o}var gi="get",bi="application/x-www-form-urlencoded";function Ei(i){return typeof HTMLElement<"u"&&i instanceof HTMLElement}function Bp(i){return Ei(i)&&i.tagName.toLowerCase()==="button"}function Lp(i){return Ei(i)&&i.tagName.toLowerCase()==="form"}function Yp(i){return Ei(i)&&i.tagName.toLowerCase()==="input"}function Gp(i){return!!(i.metaKey||i.altKey||i.ctrlKey||i.shiftKey)}function Qp(i,f){return i.button===0&&(!f||f==="_self")&&!Gp(i)}var vi=null;function Xp(){if(vi===null)try{new FormData(document.createElement("form"),0),vi=!1}catch{vi=!0}return vi}var Zp=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function $s(i){return i!=null&&!Zp.has(i)?(Bt(!1,`"${i}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${bi}"`),null):i}function Vp(i,f){let o,r,m,h,_;if(Lp(i)){let R=i.getAttribute("action");r=R?ml(R,f):null,o=i.getAttribute("method")||gi,m=$s(i.getAttribute("enctype"))||bi,h=new FormData(i)}else if(Bp(i)||Yp(i)&&(i.type==="submit"||i.type==="image")){let R=i.form;if(R==null)throw new Error('Cannot submit a -