From 79dab86e942bbf85ac99e39e1cdb5262b6f5152a Mon Sep 17 00:00:00 2001 From: zendaya Date: Sat, 2 May 2026 14:22:12 +0200 Subject: [PATCH 1/2] =?UTF-8?q?feat(release):=20v1.0.3=20=E2=80=94=20Phase?= =?UTF-8?q?=200=20hardening=20with=20expanded=20test=20coverage=20and=20UI?= =?UTF-8?q?=20enhancements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added comprehensive pytest coverage for `diff_releases`, addressing MEDIUM/LOW confidence scenarios, policy checks on latency and error rates, and multiple failure reasons. - Enhanced `runs ingest` functionality to handle edge cases including empty files, malformed JSONL, and JSON array payloads. - Implemented multi-provider and cross-model support for `release diff`, ensuring accurate comparisons across different pricing providers and models. - Updated web UI to present structured outcomes for promote/rollback actions, including policy status and a notification for pricing/model changes in the Run diff view. Co-authored-by: Cursor --- .github/workflows/release-pypi.yml | 2 +- CHANGELOG.md | 11 + DEVELOPMENT.md | 2 +- RELEASE_NOTES.md | 4 + ROADMAP.md | 17 ++ examples/ci/README.md | 2 +- .../ci/github-actions/policy-gate-pypi.yml | 2 +- examples/deploy/Dockerfile | 2 +- pyproject.toml | 2 +- src/flightdeck/__init__.py | 2 +- tests/test_ledger.py | 242 ++++++++++++++- tests/test_spine.py | 283 ++++++++++++++++++ web/src/api.ts | 24 ++ web/src/pages/ActionsPage.tsx | 127 +++++++- web/src/pages/DiffPage.tsx | 43 +++ 15 files changed, 750 insertions(+), 15 deletions(-) diff --git a/.github/workflows/release-pypi.yml b/.github/workflows/release-pypi.yml index ae843ee..2f1b2d9 100644 --- a/.github/workflows/release-pypi.yml +++ b/.github/workflows/release-pypi.yml @@ -1,4 +1,4 @@ -# Publish sdist + wheel to PyPI when a SemVer tag is pushed (e.g. v1.0.2). +# Publish sdist + wheel to PyPI when a SemVer tag is pushed (e.g. v1.0.3). # Configure "trusted publishing" on PyPI for this workflow + repository + optional GitHub environment. # https://docs.pypi.org/trusted-publishers/ diff --git a/CHANGELOG.md b/CHANGELOG.md index b36965c..3dc2fbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ This project follows [Semantic Versioning](https://semver.org/). From **v1.0.0** ## Unreleased +## 1.0.3 - 2026-05-03 + +### Added + +- **Tests:** **`tests/test_ledger.py`** — MEDIUM vs **`require_high_diff_confidence`**, LOW sample-floor boundary, **`max_latency_ms`** (and skip when latency absent), **`max_error_rate`**, multiple simultaneous policy failure reasons; **`tests/test_spine.py`** — MEDIUM confidence blocks second **`release promote`**, **`runs ingest`** on empty file / malformed JSONL / JSON array payload, **`release diff`** across different pricing providers and across different models on one provider table (plus **`POST /v1/diff`** `pricing.pricing_or_model_changed` assertion). +- **Web UI:** structured **Promote & rollback** outcome (policy badge, pointer status, action/release/baseline IDs, reason list) with raw response in a collapsed **`JsonPanel`**; **Run diff** shows a pricing/model-change callout when **`pricing.pricing_or_model_changed`** is true. + +### Changed + +- **Roadmap:** **Phase 0 progress** subsection and **Next release** pointer for **v1.0.3**; docs aligned with the patch scope above. + ## 1.0.2 - 2026-05-02 ### Added diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index aaa1a7f..517f629 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -119,7 +119,7 @@ Merging to **`main` does not publish packages** — PyPI uploads are **tag-drive 1. **PyPI:** add a **trusted publisher** for **[github.com/flightdeckdev/flightdeck](https://github.com/flightdeckdev/flightdeck)** — workflow **`release-pypi.yml`**. If PyPI offers **Environment name: (Any)**, you can still use a GitHub **Environment** named **`pypi`** for approval gates; otherwise match whatever you register on PyPI ([trusted publishers](https://docs.pypi.org/trusted-publishers/)). 2. **GitHub:** Settings → **Environments** → create **`pypi`** (optional: required reviewers / wait timer before OIDC publish). 3. Bump **`version`** in **`pyproject.toml`** and **`src/flightdeck/__init__.py`**, update **`CHANGELOG.md`**, merge to **`main`**. -4. **`git tag vX.Y.Z`** (must match **`pyproject.toml`** exactly, e.g. **`v1.0.2`**) then **`git push origin vX.Y.Z`**. +4. **`git tag vX.Y.Z`** (must match **`pyproject.toml`** exactly, e.g. **`v1.0.3`**) then **`git push origin vX.Y.Z`**. The workflow runs **ruff**, **pytest**, schema drift, **`uv build`**, publishes **sdist + wheel** to **PyPI** via **OIDC** (no long-lived API token in repo secrets), enables **publish attestations**, and creates a **GitHub Release** with generated notes and **`dist/*`** assets. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 2c63934..dd591d4 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -4,6 +4,10 @@ High-level notes for **shipping FlightDeck**. Detailed history: **[CHANGELOG.md] Narrative docs (including the CLI reference) are maintained on **[github.com/flightdeckdev/flightdeck](https://github.com/flightdeckdev/flightdeck)** `main`; this file and **`schemas/`** ship in minimal clones. +## v1.0.3 — Phase 0 hardening (tests + UI) + +Patch release (see **[CHANGELOG.md](CHANGELOG.md)**): broader **pytest** coverage for **`diff_releases`** (MEDIUM/LOW confidence, **`max_latency_ms`**, **`max_error_rate`**, combined failures), **CLI** integration for MEDIUM confidence blocking promotion when **`require_high_diff_confidence`** is on, **`runs ingest`** edge cases (empty file, bad JSONL, JSON array file), and **multi-provider / cross-model** **`release diff`** plus **`POST /v1/diff`** parity on **`pricing.pricing_or_model_changed`**. **Web UI:** promote/rollback responses use structured panels (raw JSON optional); **Run diff** surfaces the same pricing/model-change note as the CLI when the diff payload flags it. **Stable contracts:** no CLI flag removals, no **`v1`** schema or **`POST /v1/events`** shape changes; **HTTP** diff and action response shapes are unchanged (additive UI only on the client). + ## v1.0.2 — CI examples, serve packaging, and policy gate CLI Minor release (see **[CHANGELOG.md](CHANGELOG.md)**): **`flightdeck release diff --fail-on-policy`** for CI gates; **`examples/ci/`** (`ledger-gate.sh`, GitHub Actions templates) exercised in root CI; **`examples/deploy/`** (Docker/Compose for **`flightdeck serve`**); **`examples/integration/`** (SDK sample emitter for **`POST /v1/events`**); **`GET /health`** adds non-secret **`mutation_auth`** (`loopback` vs `bearer`); web shell shows mutation/token ergonomics and optional read-only UI (**`VITE_FLIGHTDECK_UI_READ_ONLY`**). Fix: policy **`min_*_runs`** explicit **`0`** overrides workspace defaults ( **`is not None`** resolution in **`diff_releases`** ). **Stable contracts:** additive **`/health`** field only; CLI flag is backward-compatible. diff --git a/ROADMAP.md b/ROADMAP.md index 99e56e1..34ad982 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -19,6 +19,12 @@ This roadmap is meant to be clear from **what is already shipped** to **near-ter --- +## Next release + +**v1.0.3** (patch): Phase 0 hardening — expanded **pytest** coverage for diff confidence (MEDIUM/LOW, policy on latency and error rate), **runs ingest** edge cases (empty file, malformed JSONL, JSON array payload), and **multi-provider / cross-model** `release diff` paths; web UI structured **promote/rollback** outcome plus a **pricing/model changed** banner on **Run diff** when the API reports it. See **[CHANGELOG.md](CHANGELOG.md)** and **[RELEASE_NOTES.md](RELEASE_NOTES.md)**. No breaking changes to stable CLI, HTTP, or **`api_version` `v1`** contracts. + +--- + ## Production readiness gaps (why it can feel standalone) These are current gaps between "works locally" and "easy to use across production services." @@ -47,6 +53,17 @@ Goal: prove the wedge with real teams using FlightDeck as release governance sou - Strengthen local security ergonomics: explicit token/env status in UI, mutation guardrails, optional read-only UX. - Continue UI productization for current scope (structured views over raw JSON where stable). +### Phase 0 progress (toward v1.0.3) + +Shipped on **`main`** for the next patch: + +- **Policy / diff tests:** `diff_releases` coverage for MEDIUM confidence vs `require_high_diff_confidence`, LOW sample floor boundaries, `max_latency_ms` (including skip when latency is absent), `max_error_rate`, and stacked policy failure reasons; CLI integration for MEDIUM blocking a second promotion after a baseline is established. +- **Ingest tests:** empty JSONL (zero inserts), malformed line (non-zero exit), JSON array file accepted. +- **Multi-provider pricing:** integration tests that diff baseline vs candidate releases with different **`pricing_reference`** providers (and same-provider different models), including parity checks on **`POST /v1/diff`** `pricing.pricing_or_model_changed`. +- **Web UI:** structured outcome card after promote/rollback (policy, pointer, IDs) with raw JSON in a collapsible panel; Diff summary shows pricing/model change when the server marks it. + +**Still open in Phase 0** (see gaps table and Phase 1 for larger items): richer **pricing normalization** product semantics (beyond per-side tables + flags), broader **integration** and **deployment** narrative in docs, and **observability** paths remain roadmap-sized rather than single-patch work. + ### Phase-0 success signals - Teams use release versioning + checksum verification as the source of truth for promotion decisions. diff --git a/examples/ci/README.md b/examples/ci/README.md index 7c1a151..30055a2 100644 --- a/examples/ci/README.md +++ b/examples/ci/README.md @@ -37,7 +37,7 @@ uv run python examples/ci/ledger_gate.py Example (**PyPI** install): ```bash -pip install "flightdeck-ai>=1.0.2" +pip install "flightdeck-ai>=1.0.3" export WORKSPACE="$(mktemp -d)" export QUICKSTART_ROOT=/path/to/flightdeck/examples/quickstart python /path/to/flightdeck/examples/ci/ledger_gate.py diff --git a/examples/ci/github-actions/policy-gate-pypi.yml b/examples/ci/github-actions/policy-gate-pypi.yml index 142e272..b40f299 100644 --- a/examples/ci/github-actions/policy-gate-pypi.yml +++ b/examples/ci/github-actions/policy-gate-pypi.yml @@ -11,7 +11,7 @@ on: env: # Pin to a tag or SHA that matches your installed flightdeck-ai version when possible. FLIGHTDECK_REF: main - FLIGHTDECK_AI_SPEC: ">=1.0.2" + FLIGHTDECK_AI_SPEC: ">=1.0.3" jobs: ledger-gate: diff --git a/examples/deploy/Dockerfile b/examples/deploy/Dockerfile index f42995d..7269e77 100644 --- a/examples/deploy/Dockerfile +++ b/examples/deploy/Dockerfile @@ -2,7 +2,7 @@ FROM python:3.14-slim RUN pip install --no-cache-dir --upgrade pip \ - && pip install --no-cache-dir "flightdeck-ai>=1.0.2" + && pip install --no-cache-dir "flightdeck-ai>=1.0.3" WORKDIR /workspace diff --git a/pyproject.toml b/pyproject.toml index 425cab4..2866a90 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "flightdeck-ai" -version = "1.0.2" +version = "1.0.3" description = "AI Release Governance for production agents." readme = "README.md" license = "Apache-2.0" diff --git a/src/flightdeck/__init__.py b/src/flightdeck/__init__.py index 2031bfc..718d871 100644 --- a/src/flightdeck/__init__.py +++ b/src/flightdeck/__init__.py @@ -1,3 +1,3 @@ """FlightDeck - AI Release Governance for production agents.""" -__version__ = "1.0.2" +__version__ = "1.0.3" diff --git a/tests/test_ledger.py b/tests/test_ledger.py index 270fef5..5682ada 100644 --- a/tests/test_ledger.py +++ b/tests/test_ledger.py @@ -17,7 +17,16 @@ ) -def _event(*, agent_id: str, run_id: str, release_id: str) -> RunEvent: +def _event( + *, + agent_id: str, + run_id: str, + release_id: str, + latency_ms: int | None = 100, + success: bool = True, + input_tokens: int = 100, + output_tokens: int = 50, +) -> RunEvent: return RunEvent( timestamp=datetime.now(tz=timezone.utc), agent_id=agent_id, @@ -30,11 +39,11 @@ def _event(*, agent_id: str, run_id: str, release_id: str) -> RunEvent: model=RunEventModelUsage( provider="openai", model="gpt-4.1-mini", - input_tokens=100, - output_tokens=50, + input_tokens=input_tokens, + output_tokens=output_tokens, ) ), - metrics=RunEventMetrics(latency_ms=100, success=True), + metrics=RunEventMetrics(latency_ms=latency_ms, success=success), ) @@ -113,3 +122,228 @@ def test_diff_releases_respects_zero_policy_sample_thresholds() -> None: assert result.confidence == "HIGH" assert result.policy.passed + + +def _events(*, n: int, release_id: str, agent_id: str = "agent_a", **kwargs) -> list[RunEvent]: + return [_event(agent_id=agent_id, run_id=f"{release_id}_{i}", release_id=release_id, **kwargs) for i in range(n)] + + +def test_medium_confidence_blocks_when_require_high_flag_set() -> None: + cfg = WorkspaceConfig() + policy = Policy(require_high_diff_confidence=True) + table = _pricing_table() + + result = diff_releases( + cfg=cfg, + policy=policy, + baseline_events=_events(n=200, release_id="rel_b"), + candidate_events=_events(n=200, release_id="rel_c"), + baseline_pricing_table=table, + candidate_pricing_table=table, + window="7d", + ) + + assert result.confidence == "MEDIUM" + assert not result.policy.passed + assert any("MEDIUM" in r for r in result.policy.reasons) + assert any("HIGH" in r for r in result.policy.reasons) + + +def test_medium_confidence_passes_without_require_high_flag() -> None: + cfg = WorkspaceConfig() + policy = Policy(require_high_diff_confidence=False) + table = _pricing_table() + + result = diff_releases( + cfg=cfg, + policy=policy, + baseline_events=_events(n=200, release_id="rel_b"), + candidate_events=_events(n=200, release_id="rel_c"), + baseline_pricing_table=table, + candidate_pricing_table=table, + window="7d", + ) + + assert result.confidence == "MEDIUM" + assert result.policy.passed + + +def test_confidence_reason_populated_for_medium_and_low() -> None: + cfg = WorkspaceConfig() + policy = Policy(require_high_diff_confidence=False) + table = _pricing_table() + + medium = diff_releases( + cfg=cfg, + policy=policy, + baseline_events=_events(n=200, release_id="rel_b"), + candidate_events=_events(n=200, release_id="rel_c"), + baseline_pricing_table=table, + candidate_pricing_table=table, + window="7d", + ) + assert medium.confidence == "MEDIUM" + assert medium.confidence_reason + assert "sample" in medium.confidence_reason + + low = diff_releases( + cfg=cfg, + policy=policy, + baseline_events=_events(n=10, release_id="rel_b"), + candidate_events=_events(n=200, release_id="rel_c"), + baseline_pricing_table=table, + candidate_pricing_table=table, + window="7d", + ) + assert low.confidence == "LOW" + assert low.confidence_reason + assert "sample" in low.confidence_reason or "floor" in low.confidence_reason + + +def test_low_floor_boundary() -> None: + cfg = WorkspaceConfig() + # Override defaults so we can drive the LOW floor at runs=50 deterministically. + policy = Policy( + min_baseline_runs=500, + min_candidate_runs=500, + min_low_runs=50, + require_high_diff_confidence=False, + ) + table = _pricing_table() + + just_below = diff_releases( + cfg=cfg, + policy=policy, + baseline_events=_events(n=49, release_id="rel_b"), + candidate_events=_events(n=200, release_id="rel_c"), + baseline_pricing_table=table, + candidate_pricing_table=table, + window="7d", + ) + assert just_below.confidence == "LOW" + + at_floor = diff_releases( + cfg=cfg, + policy=policy, + baseline_events=_events(n=50, release_id="rel_b"), + candidate_events=_events(n=200, release_id="rel_c"), + baseline_pricing_table=table, + candidate_pricing_table=table, + window="7d", + ) + assert at_floor.confidence == "MEDIUM" + + +def test_policy_max_latency_ms_blocks() -> None: + cfg = WorkspaceConfig() + policy = Policy( + max_latency_ms=50, + min_baseline_runs=0, + min_candidate_runs=0, + min_low_runs=0, + require_high_diff_confidence=False, + ) + table = _pricing_table() + + result = diff_releases( + cfg=cfg, + policy=policy, + baseline_events=_events(n=5, release_id="rel_b", latency_ms=100), + candidate_events=_events(n=5, release_id="rel_c", latency_ms=200), + baseline_pricing_table=table, + candidate_pricing_table=table, + window="7d", + ) + + assert not result.policy.passed + assert any("latency_ms_avg" in r for r in result.policy.reasons) + + +def test_policy_max_latency_ms_skipped_when_no_data() -> None: + cfg = WorkspaceConfig() + policy = Policy( + max_latency_ms=50, + min_baseline_runs=0, + min_candidate_runs=0, + min_low_runs=0, + require_high_diff_confidence=False, + ) + table = _pricing_table() + + result = diff_releases( + cfg=cfg, + policy=policy, + baseline_events=_events(n=5, release_id="rel_b", latency_ms=None), + candidate_events=_events(n=5, release_id="rel_c", latency_ms=None), + baseline_pricing_table=table, + candidate_pricing_table=table, + window="7d", + ) + + assert result.candidate.latency_ms_avg is None + assert result.policy.passed + assert not any("latency" in r for r in result.policy.reasons) + + +def test_policy_max_error_rate_blocks() -> None: + cfg = WorkspaceConfig() + policy = Policy( + max_error_rate=0.1, + min_baseline_runs=0, + min_candidate_runs=0, + min_low_runs=0, + require_high_diff_confidence=False, + ) + table = _pricing_table() + + candidate_events = [ + _event(agent_id="agent_a", run_id=f"c_{i}", release_id="rel_c", success=(i < 4)) + for i in range(8) + ] + + result = diff_releases( + cfg=cfg, + policy=policy, + baseline_events=_events(n=5, release_id="rel_b"), + candidate_events=candidate_events, + baseline_pricing_table=table, + candidate_pricing_table=table, + window="7d", + ) + + assert result.candidate.error_rate == 0.5 + assert not result.policy.passed + assert any("error_rate" in r for r in result.policy.reasons) + + +def test_policy_multiple_failures_accumulate() -> None: + cfg = WorkspaceConfig() + policy = Policy( + max_cost_per_run_usd=0.0001, + max_error_rate=0.1, + min_baseline_runs=0, + min_candidate_runs=0, + min_low_runs=0, + require_high_diff_confidence=False, + ) + table = _pricing_table() + + candidate_events = [ + _event(agent_id="agent_a", run_id=f"c_{i}", release_id="rel_c", success=(i < 4)) + for i in range(8) + ] + + result = diff_releases( + cfg=cfg, + policy=policy, + baseline_events=_events(n=5, release_id="rel_b"), + candidate_events=candidate_events, + baseline_pricing_table=table, + candidate_pricing_table=table, + window="7d", + ) + + assert not result.policy.passed + assert any("cost_per_run_usd" in r for r in result.policy.reasons) + assert any("error_rate" in r for r in result.policy.reasons) + assert len(result.policy.reasons) >= 2 diff --git a/tests/test_spine.py b/tests/test_spine.py index bb83bab..687991d 100644 --- a/tests/test_spine.py +++ b/tests/test_spine.py @@ -767,3 +767,286 @@ def test_passing_second_promotion_replaces_current_release(tmp_path: Path, monke storage.migrate() assert storage.get_promoted_release_id("agent_support", "local") == candidate_id + +def test_diff_medium_confidence_blocks_promotion(tmp_path: Path, monkeypatch) -> None: + monkeypatch.chdir(tmp_path) + runner = CliRunner() + + assert runner.invoke(cli, ["init"]).exit_code == 0 + policy = write_policy(tmp_path, require_high_diff_confidence=True) + assert runner.invoke(cli, ["policy", "set", str(policy)]).exit_code == 0 + + pricing = write_pricing(tmp_path, provider="openai", pricing_version="openai-2026-04-30") + assert runner.invoke(cli, ["pricing", "import", str(pricing)]).exit_code == 0 + + baseline_dir = write_release( + tmp_path, + agent_id="agent_support", + version="1", + pricing_provider="openai", + pricing_version="openai-2026-04-30", + ) + candidate_dir = write_release( + tmp_path, + agent_id="agent_support", + version="2", + pricing_provider="openai", + pricing_version="openai-2026-04-30", + ) + baseline_id = runner.invoke(cli, ["release", "register", str(baseline_dir)]).output.strip() + candidate_id = runner.invoke(cli, ["release", "register", str(candidate_dir)]).output.strip() + + now = datetime.now(tz=timezone.utc) + # 100 events per side: above LOW floor (50) but below HIGH target (500) -> MEDIUM. + baseline_events = write_events(tmp_path, release_id=baseline_id, agent_id="agent_support", n=100, ts=now) + candidate_events = write_events(tmp_path, release_id=candidate_id, agent_id="agent_support", n=100, ts=now) + assert runner.invoke(cli, ["runs", "ingest", str(baseline_events)]).exit_code == 0 + assert runner.invoke(cli, ["runs", "ingest", str(candidate_events)]).exit_code == 0 + + # Establish the baseline (first promotion is unconditional, so it succeeds even at MEDIUM). + assert ( + runner.invoke( + cli, + ["release", "promote", baseline_id, "--env", "local", "--window", "7d", "--reason", "baseline"], + ).exit_code + == 0 + ) + + res = runner.invoke( + cli, + ["release", "promote", candidate_id, "--env", "local", "--window", "7d", "--reason", "ship candidate"], + ) + assert res.exit_code != 0 + assert "Policy: FAIL" in res.output + assert "MEDIUM" in res.output + assert "promotion requires HIGH" in res.output + + storage = Storage(load_config().db_path) + storage.migrate() + assert storage.get_promoted_release_id("agent_support", "local") == baseline_id + + +def test_runs_ingest_empty_file(tmp_path: Path, monkeypatch) -> None: + monkeypatch.chdir(tmp_path) + runner = CliRunner() + assert runner.invoke(cli, ["init"]).exit_code == 0 + + empty = tmp_path / "empty.jsonl" + empty.write_text("", encoding="utf-8") + + res = runner.invoke(cli, ["runs", "ingest", str(empty)]) + assert res.exit_code == 0 + assert "Inserted 0 events" in res.output + + +def test_runs_ingest_rejects_malformed_jsonl(tmp_path: Path, monkeypatch) -> None: + monkeypatch.chdir(tmp_path) + runner = CliRunner() + assert runner.invoke(cli, ["init"]).exit_code == 0 + + bad = tmp_path / "bad.jsonl" + bad.write_text("{not valid json}\n", encoding="utf-8") + + res = runner.invoke(cli, ["runs", "ingest", str(bad)]) + assert res.exit_code != 0 + + +def test_runs_ingest_accepts_json_array(tmp_path: Path, monkeypatch) -> None: + monkeypatch.chdir(tmp_path) + runner = CliRunner() + assert runner.invoke(cli, ["init"]).exit_code == 0 + + pricing = write_pricing(tmp_path, provider="openai", pricing_version="openai-2026-04-30") + assert runner.invoke(cli, ["pricing", "import", str(pricing)]).exit_code == 0 + rel_dir = write_release( + tmp_path, + agent_id="agent_support", + version="1", + pricing_provider="openai", + pricing_version="openai-2026-04-30", + ) + release_id = runner.invoke(cli, ["release", "register", str(rel_dir)]).output.strip() + + now = datetime.now(tz=timezone.utc).isoformat() + events = [ + { + "api_version": "v1", + "type": "run_end", + "timestamp": now, + "workspace_id": "ws_local", + "agent_id": "agent_support", + "release_id": release_id, + "run_id": f"{release_id}_array_{i}", + "tenant_id": "unknown", + "task_id": "unknown", + "environment": "local", + "metrics": {"latency_ms": 1000, "success": True, "error_type": None}, + "usage": { + "model": { + "provider": "openai", + "model": "gpt-4.1-mini", + "input_tokens": 1000, + "output_tokens": 500, + "cached_input_tokens": 0, + }, + "tools": [], + }, + "labels": {}, + } + for i in range(3) + ] + p = tmp_path / "events_array.json" + p.write_text(json.dumps(events), encoding="utf-8") + + res = runner.invoke(cli, ["runs", "ingest", str(p)]) + assert res.exit_code == 0 + assert "Inserted 3 events" in res.output + + +def test_diff_cross_provider_releases(tmp_path: Path, monkeypatch) -> None: + monkeypatch.chdir(tmp_path) + runner = CliRunner() + + assert runner.invoke(cli, ["init"]).exit_code == 0 + + openai_pricing = write_pricing( + tmp_path, + provider="openai", + pricing_version="openai-2026-04-30", + model="gpt-4.1-mini", + input_price=1.0, + output_price=2.0, + ) + anthropic_pricing = write_pricing( + tmp_path, + provider="anthropic", + pricing_version="anthropic-2026-04-30", + model="claude-3-sonnet", + input_price=3.0, + output_price=4.0, + ) + assert runner.invoke(cli, ["pricing", "import", str(openai_pricing)]).exit_code == 0 + assert runner.invoke(cli, ["pricing", "import", str(anthropic_pricing)]).exit_code == 0 + + baseline_dir = write_release( + tmp_path, + agent_id="agent_support", + version="1", + pricing_provider="openai", + pricing_version="openai-2026-04-30", + model="gpt-4.1-mini", + ) + candidate_dir = write_release( + tmp_path, + agent_id="agent_support", + version="2", + pricing_provider="anthropic", + pricing_version="anthropic-2026-04-30", + model="claude-3-sonnet", + ) + baseline_id = runner.invoke(cli, ["release", "register", str(baseline_dir)]).output.strip() + candidate_id = runner.invoke(cli, ["release", "register", str(candidate_dir)]).output.strip() + + now = datetime.now(tz=timezone.utc) + baseline_events = write_events( + tmp_path, release_id=baseline_id, agent_id="agent_support", n=1, ts=now, model="gpt-4.1-mini" + ) + candidate_events = write_events( + tmp_path, release_id=candidate_id, agent_id="agent_support", n=1, ts=now, model="claude-3-sonnet" + ) + assert runner.invoke(cli, ["runs", "ingest", str(baseline_events)]).exit_code == 0 + assert runner.invoke(cli, ["runs", "ingest", str(candidate_events)]).exit_code == 0 + + res = runner.invoke(cli, ["release", "diff", baseline_id, candidate_id, "--window", "7d"]) + assert res.exit_code == 0 + assert "Baseline pricing: openai/openai-2026-04-30" in res.output + assert "Candidate pricing: anthropic/anthropic-2026-04-30" in res.output + assert "(model=gpt-4.1-mini)" in res.output + assert "(model=claude-3-sonnet)" in res.output + assert "NOTE: cost delta includes pricing/model assumption changes" in res.output + # baseline: 1000 input * 1.0/1k + 500 output * 2.0/1k = 1.0 + 1.0 = 2.0 + # candidate: 1000 * 3.0/1k + 500 * 4.0/1k = 3.0 + 2.0 = 5.0 + assert "Estimated model token cost/run (USD): 2.000000 -> 5.000000" in res.output + + # HTTP route exposes the same pricing-or-model-changed flag. + from fastapi.testclient import TestClient + + from flightdeck.server.app import create_app + + with TestClient(create_app()) as client: + resp = client.post( + "/v1/diff", + json={ + "baseline_release_id": baseline_id, + "candidate_release_id": candidate_id, + "window": "7d", + "environment": "local", + }, + ) + assert resp.status_code == 200 + body = resp.json() + assert body["pricing"]["baseline_provider"] == "openai" + assert body["pricing"]["candidate_provider"] == "anthropic" + assert body["pricing"]["pricing_or_model_changed"] is True + + +def test_diff_cross_model_same_provider(tmp_path: Path, monkeypatch) -> None: + monkeypatch.chdir(tmp_path) + runner = CliRunner() + + assert runner.invoke(cli, ["init"]).exit_code == 0 + + pricing_path = tmp_path / "pricing_openai_multi.yaml" + pricing_data = { + "provider": "openai", + "pricing_version": "openai-2026-04-30", + "entries": [ + { + "model": "gpt-4.1-mini", + "input_usd_per_1k_tokens": 1.0, + "output_usd_per_1k_tokens": 2.0, + }, + { + "model": "gpt-4.1", + "input_usd_per_1k_tokens": 5.0, + "output_usd_per_1k_tokens": 10.0, + }, + ], + } + pricing_path.write_text(yaml.safe_dump(pricing_data, sort_keys=False), encoding="utf-8") + assert runner.invoke(cli, ["pricing", "import", str(pricing_path)]).exit_code == 0 + + baseline_dir = write_release( + tmp_path, + agent_id="agent_support", + version="1", + pricing_provider="openai", + pricing_version="openai-2026-04-30", + model="gpt-4.1-mini", + ) + candidate_dir = write_release( + tmp_path, + agent_id="agent_support", + version="2", + pricing_provider="openai", + pricing_version="openai-2026-04-30", + model="gpt-4.1", + ) + baseline_id = runner.invoke(cli, ["release", "register", str(baseline_dir)]).output.strip() + candidate_id = runner.invoke(cli, ["release", "register", str(candidate_dir)]).output.strip() + + now = datetime.now(tz=timezone.utc) + baseline_events = write_events( + tmp_path, release_id=baseline_id, agent_id="agent_support", n=1, ts=now, model="gpt-4.1-mini" + ) + candidate_events = write_events( + tmp_path, release_id=candidate_id, agent_id="agent_support", n=1, ts=now, model="gpt-4.1" + ) + assert runner.invoke(cli, ["runs", "ingest", str(baseline_events)]).exit_code == 0 + assert runner.invoke(cli, ["runs", "ingest", str(candidate_events)]).exit_code == 0 + + res = runner.invoke(cli, ["release", "diff", baseline_id, candidate_id, "--window", "7d"]) + assert res.exit_code == 0 + assert "(model=gpt-4.1-mini)" in res.output + assert "(model=gpt-4.1)" in res.output + assert "NOTE: cost delta includes pricing/model assumption changes" in res.output diff --git a/web/src/api.ts b/web/src/api.ts index 540adfb..4fb1160 100644 --- a/web/src/api.ts +++ b/web/src/api.ts @@ -39,6 +39,30 @@ export type HealthPayload = { mutation_auth?: "bearer" | "loopback"; }; +export type PolicyResultPayload = { + passed: boolean; + reasons: string[]; + evaluated_at?: string; +}; + +/** + * Response shape for `POST /v1/promote` and `POST /v1/rollback` (HTTP 200). + * Mirrors `_action_body()` in `src/flightdeck/server/routes/actions.py`. + * + * On policy block, the server returns HTTP 409 with `{ detail: { message, outcome } }` + * where `outcome` matches this shape. + */ +export type ActionOutcomePayload = { + action_id: string; + action: "promote" | "rollback"; + release_id: string; + agent_id: string; + environment: string; + baseline_release_id: string | null; + promoted_pointer_changed: boolean; + policy: PolicyResultPayload; +}; + export async function fetchJson(path: string, init?: RequestInit): Promise { const headers = new Headers(init?.headers); const token = import.meta.env.VITE_FLIGHTDECK_LOCAL_API_TOKEN; diff --git a/web/src/pages/ActionsPage.tsx b/web/src/pages/ActionsPage.tsx index a33d45b..7ea5f2c 100644 --- a/web/src/pages/ActionsPage.tsx +++ b/web/src/pages/ActionsPage.tsx @@ -1,21 +1,73 @@ import { useState } from "react"; +import type { ActionOutcomePayload } from "../api"; import { fetchJson } from "../api"; +import { Badge } from "../components/Badge"; import { JsonPanel } from "../components/JsonPanel"; import { useTimelineRefresh } from "../context/TimelineRefreshContext"; +function shortId(id: string, keepStart = 10, keepEnd = 6) { + if (id.length <= keepStart + keepEnd + 1) return id; + return `${id.slice(0, keepStart)}…${id.slice(-keepEnd)}`; +} + +function isRecord(v: unknown): v is Record { + return typeof v === "object" && v !== null; +} + +/** + * Coerces `/v1/promote` and `/v1/rollback` 200 responses into an + * `ActionOutcomePayload`. Returns null for anything that doesn't look like + * the documented contract so we can fall back to the raw JSON panel. + */ +function pickOutcome(data: unknown): ActionOutcomePayload | null { + if (!isRecord(data)) return null; + const policy = data.policy; + if (!isRecord(policy)) return null; + const reasons = Array.isArray(policy.reasons) + ? policy.reasons.filter((r): r is string => typeof r === "string") + : []; + if ( + typeof data.action_id !== "string" || + typeof data.release_id !== "string" || + typeof data.agent_id !== "string" || + typeof data.environment !== "string" || + (data.action !== "promote" && data.action !== "rollback") || + typeof data.promoted_pointer_changed !== "boolean" + ) { + return null; + } + return { + action_id: data.action_id, + action: data.action, + release_id: data.release_id, + agent_id: data.agent_id, + environment: data.environment, + baseline_release_id: + typeof data.baseline_release_id === "string" ? data.baseline_release_id : null, + promoted_pointer_changed: data.promoted_pointer_changed, + policy: { + passed: policy.passed === true, + reasons, + evaluated_at: typeof policy.evaluated_at === "string" ? policy.evaluated_at : undefined, + }, + }; +} + export function ActionsPage() { const { notifyTimelineMutated } = useTimelineRefresh(); const [actRelease, setActRelease] = useState(""); const [actEnv, setActEnv] = useState("local"); const [actWindow, setActWindow] = useState("7d"); const [actReason, setActReason] = useState(""); - const [actOut, setActOut] = useState(null); + const [actOutcome, setActOutcome] = useState(null); + const [actRaw, setActRaw] = useState(null); const [actErr, setActErr] = useState(null); const [busy, setBusy] = useState(null); const runAction = async (path: "/v1/promote" | "/v1/rollback") => { setActErr(null); - setActOut(null); + setActOutcome(null); + setActRaw(null); const reason = actReason.trim(); if (!reason) { setActErr("Reason is required."); @@ -38,7 +90,8 @@ export function ActionsPage() { actor: "react-ui", }), }); - setActOut(JSON.stringify(data, null, 2)); + setActOutcome(pickOutcome(data)); + setActRaw(JSON.stringify(data, null, 2)); notifyTimelineMutated(); } catch (e) { setActErr(String(e)); @@ -100,7 +153,73 @@ export function ActionsPage() { {actErr ?

{actErr}

: null} - {actOut ? : null} + + {actOutcome ? ( +
+
+

+ {actOutcome.action === "promote" ? "Promotion" : "Rollback"} outcome +

+
+ Policy:{" "} + + {actOutcome.policy.passed ? "PASS" : "FAIL"} + +
+
+

+ Pointer:{" "} + + {actOutcome.promoted_pointer_changed ? "Updated" : "Unchanged"} + {" "} + · agent={actOutcome.agent_id} · env={actOutcome.environment} +

+
+
+
Action ID
+
+ + {shortId(actOutcome.action_id)} + +
+
+
+
Release
+
+ + {shortId(actOutcome.release_id)} + +
+
+
+
Previous baseline
+
+ {actOutcome.baseline_release_id ? ( + + {shortId(actOutcome.baseline_release_id)} + + ) : ( + none (first promotion) + )} +
+
+
+ {actOutcome.policy.reasons.length > 0 ? ( +
    + {actOutcome.policy.reasons.map((r) => ( +
  • {r}
  • + ))} +
+ ) : null} +
+ ) : null} + + {actRaw ? ( + + ) : null} ); } diff --git a/web/src/pages/DiffPage.tsx b/web/src/pages/DiffPage.tsx index 5fe4678..3121c92 100644 --- a/web/src/pages/DiffPage.tsx +++ b/web/src/pages/DiffPage.tsx @@ -20,6 +20,35 @@ function pickPolicy(data: DiffJson): { passed: boolean; reasons: string[] } | nu }; } +type PricingInfo = { + baselineProvider: string; + baselineVersion: string; + baselineModel: string; + candidateProvider: string; + candidateVersion: string; + candidateModel: string; + changed: boolean; +}; + +/** + * Coerces the `pricing` block from `/v1/diff` into a typed view. The contract + * is set in `_diff_body()` in `src/flightdeck/server/routes/actions.py`. + */ +function pickPricing(data: DiffJson): PricingInfo | null { + const p = data.pricing; + if (!isRecord(p)) return null; + const get = (k: string): string => (typeof p[k] === "string" ? (p[k] as string) : ""); + return { + baselineProvider: get("baseline_provider"), + baselineVersion: get("baseline_version"), + baselineModel: get("baseline_model"), + candidateProvider: get("candidate_provider"), + candidateVersion: get("candidate_version"), + candidateModel: get("candidate_model"), + changed: p.pricing_or_model_changed === true, + }; +} + function Metric({ label, baseline, @@ -92,6 +121,7 @@ export function DiffPage() { const metrics = isRecord(m) ? m : null; const samples = isRecord(s) ? s : null; const policy = diffOut ? pickPolicy(diffOut) : null; + const pricing = diffOut ? pickPricing(diffOut) : null; const num = (v: unknown) => (typeof v === "number" && Number.isFinite(v) ? String(v) : "—"); const pct = (v: unknown) => @@ -173,6 +203,19 @@ export function DiffPage() { {typeof samples.confidence_reason === "string" ? ` — ${samples.confidence_reason}` : null}

) : null} + {pricing && pricing.changed ? ( +

+ Pricing/model changed:{" "} + + {pricing.baselineProvider}/{pricing.baselineVersion} {pricing.baselineModel} + {" "} + →{" "} + + {pricing.candidateProvider}/{pricing.candidateVersion} {pricing.candidateModel} + + . Cost delta includes pricing and model assumption changes. +

+ ) : null} {metrics ? (
Date: Sat, 2 May 2026 14:22:31 +0200 Subject: [PATCH 2/2] Remove obsolete JavaScript file `index-Be9J5wBP.js` from static assets directory. --- src/flightdeck/server/static/assets/index-B_1jz54d.js | 11 +++++++++++ src/flightdeck/server/static/assets/index-Be9J5wBP.js | 11 ----------- src/flightdeck/server/static/index.html | 2 +- uv.lock | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 src/flightdeck/server/static/assets/index-B_1jz54d.js delete mode 100644 src/flightdeck/server/static/assets/index-Be9J5wBP.js diff --git a/src/flightdeck/server/static/assets/index-B_1jz54d.js b/src/flightdeck/server/static/assets/index-B_1jz54d.js new file mode 100644 index 0000000..4835be5 --- /dev/null +++ b/src/flightdeck/server/static/assets/index-B_1jz54d.js @@ -0,0 +1,11 @@ +(function(){const s=document.createElement("link").relList;if(s&&s.supports&&s.supports("modulepreload"))return;for(const d of document.querySelectorAll('link[rel="modulepreload"]'))f(d);new MutationObserver(d=>{for(const y of d)if(y.type==="childList")for(const b of y.addedNodes)b.tagName==="LINK"&&b.rel==="modulepreload"&&f(b)}).observe(document,{childList:!0,subtree:!0});function o(d){const y={};return d.integrity&&(y.integrity=d.integrity),d.referrerPolicy&&(y.referrerPolicy=d.referrerPolicy),d.crossOrigin==="use-credentials"?y.credentials="include":d.crossOrigin==="anonymous"?y.credentials="omit":y.credentials="same-origin",y}function f(d){if(d.ep)return;d.ep=!0;const y=o(d);fetch(d.href,y)}})();var Cf={exports:{}},jn={};var ih;function vv(){if(ih)return jn;ih=1;var i=Symbol.for("react.transitional.element"),s=Symbol.for("react.fragment");function o(f,d,y){var b=null;if(y!==void 0&&(b=""+y),d.key!==void 0&&(b=""+d.key),"key"in d){y={};for(var R in d)R!=="key"&&(y[R]=d[R])}else y=d;return d=y.ref,{$$typeof:i,type:f,key:b,ref:d!==void 0?d:null,props:y}}return jn.Fragment=s,jn.jsx=o,jn.jsxs=o,jn}var ch;function gv(){return ch||(ch=1,Cf.exports=vv()),Cf.exports}var v=gv(),Uf={exports:{}},I={};var fh;function pv(){if(fh)return I;fh=1;var i=Symbol.for("react.transitional.element"),s=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),f=Symbol.for("react.strict_mode"),d=Symbol.for("react.profiler"),y=Symbol.for("react.consumer"),b=Symbol.for("react.context"),R=Symbol.for("react.forward_ref"),S=Symbol.for("react.suspense"),h=Symbol.for("react.memo"),M=Symbol.for("react.lazy"),x=Symbol.for("react.activity"),B=Symbol.iterator;function $(p){return p===null||typeof p!="object"?null:(p=B&&p[B]||p["@@iterator"],typeof p=="function"?p:null)}var w={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Y=Object.assign,H={};function G(p,U,L){this.props=p,this.context=U,this.refs=H,this.updater=L||w}G.prototype.isReactComponent={},G.prototype.setState=function(p,U){if(typeof p!="object"&&typeof p!="function"&&p!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,p,U,"setState")},G.prototype.forceUpdate=function(p){this.updater.enqueueForceUpdate(this,p,"forceUpdate")};function Q(){}Q.prototype=G.prototype;function J(p,U,L){this.props=p,this.context=U,this.refs=H,this.updater=L||w}var at=J.prototype=new Q;at.constructor=J,Y(at,G.prototype),at.isPureReactComponent=!0;var et=Array.isArray;function bt(){}var X={H:null,A:null,T:null,S:null},Rt=Object.prototype.hasOwnProperty;function wt(p,U,L){var V=L.ref;return{$$typeof:i,type:p,key:U,ref:V!==void 0?V:null,props:L}}function Ce(p,U){return wt(p.type,U,p.props)}function ye(p){return typeof p=="object"&&p!==null&&p.$$typeof===i}function Jt(p){var U={"=":"=0",":":"=2"};return"$"+p.replace(/[=:]/g,function(L){return U[L]})}var Ue=/\/+/g;function ve(p,U){return typeof p=="object"&&p!==null&&p.key!=null?Jt(""+p.key):U.toString(36)}function Ct(p){switch(p.status){case"fulfilled":return p.value;case"rejected":throw p.reason;default:switch(typeof p.status=="string"?p.then(bt,bt):(p.status="pending",p.then(function(U){p.status==="pending"&&(p.status="fulfilled",p.value=U)},function(U){p.status==="pending"&&(p.status="rejected",p.reason=U)})),p.status){case"fulfilled":return p.value;case"rejected":throw p.reason}}throw p}function D(p,U,L,V,P){var nt=typeof p;(nt==="undefined"||nt==="boolean")&&(p=null);var ht=!1;if(p===null)ht=!0;else switch(nt){case"bigint":case"string":case"number":ht=!0;break;case"object":switch(p.$$typeof){case i:case s:ht=!0;break;case M:return ht=p._init,D(ht(p._payload),U,L,V,P)}}if(ht)return P=P(p),ht=V===""?"."+ve(p,0):V,et(P)?(L="",ht!=null&&(L=ht.replace(Ue,"$&/")+"/"),D(P,U,L,"",function(La){return La})):P!=null&&(ye(P)&&(P=Ce(P,L+(P.key==null||p&&p.key===P.key?"":(""+P.key).replace(Ue,"$&/")+"/")+ht)),U.push(P)),1;ht=0;var Wt=V===""?".":V+":";if(et(p))for(var Dt=0;Dt>>1,Et=D[vt];if(0>>1;vtd(L,F))Vd(P,L)?(D[vt]=P,D[V]=F,vt=V):(D[vt]=L,D[U]=F,vt=U);else if(Vd(P,F))D[vt]=P,D[V]=F,vt=V;else break t}}return q}function d(D,q){var F=D.sortIndex-q.sortIndex;return F!==0?F:D.id-q.id}if(i.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var y=performance;i.unstable_now=function(){return y.now()}}else{var b=Date,R=b.now();i.unstable_now=function(){return b.now()-R}}var S=[],h=[],M=1,x=null,B=3,$=!1,w=!1,Y=!1,H=!1,G=typeof setTimeout=="function"?setTimeout:null,Q=typeof clearTimeout=="function"?clearTimeout:null,J=typeof setImmediate<"u"?setImmediate:null;function at(D){for(var q=o(h);q!==null;){if(q.callback===null)f(h);else if(q.startTime<=D)f(h),q.sortIndex=q.expirationTime,s(S,q);else break;q=o(h)}}function et(D){if(Y=!1,at(D),!w)if(o(S)!==null)w=!0,bt||(bt=!0,Jt());else{var q=o(h);q!==null&&Ct(et,q.startTime-D)}}var bt=!1,X=-1,Rt=5,wt=-1;function Ce(){return H?!0:!(i.unstable_now()-wtD&&Ce());){var vt=x.callback;if(typeof vt=="function"){x.callback=null,B=x.priorityLevel;var Et=vt(x.expirationTime<=D);if(D=i.unstable_now(),typeof Et=="function"){x.callback=Et,at(D),q=!0;break e}x===o(S)&&f(S),at(D)}else f(S);x=o(S)}if(x!==null)q=!0;else{var p=o(h);p!==null&&Ct(et,p.startTime-D),q=!1}}break t}finally{x=null,B=F,$=!1}q=void 0}}finally{q?Jt():bt=!1}}}var Jt;if(typeof J=="function")Jt=function(){J(ye)};else if(typeof MessageChannel<"u"){var Ue=new MessageChannel,ve=Ue.port2;Ue.port1.onmessage=ye,Jt=function(){ve.postMessage(null)}}else Jt=function(){G(ye,0)};function Ct(D,q){X=G(function(){D(i.unstable_now())},q)}i.unstable_IdlePriority=5,i.unstable_ImmediatePriority=1,i.unstable_LowPriority=4,i.unstable_NormalPriority=3,i.unstable_Profiling=null,i.unstable_UserBlockingPriority=2,i.unstable_cancelCallback=function(D){D.callback=null},i.unstable_forceFrameRate=function(D){0>D||125vt?(D.sortIndex=F,s(h,D),o(S)===null&&D===o(h)&&(Y?(Q(X),X=-1):Y=!0,Ct(et,F-vt))):(D.sortIndex=Et,s(S,D),w||$||(w=!0,bt||(bt=!0,Jt()))),D},i.unstable_shouldYield=Ce,i.unstable_wrapCallback=function(D){var q=B;return function(){var F=B;B=q;try{return D.apply(this,arguments)}finally{B=F}}}})(qf)),qf}var oh;function bv(){return oh||(oh=1,Bf.exports=Sv()),Bf.exports}var Lf={exports:{}},$t={};var dh;function Ev(){if(dh)return $t;dh=1;var i=$f();function s(S){var h="https://react.dev/errors/"+S;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(i)}catch(s){console.error(s)}}return i(),Lf.exports=Ev(),Lf.exports}var mh;function Tv(){if(mh)return Cn;mh=1;var i=bv(),s=$f(),o=_v();function f(t){var e="https://react.dev/errors/"+t;if(1Et||(t.current=vt[Et],vt[Et]=null,Et--)}function L(t,e){Et++,vt[Et]=t.current,t.current=e}var V=p(null),P=p(null),nt=p(null),ht=p(null);function Wt(t,e){switch(L(nt,e),L(P,t),L(V,null),e.nodeType){case 9:case 11:t=(t=e.documentElement)&&(t=t.namespaceURI)?Od(t):0;break;default:if(t=e.tagName,e=e.namespaceURI)e=Od(e),t=Dd(e,t);else switch(t){case"svg":t=1;break;case"math":t=2;break;default:t=0}}U(V),L(V,t)}function Dt(){U(V),U(P),U(nt)}function La(t){t.memoizedState!==null&&L(ht,t);var e=V.current,l=Dd(e,t.type);e!==l&&(L(P,t),L(V,l))}function Ln(t){P.current===t&&(U(V),U(P)),ht.current===t&&(U(ht),Nn._currentValue=F)}var mi,ns;function Dl(t){if(mi===void 0)try{throw Error()}catch(l){var e=l.stack.trim().match(/\n( *(at )?)/);mi=e&&e[1]||"",ns=-1)":-1n||m[a]!==A[n]){var O=` +`+m[a].replace(" at new "," at ");return t.displayName&&O.includes("")&&(O=O.replace("",t.displayName)),O}while(1<=a&&0<=n);break}}}finally{yi=!1,Error.prepareStackTrace=l}return(l=t?t.displayName||t.name:"")?Dl(l):""}function Jh(t,e){switch(t.tag){case 26:case 27:case 5:return Dl(t.type);case 16:return Dl("Lazy");case 13:return t.child!==e&&e!==null?Dl("Suspense Fallback"):Dl("Suspense");case 19:return Dl("SuspenseList");case 0:case 15:return vi(t.type,!1);case 11:return vi(t.type.render,!1);case 1:return vi(t.type,!0);case 31:return Dl("Activity");default:return""}}function us(t){try{var e="",l=null;do e+=Jh(t,l),l=t,t=t.return;while(t);return e}catch(a){return` +Error generating stack: `+a.message+` +`+a.stack}}var gi=Object.prototype.hasOwnProperty,pi=i.unstable_scheduleCallback,Si=i.unstable_cancelCallback,$h=i.unstable_shouldYield,Wh=i.unstable_requestPaint,ne=i.unstable_now,kh=i.unstable_getCurrentPriorityLevel,is=i.unstable_ImmediatePriority,cs=i.unstable_UserBlockingPriority,Yn=i.unstable_NormalPriority,Fh=i.unstable_LowPriority,fs=i.unstable_IdlePriority,Ih=i.log,Ph=i.unstable_setDisableYieldValue,Ya=null,ue=null;function ul(t){if(typeof Ih=="function"&&Ph(t),ue&&typeof ue.setStrictMode=="function")try{ue.setStrictMode(Ya,t)}catch{}}var ie=Math.clz32?Math.clz32:lm,tm=Math.log,em=Math.LN2;function lm(t){return t>>>=0,t===0?32:31-(tm(t)/em|0)|0}var Gn=256,Xn=262144,Qn=4194304;function Ml(t){var e=t&42;if(e!==0)return e;switch(t&-t){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 t&261888;case 262144:case 524288:case 1048576:case 2097152:return t&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return t&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return t}}function Zn(t,e,l){var a=t.pendingLanes;if(a===0)return 0;var n=0,u=t.suspendedLanes,c=t.pingedLanes;t=t.warmLanes;var r=a&134217727;return r!==0?(a=r&~u,a!==0?n=Ml(a):(c&=r,c!==0?n=Ml(c):l||(l=r&~t,l!==0&&(n=Ml(l))))):(r=a&~u,r!==0?n=Ml(r):c!==0?n=Ml(c):l||(l=a&~t,l!==0&&(n=Ml(l)))),n===0?0:e!==0&&e!==n&&(e&u)===0&&(u=n&-n,l=e&-e,u>=l||u===32&&(l&4194048)!==0)?e:n}function Ga(t,e){return(t.pendingLanes&~(t.suspendedLanes&~t.pingedLanes)&e)===0}function am(t,e){switch(t){case 1:case 2:case 4:case 8:case 64:return e+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 e+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function ss(){var t=Qn;return Qn<<=1,(Qn&62914560)===0&&(Qn=4194304),t}function bi(t){for(var e=[],l=0;31>l;l++)e.push(t);return e}function Xa(t,e){t.pendingLanes|=e,e!==268435456&&(t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0)}function nm(t,e,l,a,n,u){var c=t.pendingLanes;t.pendingLanes=l,t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0,t.expiredLanes&=l,t.entangledLanes&=l,t.errorRecoveryDisabledLanes&=l,t.shellSuspendCounter=0;var r=t.entanglements,m=t.expirationTimes,A=t.hiddenUpdates;for(l=c&~l;0"u")return null;try{return t.activeElement||t.body}catch{return t.body}}var rm=/[\n"\\]/g;function pe(t){return t.replace(rm,function(e){return"\\"+e.charCodeAt(0).toString(16)+" "})}function xi(t,e,l,a,n,u,c,r){t.name="",c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"?t.type=c:t.removeAttribute("type"),e!=null?c==="number"?(e===0&&t.value===""||t.value!=e)&&(t.value=""+ge(e)):t.value!==""+ge(e)&&(t.value=""+ge(e)):c!=="submit"&&c!=="reset"||t.removeAttribute("value"),e!=null?Ri(t,c,ge(e)):l!=null?Ri(t,c,ge(l)):a!=null&&t.removeAttribute("value"),n==null&&u!=null&&(t.defaultChecked=!!u),n!=null&&(t.checked=n&&typeof n!="function"&&typeof n!="symbol"),r!=null&&typeof r!="function"&&typeof r!="symbol"&&typeof r!="boolean"?t.name=""+ge(r):t.removeAttribute("name")}function _s(t,e,l,a,n,u,c,r){if(u!=null&&typeof u!="function"&&typeof u!="symbol"&&typeof u!="boolean"&&(t.type=u),e!=null||l!=null){if(!(u!=="submit"&&u!=="reset"||e!=null)){zi(t);return}l=l!=null?""+ge(l):"",e=e!=null?""+ge(e):l,r||e===t.value||(t.value=e),t.defaultValue=e}a=a??n,a=typeof a!="function"&&typeof a!="symbol"&&!!a,t.checked=r?t.checked:!!a,t.defaultChecked=!!a,c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"&&(t.name=c),zi(t)}function Ri(t,e,l){e==="number"&&wn(t.ownerDocument)===t||t.defaultValue===""+l||(t.defaultValue=""+l)}function ea(t,e,l,a){if(t=t.options,e){e={};for(var n=0;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),ji=!1;if(Qe)try{var Ka={};Object.defineProperty(Ka,"passive",{get:function(){ji=!0}}),window.addEventListener("test",Ka,Ka),window.removeEventListener("test",Ka,Ka)}catch{ji=!1}var cl=null,Ci=null,$n=null;function Os(){if($n)return $n;var t,e=Ci,l=e.length,a,n="value"in cl?cl.value:cl.textContent,u=n.length;for(t=0;t=$a),Hs=" ",Bs=!1;function qs(t,e){switch(t){case"keyup":return Lm.indexOf(e.keyCode)!==-1;case"keydown":return e.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Ls(t){return t=t.detail,typeof t=="object"&&"data"in t?t.data:null}var ua=!1;function Gm(t,e){switch(t){case"compositionend":return Ls(e);case"keypress":return e.which!==32?null:(Bs=!0,Hs);case"textInput":return t=e.data,t===Hs&&Bs?null:t;default:return null}}function Xm(t,e){if(ua)return t==="compositionend"||!Li&&qs(t,e)?(t=Os(),$n=Ci=cl=null,ua=!1,t):null;switch(t){case"paste":return null;case"keypress":if(!(e.ctrlKey||e.altKey||e.metaKey)||e.ctrlKey&&e.altKey){if(e.char&&1=e)return{node:l,offset:e-t};t=a}t:{for(;l;){if(l.nextSibling){l=l.nextSibling;break t}l=l.parentNode}l=void 0}l=ws(l)}}function $s(t,e){return t&&e?t===e?!0:t&&t.nodeType===3?!1:e&&e.nodeType===3?$s(t,e.parentNode):"contains"in t?t.contains(e):t.compareDocumentPosition?!!(t.compareDocumentPosition(e)&16):!1:!1}function Ws(t){t=t!=null&&t.ownerDocument!=null&&t.ownerDocument.defaultView!=null?t.ownerDocument.defaultView:window;for(var e=wn(t.document);e instanceof t.HTMLIFrameElement;){try{var l=typeof e.contentWindow.location.href=="string"}catch{l=!1}if(l)t=e.contentWindow;else break;e=wn(t.document)}return e}function Xi(t){var e=t&&t.nodeName&&t.nodeName.toLowerCase();return e&&(e==="input"&&(t.type==="text"||t.type==="search"||t.type==="tel"||t.type==="url"||t.type==="password")||e==="textarea"||t.contentEditable==="true")}var Wm=Qe&&"documentMode"in document&&11>=document.documentMode,ia=null,Qi=null,Ia=null,Zi=!1;function ks(t,e,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;Zi||ia==null||ia!==wn(a)||(a=ia,"selectionStart"in a&&Xi(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),Ia&&Fa(Ia,a)||(Ia=a,a=Xu(Qi,"onSelect"),0>=c,n-=c,He=1<<32-ie(e)+n|l<lt?(ft=K,K=null):ft=K.sibling;var ot=z(E,K,_[lt],j);if(ot===null){K===null&&(K=ft);break}t&&K&&ot.alternate===null&&e(E,K),g=u(ot,g,lt),rt===null?W=ot:rt.sibling=ot,rt=ot,K=ft}if(lt===_.length)return l(E,K),st&&Ve(E,lt),W;if(K===null){for(;lt<_.length;lt++)K=C(E,_[lt],j),K!==null&&(g=u(K,g,lt),rt===null?W=K:rt.sibling=K,rt=K);return st&&Ve(E,lt),W}for(K=a(K);lt<_.length;lt++)ft=N(K,E,lt,_[lt],j),ft!==null&&(t&&ft.alternate!==null&&K.delete(ft.key===null?lt:ft.key),g=u(ft,g,lt),rt===null?W=ft:rt.sibling=ft,rt=ft);return t&&K.forEach(function(Ol){return e(E,Ol)}),st&&Ve(E,lt),W}function k(E,g,_,j){if(_==null)throw Error(f(151));for(var W=null,rt=null,K=g,lt=g=0,ft=null,ot=_.next();K!==null&&!ot.done;lt++,ot=_.next()){K.index>lt?(ft=K,K=null):ft=K.sibling;var Ol=z(E,K,ot.value,j);if(Ol===null){K===null&&(K=ft);break}t&&K&&Ol.alternate===null&&e(E,K),g=u(Ol,g,lt),rt===null?W=Ol:rt.sibling=Ol,rt=Ol,K=ft}if(ot.done)return l(E,K),st&&Ve(E,lt),W;if(K===null){for(;!ot.done;lt++,ot=_.next())ot=C(E,ot.value,j),ot!==null&&(g=u(ot,g,lt),rt===null?W=ot:rt.sibling=ot,rt=ot);return st&&Ve(E,lt),W}for(K=a(K);!ot.done;lt++,ot=_.next())ot=N(K,E,lt,ot.value,j),ot!==null&&(t&&ot.alternate!==null&&K.delete(ot.key===null?lt:ot.key),g=u(ot,g,lt),rt===null?W=ot:rt.sibling=ot,rt=ot);return t&&K.forEach(function(yv){return e(E,yv)}),st&&Ve(E,lt),W}function St(E,g,_,j){if(typeof _=="object"&&_!==null&&_.type===Y&&_.key===null&&(_=_.props.children),typeof _=="object"&&_!==null){switch(_.$$typeof){case $:t:{for(var W=_.key;g!==null;){if(g.key===W){if(W=_.type,W===Y){if(g.tag===7){l(E,g.sibling),j=n(g,_.props.children),j.return=E,E=j;break t}}else if(g.elementType===W||typeof W=="object"&&W!==null&&W.$$typeof===Rt&&Ql(W)===g.type){l(E,g.sibling),j=n(g,_.props),nn(j,_),j.return=E,E=j;break t}l(E,g);break}else e(E,g);g=g.sibling}_.type===Y?(j=ql(_.props.children,E.mode,j,_.key),j.return=E,E=j):(j=nu(_.type,_.key,_.props,null,E.mode,j),nn(j,_),j.return=E,E=j)}return c(E);case w:t:{for(W=_.key;g!==null;){if(g.key===W)if(g.tag===4&&g.stateNode.containerInfo===_.containerInfo&&g.stateNode.implementation===_.implementation){l(E,g.sibling),j=n(g,_.children||[]),j.return=E,E=j;break t}else{l(E,g);break}else e(E,g);g=g.sibling}j=ki(_,E.mode,j),j.return=E,E=j}return c(E);case Rt:return _=Ql(_),St(E,g,_,j)}if(Ct(_))return Z(E,g,_,j);if(Jt(_)){if(W=Jt(_),typeof W!="function")throw Error(f(150));return _=W.call(_),k(E,g,_,j)}if(typeof _.then=="function")return St(E,g,ou(_),j);if(_.$$typeof===J)return St(E,g,cu(E,_),j);du(E,_)}return typeof _=="string"&&_!==""||typeof _=="number"||typeof _=="bigint"?(_=""+_,g!==null&&g.tag===6?(l(E,g.sibling),j=n(g,_),j.return=E,E=j):(l(E,g),j=Wi(_,E.mode,j),j.return=E,E=j),c(E)):l(E,g)}return function(E,g,_,j){try{an=0;var W=St(E,g,_,j);return ga=null,W}catch(K){if(K===va||K===su)throw K;var rt=fe(29,K,null,E.mode);return rt.lanes=j,rt.return=E,rt}}}var Vl=Sr(!0),br=Sr(!1),dl=!1;function fc(t){t.updateQueue={baseState:t.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function sc(t,e){t=t.updateQueue,e.updateQueue===t&&(e.updateQueue={baseState:t.baseState,firstBaseUpdate:t.firstBaseUpdate,lastBaseUpdate:t.lastBaseUpdate,shared:t.shared,callbacks:null})}function hl(t){return{lane:t,tag:0,payload:null,callback:null,next:null}}function ml(t,e,l){var a=t.updateQueue;if(a===null)return null;if(a=a.shared,(dt&2)!==0){var n=a.pending;return n===null?e.next=e:(e.next=n.next,n.next=e),a.pending=e,e=au(t),ar(t,null,l),e}return lu(t,a,e,l),au(t)}function un(t,e,l){if(e=e.updateQueue,e!==null&&(e=e.shared,(l&4194048)!==0)){var a=e.lanes;a&=t.pendingLanes,l|=a,e.lanes=l,os(t,l)}}function rc(t,e){var l=t.updateQueue,a=t.alternate;if(a!==null&&(a=a.updateQueue,l===a)){var n=null,u=null;if(l=l.firstBaseUpdate,l!==null){do{var c={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};u===null?n=u=c:u=u.next=c,l=l.next}while(l!==null);u===null?n=u=e:u=u.next=e}else n=u=e;l={baseState:a.baseState,firstBaseUpdate:n,lastBaseUpdate:u,shared:a.shared,callbacks:a.callbacks},t.updateQueue=l;return}t=l.lastBaseUpdate,t===null?l.firstBaseUpdate=e:t.next=e,l.lastBaseUpdate=e}var oc=!1;function cn(){if(oc){var t=ya;if(t!==null)throw t}}function fn(t,e,l,a){oc=!1;var n=t.updateQueue;dl=!1;var u=n.firstBaseUpdate,c=n.lastBaseUpdate,r=n.shared.pending;if(r!==null){n.shared.pending=null;var m=r,A=m.next;m.next=null,c===null?u=A:c.next=A,c=m;var O=t.alternate;O!==null&&(O=O.updateQueue,r=O.lastBaseUpdate,r!==c&&(r===null?O.firstBaseUpdate=A:r.next=A,O.lastBaseUpdate=m))}if(u!==null){var C=n.baseState;c=0,O=A=m=null,r=u;do{var z=r.lane&-536870913,N=z!==r.lane;if(N?(ct&z)===z:(a&z)===z){z!==0&&z===ma&&(oc=!0),O!==null&&(O=O.next={lane:0,tag:r.tag,payload:r.payload,callback:null,next:null});t:{var Z=t,k=r;z=e;var St=l;switch(k.tag){case 1:if(Z=k.payload,typeof Z=="function"){C=Z.call(St,C,z);break t}C=Z;break t;case 3:Z.flags=Z.flags&-65537|128;case 0:if(Z=k.payload,z=typeof Z=="function"?Z.call(St,C,z):Z,z==null)break t;C=x({},C,z);break t;case 2:dl=!0}}z=r.callback,z!==null&&(t.flags|=64,N&&(t.flags|=8192),N=n.callbacks,N===null?n.callbacks=[z]:N.push(z))}else N={lane:z,tag:r.tag,payload:r.payload,callback:r.callback,next:null},O===null?(A=O=N,m=C):O=O.next=N,c|=z;if(r=r.next,r===null){if(r=n.shared.pending,r===null)break;N=r,r=N.next,N.next=null,n.lastBaseUpdate=N,n.shared.pending=null}}while(!0);O===null&&(m=C),n.baseState=m,n.firstBaseUpdate=A,n.lastBaseUpdate=O,u===null&&(n.shared.lanes=0),Sl|=c,t.lanes=c,t.memoizedState=C}}function Er(t,e){if(typeof t!="function")throw Error(f(191,t));t.call(e)}function _r(t,e){var l=t.callbacks;if(l!==null)for(t.callbacks=null,t=0;tu?u:8;var c=D.T,r={};D.T=r,Dc(t,!1,e,l);try{var m=n(),A=D.S;if(A!==null&&A(r,m),m!==null&&typeof m=="object"&&typeof m.then=="function"){var O=ny(m,a);on(t,e,O,he(t))}else on(t,e,a,he(t))}catch(C){on(t,e,{then:function(){},status:"rejected",reason:C},he())}finally{q.p=u,c!==null&&r.types!==null&&(c.types=r.types),D.T=c}}function ry(){}function Nc(t,e,l,a){if(t.tag!==5)throw Error(f(476));var n=to(t).queue;Pr(t,n,e,F,l===null?ry:function(){return eo(t),l(a)})}function to(t){var e=t.memoizedState;if(e!==null)return e;e={memoizedState:F,baseState:F,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:$e,lastRenderedState:F},next:null};var l={};return e.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:$e,lastRenderedState:l},next:null},t.memoizedState=e,t=t.alternate,t!==null&&(t.memoizedState=e),e}function eo(t){var e=to(t);e.next===null&&(e=t.alternate.memoizedState),on(t,e.next.queue,{},he())}function Oc(){return Zt(Nn)}function lo(){return jt().memoizedState}function ao(){return jt().memoizedState}function oy(t){for(var e=t.return;e!==null;){switch(e.tag){case 24:case 3:var l=he();t=hl(l);var a=ml(e,t,l);a!==null&&(ae(a,e,l),un(a,e,l)),e={cache:nc()},t.payload=e;return}e=e.return}}function dy(t,e,l){var a=he();l={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},_u(t)?uo(e,l):(l=Ji(t,e,l,a),l!==null&&(ae(l,t,a),io(l,e,a)))}function no(t,e,l){var a=he();on(t,e,l,a)}function on(t,e,l,a){var n={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(_u(t))uo(e,n);else{var u=t.alternate;if(t.lanes===0&&(u===null||u.lanes===0)&&(u=e.lastRenderedReducer,u!==null))try{var c=e.lastRenderedState,r=u(c,l);if(n.hasEagerState=!0,n.eagerState=r,ce(r,c))return lu(t,e,n,0),_t===null&&eu(),!1}catch{}if(l=Ji(t,e,n,a),l!==null)return ae(l,t,a),io(l,e,a),!0}return!1}function Dc(t,e,l,a){if(a={lane:2,revertLane:sf(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},_u(t)){if(e)throw Error(f(479))}else e=Ji(t,l,a,2),e!==null&&ae(e,t,2)}function _u(t){var e=t.alternate;return t===tt||e!==null&&e===tt}function uo(t,e){Sa=yu=!0;var l=t.pending;l===null?e.next=e:(e.next=l.next,l.next=e),t.pending=e}function io(t,e,l){if((l&4194048)!==0){var a=e.lanes;a&=t.pendingLanes,l|=a,e.lanes=l,os(t,l)}}var dn={readContext:Zt,use:pu,useCallback:Nt,useContext:Nt,useEffect:Nt,useImperativeHandle:Nt,useLayoutEffect:Nt,useInsertionEffect:Nt,useMemo:Nt,useReducer:Nt,useRef:Nt,useState:Nt,useDebugValue:Nt,useDeferredValue:Nt,useTransition:Nt,useSyncExternalStore:Nt,useId:Nt,useHostTransitionStatus:Nt,useFormState:Nt,useActionState:Nt,useOptimistic:Nt,useMemoCache:Nt,useCacheRefresh:Nt};dn.useEffectEvent=Nt;var co={readContext:Zt,use:pu,useCallback:function(t,e){return kt().memoizedState=[t,e===void 0?null:e],t},useContext:Zt,useEffect:Vr,useImperativeHandle:function(t,e,l){l=l!=null?l.concat([t]):null,bu(4194308,4,$r.bind(null,e,t),l)},useLayoutEffect:function(t,e){return bu(4194308,4,t,e)},useInsertionEffect:function(t,e){bu(4,2,t,e)},useMemo:function(t,e){var l=kt();e=e===void 0?null:e;var a=t();if(Kl){ul(!0);try{t()}finally{ul(!1)}}return l.memoizedState=[a,e],a},useReducer:function(t,e,l){var a=kt();if(l!==void 0){var n=l(e);if(Kl){ul(!0);try{l(e)}finally{ul(!1)}}}else n=e;return a.memoizedState=a.baseState=n,t={pending:null,lanes:0,dispatch:null,lastRenderedReducer:t,lastRenderedState:n},a.queue=t,t=t.dispatch=dy.bind(null,tt,t),[a.memoizedState,t]},useRef:function(t){var e=kt();return t={current:t},e.memoizedState=t},useState:function(t){t=Tc(t);var e=t.queue,l=no.bind(null,tt,e);return e.dispatch=l,[t.memoizedState,l]},useDebugValue:xc,useDeferredValue:function(t,e){var l=kt();return Rc(l,t,e)},useTransition:function(){var t=Tc(!1);return t=Pr.bind(null,tt,t.queue,!0,!1),kt().memoizedState=t,[!1,t]},useSyncExternalStore:function(t,e,l){var a=tt,n=kt();if(st){if(l===void 0)throw Error(f(407));l=l()}else{if(l=e(),_t===null)throw Error(f(349));(ct&127)!==0||Nr(a,e,l)}n.memoizedState=l;var u={value:l,getSnapshot:e};return n.queue=u,Vr(Dr.bind(null,a,u,t),[t]),a.flags|=2048,Ea(9,{destroy:void 0},Or.bind(null,a,u,l,e),null),l},useId:function(){var t=kt(),e=_t.identifierPrefix;if(st){var l=Be,a=He;l=(a&~(1<<32-ie(a)-1)).toString(32)+l,e="_"+e+"R_"+l,l=vu++,0<\/script>",u=u.removeChild(u.firstChild);break;case"select":u=typeof a.is=="string"?c.createElement("select",{is:a.is}):c.createElement("select"),a.multiple?u.multiple=!0:a.size&&(u.size=a.size);break;default:u=typeof a.is=="string"?c.createElement(n,{is:a.is}):c.createElement(n)}}u[Xt]=e,u[Ft]=a;t:for(c=e.child;c!==null;){if(c.tag===5||c.tag===6)u.appendChild(c.stateNode);else if(c.tag!==4&&c.tag!==27&&c.child!==null){c.child.return=c,c=c.child;continue}if(c===e)break t;for(;c.sibling===null;){if(c.return===null||c.return===e)break t;c=c.return}c.sibling.return=c.return,c=c.sibling}e.stateNode=u;t:switch(Kt(u,n,a),n){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break t;case"img":a=!0;break t;default:a=!1}a&&ke(e)}}return At(e),Vc(e,e.type,t===null?null:t.memoizedProps,e.pendingProps,l),null;case 6:if(t&&e.stateNode!=null)t.memoizedProps!==a&&ke(e);else{if(typeof a!="string"&&e.stateNode===null)throw Error(f(166));if(t=nt.current,da(e)){if(t=e.stateNode,l=e.memoizedProps,a=null,n=Qt,n!==null)switch(n.tag){case 27:case 5:a=n.memoizedProps}t[Xt]=e,t=!!(t.nodeValue===l||a!==null&&a.suppressHydrationWarning===!0||Rd(t.nodeValue,l)),t||rl(e,!0)}else t=Qu(t).createTextNode(a),t[Xt]=e,e.stateNode=t}return At(e),null;case 31:if(l=e.memoizedState,t===null||t.memoizedState!==null){if(a=da(e),l!==null){if(t===null){if(!a)throw Error(f(318));if(t=e.memoizedState,t=t!==null?t.dehydrated:null,!t)throw Error(f(557));t[Xt]=e}else Ll(),(e.flags&128)===0&&(e.memoizedState=null),e.flags|=4;At(e),t=!1}else l=tc(),t!==null&&t.memoizedState!==null&&(t.memoizedState.hydrationErrors=l),t=!0;if(!t)return e.flags&256?(re(e),e):(re(e),null);if((e.flags&128)!==0)throw Error(f(558))}return At(e),null;case 13:if(a=e.memoizedState,t===null||t.memoizedState!==null&&t.memoizedState.dehydrated!==null){if(n=da(e),a!==null&&a.dehydrated!==null){if(t===null){if(!n)throw Error(f(318));if(n=e.memoizedState,n=n!==null?n.dehydrated:null,!n)throw Error(f(317));n[Xt]=e}else Ll(),(e.flags&128)===0&&(e.memoizedState=null),e.flags|=4;At(e),n=!1}else n=tc(),t!==null&&t.memoizedState!==null&&(t.memoizedState.hydrationErrors=n),n=!0;if(!n)return e.flags&256?(re(e),e):(re(e),null)}return re(e),(e.flags&128)!==0?(e.lanes=l,e):(l=a!==null,t=t!==null&&t.memoizedState!==null,l&&(a=e.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!==t&&l&&(e.child.flags|=8192),Ru(e,e.updateQueue),At(e),null);case 4:return Dt(),t===null&&hf(e.stateNode.containerInfo),At(e),null;case 10:return we(e.type),At(e),null;case 19:if(U(Mt),a=e.memoizedState,a===null)return At(e),null;if(n=(e.flags&128)!==0,u=a.rendering,u===null)if(n)mn(a,!1);else{if(Ot!==0||t!==null&&(t.flags&128)!==0)for(t=e.child;t!==null;){if(u=mu(t),u!==null){for(e.flags|=128,mn(a,!1),t=u.updateQueue,e.updateQueue=t,Ru(e,t),e.subtreeFlags=0,t=l,l=e.child;l!==null;)nr(l,t),l=l.sibling;return L(Mt,Mt.current&1|2),st&&Ve(e,a.treeForkCount),e.child}t=t.sibling}a.tail!==null&&ne()>ju&&(e.flags|=128,n=!0,mn(a,!1),e.lanes=4194304)}else{if(!n)if(t=mu(u),t!==null){if(e.flags|=128,n=!0,t=t.updateQueue,e.updateQueue=t,Ru(e,t),mn(a,!0),a.tail===null&&a.tailMode==="hidden"&&!u.alternate&&!st)return At(e),null}else 2*ne()-a.renderingStartTime>ju&&l!==536870912&&(e.flags|=128,n=!0,mn(a,!1),e.lanes=4194304);a.isBackwards?(u.sibling=e.child,e.child=u):(t=a.last,t!==null?t.sibling=u:e.child=u,a.last=u)}return a.tail!==null?(t=a.tail,a.rendering=t,a.tail=t.sibling,a.renderingStartTime=ne(),t.sibling=null,l=Mt.current,L(Mt,n?l&1|2:l&1),st&&Ve(e,a.treeForkCount),t):(At(e),null);case 22:case 23:return re(e),hc(),a=e.memoizedState!==null,t!==null?t.memoizedState!==null!==a&&(e.flags|=8192):a&&(e.flags|=8192),a?(l&536870912)!==0&&(e.flags&128)===0&&(At(e),e.subtreeFlags&6&&(e.flags|=8192)):At(e),l=e.updateQueue,l!==null&&Ru(e,l.retryQueue),l=null,t!==null&&t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(l=t.memoizedState.cachePool.pool),a=null,e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(a=e.memoizedState.cachePool.pool),a!==l&&(e.flags|=2048),t!==null&&U(Xl),null;case 24:return l=null,t!==null&&(l=t.memoizedState.cache),e.memoizedState.cache!==l&&(e.flags|=2048),we(Ut),At(e),null;case 25:return null;case 30:return null}throw Error(f(156,e.tag))}function gy(t,e){switch(Ii(e),e.tag){case 1:return t=e.flags,t&65536?(e.flags=t&-65537|128,e):null;case 3:return we(Ut),Dt(),t=e.flags,(t&65536)!==0&&(t&128)===0?(e.flags=t&-65537|128,e):null;case 26:case 27:case 5:return Ln(e),null;case 31:if(e.memoizedState!==null){if(re(e),e.alternate===null)throw Error(f(340));Ll()}return t=e.flags,t&65536?(e.flags=t&-65537|128,e):null;case 13:if(re(e),t=e.memoizedState,t!==null&&t.dehydrated!==null){if(e.alternate===null)throw Error(f(340));Ll()}return t=e.flags,t&65536?(e.flags=t&-65537|128,e):null;case 19:return U(Mt),null;case 4:return Dt(),null;case 10:return we(e.type),null;case 22:case 23:return re(e),hc(),t!==null&&U(Xl),t=e.flags,t&65536?(e.flags=t&-65537|128,e):null;case 24:return we(Ut),null;case 25:return null;default:return null}}function jo(t,e){switch(Ii(e),e.tag){case 3:we(Ut),Dt();break;case 26:case 27:case 5:Ln(e);break;case 4:Dt();break;case 31:e.memoizedState!==null&&re(e);break;case 13:re(e);break;case 19:U(Mt);break;case 10:we(e.type);break;case 22:case 23:re(e),hc(),t!==null&&U(Xl);break;case 24:we(Ut)}}function yn(t,e){try{var l=e.updateQueue,a=l!==null?l.lastEffect:null;if(a!==null){var n=a.next;l=n;do{if((l.tag&t)===t){a=void 0;var u=l.create,c=l.inst;a=u(),c.destroy=a}l=l.next}while(l!==n)}}catch(r){yt(e,e.return,r)}}function gl(t,e,l){try{var a=e.updateQueue,n=a!==null?a.lastEffect:null;if(n!==null){var u=n.next;a=u;do{if((a.tag&t)===t){var c=a.inst,r=c.destroy;if(r!==void 0){c.destroy=void 0,n=e;var m=l,A=r;try{A()}catch(O){yt(n,m,O)}}}a=a.next}while(a!==u)}}catch(O){yt(e,e.return,O)}}function Co(t){var e=t.updateQueue;if(e!==null){var l=t.stateNode;try{_r(e,l)}catch(a){yt(t,t.return,a)}}}function Uo(t,e,l){l.props=wl(t.type,t.memoizedProps),l.state=t.memoizedState;try{l.componentWillUnmount()}catch(a){yt(t,e,a)}}function vn(t,e){try{var l=t.ref;if(l!==null){switch(t.tag){case 26:case 27:case 5:var a=t.stateNode;break;case 30:a=t.stateNode;break;default:a=t.stateNode}typeof l=="function"?t.refCleanup=l(a):l.current=a}}catch(n){yt(t,e,n)}}function qe(t,e){var l=t.ref,a=t.refCleanup;if(l!==null)if(typeof a=="function")try{a()}catch(n){yt(t,e,n)}finally{t.refCleanup=null,t=t.alternate,t!=null&&(t.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(n){yt(t,e,n)}else l.current=null}function Ho(t){var e=t.type,l=t.memoizedProps,a=t.stateNode;try{t:switch(e){case"button":case"input":case"select":case"textarea":l.autoFocus&&a.focus();break t;case"img":l.src?a.src=l.src:l.srcSet&&(a.srcset=l.srcSet)}}catch(n){yt(t,t.return,n)}}function Kc(t,e,l){try{var a=t.stateNode;Yy(a,t.type,l,e),a[Ft]=e}catch(n){yt(t,t.return,n)}}function Bo(t){return t.tag===5||t.tag===3||t.tag===26||t.tag===27&&Al(t.type)||t.tag===4}function wc(t){t:for(;;){for(;t.sibling===null;){if(t.return===null||Bo(t.return))return null;t=t.return}for(t.sibling.return=t.return,t=t.sibling;t.tag!==5&&t.tag!==6&&t.tag!==18;){if(t.tag===27&&Al(t.type)||t.flags&2||t.child===null||t.tag===4)continue t;t.child.return=t,t=t.child}if(!(t.flags&2))return t.stateNode}}function Jc(t,e,l){var a=t.tag;if(a===5||a===6)t=t.stateNode,e?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(t,e):(e=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,e.appendChild(t),l=l._reactRootContainer,l!=null||e.onclick!==null||(e.onclick=Xe));else if(a!==4&&(a===27&&Al(t.type)&&(l=t.stateNode,e=null),t=t.child,t!==null))for(Jc(t,e,l),t=t.sibling;t!==null;)Jc(t,e,l),t=t.sibling}function Nu(t,e,l){var a=t.tag;if(a===5||a===6)t=t.stateNode,e?l.insertBefore(t,e):l.appendChild(t);else if(a!==4&&(a===27&&Al(t.type)&&(l=t.stateNode),t=t.child,t!==null))for(Nu(t,e,l),t=t.sibling;t!==null;)Nu(t,e,l),t=t.sibling}function qo(t){var e=t.stateNode,l=t.memoizedProps;try{for(var a=t.type,n=e.attributes;n.length;)e.removeAttributeNode(n[0]);Kt(e,a,l),e[Xt]=t,e[Ft]=l}catch(u){yt(t,t.return,u)}}var Fe=!1,qt=!1,$c=!1,Lo=typeof WeakSet=="function"?WeakSet:Set,Gt=null;function py(t,e){if(t=t.containerInfo,vf=Wu,t=Ws(t),Xi(t)){if("selectionStart"in t)var l={start:t.selectionStart,end:t.selectionEnd};else t:{l=(l=t.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 t}var c=0,r=-1,m=-1,A=0,O=0,C=t,z=null;e:for(;;){for(var N;C!==l||n!==0&&C.nodeType!==3||(r=c+n),C!==u||a!==0&&C.nodeType!==3||(m=c+a),C.nodeType===3&&(c+=C.nodeValue.length),(N=C.firstChild)!==null;)z=C,C=N;for(;;){if(C===t)break e;if(z===l&&++A===n&&(r=c),z===u&&++O===a&&(m=c),(N=C.nextSibling)!==null)break;C=z,z=C.parentNode}C=N}l=r===-1||m===-1?null:{start:r,end:m}}else l=null}l=l||{start:0,end:0}}else l=null;for(gf={focusedElem:t,selectionRange:l},Wu=!1,Gt=e;Gt!==null;)if(e=Gt,t=e.child,(e.subtreeFlags&1028)!==0&&t!==null)t.return=e,Gt=t;else for(;Gt!==null;){switch(e=Gt,u=e.alternate,t=e.flags,e.tag){case 0:if((t&4)!==0&&(t=e.updateQueue,t=t!==null?t.events:null,t!==null))for(l=0;l title"))),Kt(u,a,l),u[Xt]=t,Yt(u),a=u;break t;case"link":var c=Vd("link","href",n).get(a+(l.href||""));if(c){for(var r=0;rSt&&(c=St,St=k,k=c);var E=Js(r,k),g=Js(r,St);if(E&&g&&(N.rangeCount!==1||N.anchorNode!==E.node||N.anchorOffset!==E.offset||N.focusNode!==g.node||N.focusOffset!==g.offset)){var _=C.createRange();_.setStart(E.node,E.offset),N.removeAllRanges(),k>St?(N.addRange(_),N.extend(g.node,g.offset)):(_.setEnd(g.node,g.offset),N.addRange(_))}}}}for(C=[],N=r;N=N.parentNode;)N.nodeType===1&&C.push({element:N,left:N.scrollLeft,top:N.scrollTop});for(typeof r.focus=="function"&&r.focus(),r=0;rl?32:l,D.T=null,l=ef,ef=null;var u=El,c=ll;if(Lt=0,xa=El=null,ll=0,(dt&6)!==0)throw Error(f(331));var r=dt;if(dt|=4,Wo(u.current),wo(u,u.current,c,l),dt=r,_n(0,!1),ue&&typeof ue.onPostCommitFiberRoot=="function")try{ue.onPostCommitFiberRoot(Ya,u)}catch{}return!0}finally{q.p=n,D.T=a,hd(t,e)}}function yd(t,e,l){e=be(l,e),e=Uc(t.stateNode,e,2),t=ml(t,e,2),t!==null&&(Xa(t,2),Le(t))}function yt(t,e,l){if(t.tag===3)yd(t,t,l);else for(;e!==null;){if(e.tag===3){yd(e,t,l);break}else if(e.tag===1){var a=e.stateNode;if(typeof e.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(bl===null||!bl.has(a))){t=be(l,t),l=vo(2),a=ml(e,l,2),a!==null&&(go(l,a,e,t),Xa(a,2),Le(a));break}}e=e.return}}function uf(t,e,l){var a=t.pingCache;if(a===null){a=t.pingCache=new Ey;var n=new Set;a.set(e,n)}else n=a.get(e),n===void 0&&(n=new Set,a.set(e,n));n.has(l)||(Fc=!0,n.add(l),t=xy.bind(null,t,e,l),e.then(t,t))}function xy(t,e,l){var a=t.pingCache;a!==null&&a.delete(e),t.pingedLanes|=t.suspendedLanes&l,t.warmLanes&=~l,_t===t&&(ct&l)===l&&(Ot===4||Ot===3&&(ct&62914560)===ct&&300>ne()-Mu?(dt&2)===0&&Ra(t,0):Ic|=l,za===ct&&(za=0)),Le(t)}function vd(t,e){e===0&&(e=ss()),t=Bl(t,e),t!==null&&(Xa(t,e),Le(t))}function Ry(t){var e=t.memoizedState,l=0;e!==null&&(l=e.retryLane),vd(t,l)}function Ny(t,e){var l=0;switch(t.tag){case 31:case 13:var a=t.stateNode,n=t.memoizedState;n!==null&&(l=n.retryLane);break;case 19:a=t.stateNode;break;case 22:a=t.stateNode._retryCache;break;default:throw Error(f(314))}a!==null&&a.delete(e),vd(t,l)}function Oy(t,e){return pi(t,e)}var Lu=null,Oa=null,cf=!1,Yu=!1,ff=!1,Tl=0;function Le(t){t!==Oa&&t.next===null&&(Oa===null?Lu=Oa=t:Oa=Oa.next=t),Yu=!0,cf||(cf=!0,My())}function _n(t,e){if(!ff&&Yu){ff=!0;do for(var l=!1,a=Lu;a!==null;){if(t!==0){var n=a.pendingLanes;if(n===0)var u=0;else{var c=a.suspendedLanes,r=a.pingedLanes;u=(1<<31-ie(42|t)+1)-1,u&=n&~(c&~r),u=u&201326741?u&201326741|1:u?u|2:0}u!==0&&(l=!0,bd(a,u))}else u=ct,u=Zn(a,a===_t?u:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(u&3)===0||Ga(a,u)||(l=!0,bd(a,u));a=a.next}while(l);ff=!1}}function Dy(){gd()}function gd(){Yu=cf=!1;var t=0;Tl!==0&&Xy()&&(t=Tl);for(var e=ne(),l=null,a=Lu;a!==null;){var n=a.next,u=pd(a,e);u===0?(a.next=null,l===null?Lu=n:l.next=n,n===null&&(Oa=l)):(l=a,(t!==0||(u&3)!==0)&&(Yu=!0)),a=n}Lt!==0&&Lt!==5||_n(t),Tl!==0&&(Tl=0)}function pd(t,e){for(var l=t.suspendedLanes,a=t.pingedLanes,n=t.expirationTimes,u=t.pendingLanes&-62914561;0r)break;var O=m.transferSize,C=m.initiatorType;O&&Nd(C)&&(m=m.responseEnd,c+=O*(m"u"?null:document;function Gd(t,e,l){var a=Da;if(a&&typeof e=="string"&&e){var n=pe(e);n='link[rel="'+t+'"][href="'+n+'"]',typeof l=="string"&&(n+='[crossorigin="'+l+'"]'),Yd.has(n)||(Yd.add(n),t={rel:t,crossOrigin:l,href:e},a.querySelector(n)===null&&(e=a.createElement("link"),Kt(e,"link",t),Yt(e),a.head.appendChild(e)))}}function ky(t){al.D(t),Gd("dns-prefetch",t,null)}function Fy(t,e){al.C(t,e),Gd("preconnect",t,e)}function Iy(t,e,l){al.L(t,e,l);var a=Da;if(a&&t&&e){var n='link[rel="preload"][as="'+pe(e)+'"]';e==="image"&&l&&l.imageSrcSet?(n+='[imagesrcset="'+pe(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(n+='[imagesizes="'+pe(l.imageSizes)+'"]')):n+='[href="'+pe(t)+'"]';var u=n;switch(e){case"style":u=Ma(t);break;case"script":u=ja(t)}xe.has(u)||(t=x({rel:"preload",href:e==="image"&&l&&l.imageSrcSet?void 0:t,as:e},l),xe.set(u,t),a.querySelector(n)!==null||e==="style"&&a.querySelector(xn(u))||e==="script"&&a.querySelector(Rn(u))||(e=a.createElement("link"),Kt(e,"link",t),Yt(e),a.head.appendChild(e)))}}function Py(t,e){al.m(t,e);var l=Da;if(l&&t){var a=e&&typeof e.as=="string"?e.as:"script",n='link[rel="modulepreload"][as="'+pe(a)+'"][href="'+pe(t)+'"]',u=n;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":u=ja(t)}if(!xe.has(u)&&(t=x({rel:"modulepreload",href:t},e),xe.set(u,t),l.querySelector(n)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(Rn(u)))return}a=l.createElement("link"),Kt(a,"link",t),Yt(a),l.head.appendChild(a)}}}function tv(t,e,l){al.S(t,e,l);var a=Da;if(a&&t){var n=Pl(a).hoistableStyles,u=Ma(t);e=e||"default";var c=n.get(u);if(!c){var r={loading:0,preload:null};if(c=a.querySelector(xn(u)))r.loading=5;else{t=x({rel:"stylesheet",href:t,"data-precedence":e},l),(l=xe.get(u))&&Af(t,l);var m=c=a.createElement("link");Yt(m),Kt(m,"link",t),m._p=new Promise(function(A,O){m.onload=A,m.onerror=O}),m.addEventListener("load",function(){r.loading|=1}),m.addEventListener("error",function(){r.loading|=2}),r.loading|=4,Vu(c,e,a)}c={type:"stylesheet",instance:c,count:1,state:r},n.set(u,c)}}}function ev(t,e){al.X(t,e);var l=Da;if(l&&t){var a=Pl(l).hoistableScripts,n=ja(t),u=a.get(n);u||(u=l.querySelector(Rn(n)),u||(t=x({src:t,async:!0},e),(e=xe.get(n))&&zf(t,e),u=l.createElement("script"),Yt(u),Kt(u,"link",t),l.head.appendChild(u)),u={type:"script",instance:u,count:1,state:null},a.set(n,u))}}function lv(t,e){al.M(t,e);var l=Da;if(l&&t){var a=Pl(l).hoistableScripts,n=ja(t),u=a.get(n);u||(u=l.querySelector(Rn(n)),u||(t=x({src:t,async:!0,type:"module"},e),(e=xe.get(n))&&zf(t,e),u=l.createElement("script"),Yt(u),Kt(u,"link",t),l.head.appendChild(u)),u={type:"script",instance:u,count:1,state:null},a.set(n,u))}}function Xd(t,e,l,a){var n=(n=nt.current)?Zu(n):null;if(!n)throw Error(f(446));switch(t){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(e=Ma(l.href),l=Pl(n).hoistableStyles,a=l.get(e),a||(a={type:"style",instance:null,count:0,state:null},l.set(e,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){t=Ma(l.href);var u=Pl(n).hoistableStyles,c=u.get(t);if(c||(n=n.ownerDocument||n,c={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},u.set(t,c),(u=n.querySelector(xn(t)))&&!u._p&&(c.instance=u,c.state.loading=5),xe.has(t)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},xe.set(t,l),u||av(n,t,l,c.state))),e&&a===null)throw Error(f(528,""));return c}if(e&&a!==null)throw Error(f(529,""));return null;case"script":return e=l.async,l=l.src,typeof l=="string"&&e&&typeof e!="function"&&typeof e!="symbol"?(e=ja(l),l=Pl(n).hoistableScripts,a=l.get(e),a||(a={type:"script",instance:null,count:0,state:null},l.set(e,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(f(444,t))}}function Ma(t){return'href="'+pe(t)+'"'}function xn(t){return'link[rel="stylesheet"]['+t+"]"}function Qd(t){return x({},t,{"data-precedence":t.precedence,precedence:null})}function av(t,e,l,a){t.querySelector('link[rel="preload"][as="style"]['+e+"]")?a.loading=1:(e=t.createElement("link"),a.preload=e,e.addEventListener("load",function(){return a.loading|=1}),e.addEventListener("error",function(){return a.loading|=2}),Kt(e,"link",l),Yt(e),t.head.appendChild(e))}function ja(t){return'[src="'+pe(t)+'"]'}function Rn(t){return"script[async]"+t}function Zd(t,e,l){if(e.count++,e.instance===null)switch(e.type){case"style":var a=t.querySelector('style[data-href~="'+pe(l.href)+'"]');if(a)return e.instance=a,Yt(a),a;var n=x({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(t.ownerDocument||t).createElement("style"),Yt(a),Kt(a,"style",n),Vu(a,l.precedence,t),e.instance=a;case"stylesheet":n=Ma(l.href);var u=t.querySelector(xn(n));if(u)return e.state.loading|=4,e.instance=u,Yt(u),u;a=Qd(l),(n=xe.get(n))&&Af(a,n),u=(t.ownerDocument||t).createElement("link"),Yt(u);var c=u;return c._p=new Promise(function(r,m){c.onload=r,c.onerror=m}),Kt(u,"link",a),e.state.loading|=4,Vu(u,l.precedence,t),e.instance=u;case"script":return u=ja(l.src),(n=t.querySelector(Rn(u)))?(e.instance=n,Yt(n),n):(a=l,(n=xe.get(u))&&(a=x({},l),zf(a,n)),t=t.ownerDocument||t,n=t.createElement("script"),Yt(n),Kt(n,"link",a),t.head.appendChild(n),e.instance=n);case"void":return null;default:throw Error(f(443,e.type))}else e.type==="stylesheet"&&(e.state.loading&4)===0&&(a=e.instance,e.state.loading|=4,Vu(a,l.precedence,t));return e.instance}function Vu(t,e,l){for(var a=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),n=a.length?a[a.length-1]:null,u=n,c=0;c title"):null)}function nv(t,e,l){if(l===1||e.itemProp!=null)return!1;switch(t){case"meta":case"title":return!0;case"style":if(typeof e.precedence!="string"||typeof e.href!="string"||e.href==="")break;return!0;case"link":if(typeof e.rel!="string"||typeof e.href!="string"||e.href===""||e.onLoad||e.onError)break;return e.rel==="stylesheet"?(t=e.disabled,typeof e.precedence=="string"&&t==null):!0;case"script":if(e.async&&typeof e.async!="function"&&typeof e.async!="symbol"&&!e.onLoad&&!e.onError&&e.src&&typeof e.src=="string")return!0}return!1}function wd(t){return!(t.type==="stylesheet"&&(t.state.loading&3)===0)}function uv(t,e,l,a){if(l.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var n=Ma(a.href),u=e.querySelector(xn(n));if(u){e=u._p,e!==null&&typeof e=="object"&&typeof e.then=="function"&&(t.count++,t=wu.bind(t),e.then(t,t)),l.state.loading|=4,l.instance=u,Yt(u);return}u=e.ownerDocument||e,a=Qd(a),(n=xe.get(n))&&Af(a,n),u=u.createElement("link"),Yt(u);var c=u;c._p=new Promise(function(r,m){c.onload=r,c.onerror=m}),Kt(u,"link",a),l.instance=u}t.stylesheets===null&&(t.stylesheets=new Map),t.stylesheets.set(l,e),(e=l.state.preload)&&(l.state.loading&3)===0&&(t.count++,l=wu.bind(t),e.addEventListener("load",l),e.addEventListener("error",l))}}var xf=0;function iv(t,e){return t.stylesheets&&t.count===0&&$u(t,t.stylesheets),0xf?50:800)+e);return t.unsuspend=l,function(){t.unsuspend=null,clearTimeout(a),clearTimeout(n)}}:null}function wu(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)$u(this,this.stylesheets);else if(this.unsuspend){var t=this.unsuspend;this.unsuspend=null,t()}}}var Ju=null;function $u(t,e){t.stylesheets=null,t.unsuspend!==null&&(t.count++,Ju=new Map,e.forEach(cv,t),Ju=null,wu.call(t))}function cv(t,e){if(!(e.state.loading&4)){var l=Ju.get(t);if(l)var a=l.get(null);else{l=new Map,Ju.set(t,l);for(var n=t.querySelectorAll("link[data-precedence],style[data-precedence]"),u=0;u"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(i)}catch(s){console.error(s)}}return i(),Hf.exports=Tv(),Hf.exports}var zv=Av();var vh="popstate";function gh(i){return typeof i=="object"&&i!=null&&"pathname"in i&&"search"in i&&"hash"in i&&"state"in i&&"key"in i}function xv(i={}){function s(d,y){let{pathname:b="/",search:R="",hash:S=""}=Wl(d.location.hash.substring(1));return!b.startsWith("/")&&!b.startsWith(".")&&(b="/"+b),wf("",{pathname:b,search:R,hash:S},y.state&&y.state.usr||null,y.state&&y.state.key||"default")}function o(d,y){let b=d.document.querySelector("base"),R="";if(b&&b.getAttribute("href")){let S=d.location.href,h=S.indexOf("#");R=h===-1?S:S.slice(0,h)}return R+"#"+(typeof y=="string"?y:Hn(y))}function f(d,y){Re(d.pathname.charAt(0)==="/",`relative pathnames are not supported in hash history.push(${JSON.stringify(y)})`)}return Nv(s,o,f,i)}function xt(i,s){if(i===!1||i===null||typeof i>"u")throw new Error(s)}function Re(i,s){if(!i){typeof console<"u"&&console.warn(s);try{throw new Error(s)}catch{}}}function Rv(){return Math.random().toString(36).substring(2,10)}function ph(i,s){return{usr:i.state,key:i.key,idx:s,masked:i.unstable_mask?{pathname:i.pathname,search:i.search,hash:i.hash}:void 0}}function wf(i,s,o=null,f,d){return{pathname:typeof i=="string"?i:i.pathname,search:"",hash:"",...typeof s=="string"?Wl(s):s,state:o,key:s&&s.key||f||Rv(),unstable_mask:d}}function Hn({pathname:i="/",search:s="",hash:o=""}){return s&&s!=="?"&&(i+=s.charAt(0)==="?"?s:"?"+s),o&&o!=="#"&&(i+=o.charAt(0)==="#"?o:"#"+o),i}function Wl(i){let s={};if(i){let o=i.indexOf("#");o>=0&&(s.hash=i.substring(o),i=i.substring(0,o));let f=i.indexOf("?");f>=0&&(s.search=i.substring(f),i=i.substring(0,f)),i&&(s.pathname=i)}return s}function Nv(i,s,o,f={}){let{window:d=document.defaultView,v5Compat:y=!1}=f,b=d.history,R="POP",S=null,h=M();h==null&&(h=0,b.replaceState({...b.state,idx:h},""));function M(){return(b.state||{idx:null}).idx}function x(){R="POP";let H=M(),G=H==null?null:H-h;h=H,S&&S({action:R,location:Y.location,delta:G})}function B(H,G){R="PUSH";let Q=gh(H)?H:wf(Y.location,H,G);o&&o(Q,H),h=M()+1;let J=ph(Q,h),at=Y.createHref(Q.unstable_mask||Q);try{b.pushState(J,"",at)}catch(et){if(et instanceof DOMException&&et.name==="DataCloneError")throw et;d.location.assign(at)}y&&S&&S({action:R,location:Y.location,delta:1})}function $(H,G){R="REPLACE";let Q=gh(H)?H:wf(Y.location,H,G);o&&o(Q,H),h=M();let J=ph(Q,h),at=Y.createHref(Q.unstable_mask||Q);b.replaceState(J,"",at),y&&S&&S({action:R,location:Y.location,delta:0})}function w(H){return Ov(H)}let Y={get action(){return R},get location(){return i(d,b)},listen(H){if(S)throw new Error("A history only accepts one active listener");return d.addEventListener(vh,x),S=H,()=>{d.removeEventListener(vh,x),S=null}},createHref(H){return s(d,H)},createURL:w,encodeLocation(H){let G=w(H);return{pathname:G.pathname,search:G.search,hash:G.hash}},push:B,replace:$,go(H){return b.go(H)}};return Y}function Ov(i,s=!1){let o="http://localhost";typeof window<"u"&&(o=window.location.origin!=="null"?window.location.origin:window.location.href),xt(o,"No window.location.(origin|href) available to create URL");let f=typeof i=="string"?i:Hn(i);return f=f.replace(/ $/,"%20"),!s&&f.startsWith("//")&&(f=o+f),new URL(f,o)}function Ah(i,s,o="/"){return Dv(i,s,o,!1)}function Dv(i,s,o,f){let d=typeof s=="string"?Wl(s):s,y=nl(d.pathname||"/",o);if(y==null)return null;let b=zh(i);Mv(b);let R=null;for(let S=0;R==null&&S{let M={relativePath:h===void 0?b.path||"":h,caseSensitive:b.caseSensitive===!0,childrenIndex:R,route:b};if(M.relativePath.startsWith("/")){if(!M.relativePath.startsWith(f)&&S)return;xt(M.relativePath.startsWith(f),`Absolute route path "${M.relativePath}" nested under path "${f}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),M.relativePath=M.relativePath.slice(f.length)}let x=Me([f,M.relativePath]),B=o.concat(M);b.children&&b.children.length>0&&(xt(b.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${x}".`),zh(b.children,s,B,x,S)),!(b.path==null&&!b.index)&&s.push({path:x,score:Lv(x,b.index),routesMeta:B})};return i.forEach((b,R)=>{if(b.path===""||!b.path?.includes("?"))y(b,R);else for(let S of xh(b.path))y(b,R,!0,S)}),s}function xh(i){let s=i.split("/");if(s.length===0)return[];let[o,...f]=s,d=o.endsWith("?"),y=o.replace(/\?$/,"");if(f.length===0)return d?[y,""]:[y];let b=xh(f.join("/")),R=[];return R.push(...b.map(S=>S===""?y:[y,S].join("/"))),d&&R.push(...b),R.map(S=>i.startsWith("/")&&S===""?"/":S)}function Mv(i){i.sort((s,o)=>s.score!==o.score?o.score-s.score:Yv(s.routesMeta.map(f=>f.childrenIndex),o.routesMeta.map(f=>f.childrenIndex)))}var jv=/^:[\w-]+$/,Cv=3,Uv=2,Hv=1,Bv=10,qv=-2,Sh=i=>i==="*";function Lv(i,s){let o=i.split("/"),f=o.length;return o.some(Sh)&&(f+=qv),s&&(f+=Uv),o.filter(d=>!Sh(d)).reduce((d,y)=>d+(jv.test(y)?Cv:y===""?Hv:Bv),f)}function Yv(i,s){return i.length===s.length&&i.slice(0,-1).every((f,d)=>f===s[d])?i[i.length-1]-s[s.length-1]:0}function Gv(i,s,o=!1){let{routesMeta:f}=i,d={},y="/",b=[];for(let R=0;R{if(M==="*"){let w=R[B]||"";b=y.slice(0,y.length-w.length).replace(/(.)\/+$/,"$1")}const $=R[B];return x&&!$?h[M]=void 0:h[M]=($||"").replace(/%2F/g,"/"),h},{}),pathname:y,pathnameBase:b,pattern:i}}function Xv(i,s=!1,o=!0){Re(i==="*"||!i.endsWith("*")||i.endsWith("/*"),`Route path "${i}" will be treated as if it were "${i.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${i.replace(/\*$/,"/*")}".`);let f=[],d="^"+i.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(b,R,S,h,M)=>{if(f.push({paramName:R,isOptional:S!=null}),S){let x=M.charAt(h+b.length);return x&&x!=="/"?"/([^\\/]*)":"(?:/([^\\/]*))?"}return"/([^\\/]+)"}).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return i.endsWith("*")?(f.push({paramName:"*"}),d+=i==="*"||i==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):o?d+="\\/*$":i!==""&&i!=="/"&&(d+="(?:(?=\\/|$))"),[new RegExp(d,s?void 0:"i"),f]}function Qv(i){try{return i.split("/").map(s=>decodeURIComponent(s).replace(/\//g,"%2F")).join("/")}catch(s){return Re(!1,`The URL path "${i}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${s}).`),i}}function nl(i,s){if(s==="/")return i;if(!i.toLowerCase().startsWith(s.toLowerCase()))return null;let o=s.endsWith("/")?s.length-1:s.length,f=i.charAt(o);return f&&f!=="/"?null:i.slice(o)||"/"}var Zv=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;function Vv(i,s="/"){let{pathname:o,search:f="",hash:d=""}=typeof i=="string"?Wl(i):i,y;return o?(o=Rh(o),o.startsWith("/")?y=bh(o.substring(1),"/"):y=bh(o,s)):y=s,{pathname:y,search:Jv(f),hash:$v(d)}}function bh(i,s){let o=fi(s).split("/");return i.split("/").forEach(d=>{d===".."?o.length>1&&o.pop():d!=="."&&o.push(d)}),o.length>1?o.join("/"):"/"}function Yf(i,s,o,f){return`Cannot include a '${i}' character in a manually specified \`to.${s}\` field [${JSON.stringify(f)}]. Please separate it out to the \`to.${o}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function Kv(i){return i.filter((s,o)=>o===0||s.route.path&&s.route.path.length>0)}function Wf(i){let s=Kv(i);return s.map((o,f)=>f===s.length-1?o.pathname:o.pathnameBase)}function oi(i,s,o,f=!1){let d;typeof i=="string"?d=Wl(i):(d={...i},xt(!d.pathname||!d.pathname.includes("?"),Yf("?","pathname","search",d)),xt(!d.pathname||!d.pathname.includes("#"),Yf("#","pathname","hash",d)),xt(!d.search||!d.search.includes("#"),Yf("#","search","hash",d)));let y=i===""||d.pathname==="",b=y?"/":d.pathname,R;if(b==null)R=o;else{let x=s.length-1;if(!f&&b.startsWith("..")){let B=b.split("/");for(;B[0]==="..";)B.shift(),x-=1;d.pathname=B.join("/")}R=x>=0?s[x]:"/"}let S=Vv(d,R),h=b&&b!=="/"&&b.endsWith("/"),M=(y||b===".")&&o.endsWith("/");return!S.pathname.endsWith("/")&&(h||M)&&(S.pathname+="/"),S}var Rh=i=>i.replace(/\/\/+/g,"/"),Me=i=>Rh(i.join("/")),fi=i=>i.replace(/\/+$/,""),wv=i=>fi(i).replace(/^\/*/,"/"),Jv=i=>!i||i==="?"?"":i.startsWith("?")?i:"?"+i,$v=i=>!i||i==="#"?"":i.startsWith("#")?i:"#"+i,Wv=class{constructor(i,s,o,f=!1){this.status=i,this.statusText=s||"",this.internal=f,o instanceof Error?(this.data=o.toString(),this.error=o):this.data=o}};function kv(i){return i!=null&&typeof i.status=="number"&&typeof i.statusText=="string"&&typeof i.internal=="boolean"&&"data"in i}function Fv(i){let s=i.map(o=>o.route.path).filter(Boolean);return Me(s)||"/"}var Nh=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function Oh(i,s){let o=i;if(typeof o!="string"||!Zv.test(o))return{absoluteURL:void 0,isExternal:!1,to:o};let f=o,d=!1;if(Nh)try{let y=new URL(window.location.href),b=o.startsWith("//")?new URL(y.protocol+o):new URL(o),R=nl(b.pathname,s);b.origin===y.origin&&R!=null?o=R+b.search+b.hash:d=!0}catch{Re(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:f,isExternal:d,to:o}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var Dh=["POST","PUT","PATCH","DELETE"];new Set(Dh);var Iv=["GET",...Dh];new Set(Iv);var Ba=T.createContext(null);Ba.displayName="DataRouter";var di=T.createContext(null);di.displayName="DataRouterState";var Mh=T.createContext(!1);function Pv(){return T.useContext(Mh)}var jh=T.createContext({isTransitioning:!1});jh.displayName="ViewTransition";var t0=T.createContext(new Map);t0.displayName="Fetchers";var e0=T.createContext(null);e0.displayName="Await";var me=T.createContext(null);me.displayName="Navigation";var Bn=T.createContext(null);Bn.displayName="Location";var je=T.createContext({outlet:null,matches:[],isDataRoute:!1});je.displayName="Route";var kf=T.createContext(null);kf.displayName="RouteError";var Ch="REACT_ROUTER_ERROR",l0="REDIRECT",a0="ROUTE_ERROR_RESPONSE";function n0(i){if(i.startsWith(`${Ch}:${l0}:{`))try{let s=JSON.parse(i.slice(28));if(typeof s=="object"&&s&&typeof s.status=="number"&&typeof s.statusText=="string"&&typeof s.location=="string"&&typeof s.reloadDocument=="boolean"&&typeof s.replace=="boolean")return s}catch{}}function u0(i){if(i.startsWith(`${Ch}:${a0}:{`))try{let s=JSON.parse(i.slice(40));if(typeof s=="object"&&s&&typeof s.status=="number"&&typeof s.statusText=="string")return new Wv(s.status,s.statusText,s.data)}catch{}}function i0(i,{relative:s}={}){xt(qa(),"useHref() may be used only in the context of a component.");let{basename:o,navigator:f}=T.useContext(me),{hash:d,pathname:y,search:b}=qn(i,{relative:s}),R=y;return o!=="/"&&(R=y==="/"?o:Me([o,y])),f.createHref({pathname:R,search:b,hash:d})}function qa(){return T.useContext(Bn)!=null}function Ye(){return xt(qa(),"useLocation() may be used only in the context of a component."),T.useContext(Bn).location}var Uh="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function Hh(i){T.useContext(me).static||T.useLayoutEffect(i)}function Bh(){let{isDataRoute:i}=T.useContext(je);return i?E0():c0()}function c0(){xt(qa(),"useNavigate() may be used only in the context of a component.");let i=T.useContext(Ba),{basename:s,navigator:o}=T.useContext(me),{matches:f}=T.useContext(je),{pathname:d}=Ye(),y=JSON.stringify(Wf(f)),b=T.useRef(!1);return Hh(()=>{b.current=!0}),T.useCallback((S,h={})=>{if(Re(b.current,Uh),!b.current)return;if(typeof S=="number"){o.go(S);return}let M=oi(S,JSON.parse(y),d,h.relative==="path");i==null&&s!=="/"&&(M.pathname=M.pathname==="/"?s:Me([s,M.pathname])),(h.replace?o.replace:o.push)(M,h.state,h)},[s,o,y,d,i])}var f0=T.createContext(null);function s0(i){let s=T.useContext(je).outlet;return T.useMemo(()=>s&&T.createElement(f0.Provider,{value:i},s),[s,i])}function qn(i,{relative:s}={}){let{matches:o}=T.useContext(je),{pathname:f}=Ye(),d=JSON.stringify(Wf(o));return T.useMemo(()=>oi(i,JSON.parse(d),f,s==="path"),[i,d,f,s])}function r0(i,s){return qh(i,s)}function qh(i,s,o){xt(qa(),"useRoutes() may be used only in the context of a component.");let{navigator:f}=T.useContext(me),{matches:d}=T.useContext(je),y=d[d.length-1],b=y?y.params:{},R=y?y.pathname:"/",S=y?y.pathnameBase:"/",h=y&&y.route;{let H=h&&h.path||"";Yh(R,!h||H.endsWith("*")||H.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 M=Ye(),x;if(s){let H=typeof s=="string"?Wl(s):s;xt(S==="/"||H.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 "${H.pathname}" was given in the \`location\` prop.`),x=H}else x=M;let B=x.pathname||"/",$=B;if(S!=="/"){let H=S.replace(/^\//,"").split("/");$="/"+B.replace(/^\//,"").split("/").slice(H.length).join("/")}let w=Ah(i,{pathname:$});Re(h||w!=null,`No routes matched location "${x.pathname}${x.search}${x.hash}" `),Re(w==null||w[w.length-1].route.element!==void 0||w[w.length-1].route.Component!==void 0||w[w.length-1].route.lazy!==void 0,`Matched leaf route at location "${x.pathname}${x.search}${x.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 Y=y0(w&&w.map(H=>Object.assign({},H,{params:Object.assign({},b,H.params),pathname:Me([S,f.encodeLocation?f.encodeLocation(H.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:H.pathname]),pathnameBase:H.pathnameBase==="/"?S:Me([S,f.encodeLocation?f.encodeLocation(H.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:H.pathnameBase])})),d,o);return s&&Y?T.createElement(Bn.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",unstable_mask:void 0,...x},navigationType:"POP"}},Y):Y}function o0(){let i=b0(),s=kv(i)?`${i.status} ${i.statusText}`:i instanceof Error?i.message:JSON.stringify(i),o=i instanceof Error?i.stack:null,f="rgba(200,200,200, 0.5)",d={padding:"0.5rem",backgroundColor:f},y={padding:"2px 4px",backgroundColor:f},b=null;return console.error("Error handled by React Router default ErrorBoundary:",i),b=T.createElement(T.Fragment,null,T.createElement("p",null,"💿 Hey developer 👋"),T.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",T.createElement("code",{style:y},"ErrorBoundary")," or"," ",T.createElement("code",{style:y},"errorElement")," prop on your route.")),T.createElement(T.Fragment,null,T.createElement("h2",null,"Unexpected Application Error!"),T.createElement("h3",{style:{fontStyle:"italic"}},s),o?T.createElement("pre",{style:d},o):null,b)}var d0=T.createElement(o0,null),Lh=class extends T.Component{constructor(i){super(i),this.state={location:i.location,revalidation:i.revalidation,error:i.error}}static getDerivedStateFromError(i){return{error:i}}static getDerivedStateFromProps(i,s){return s.location!==i.location||s.revalidation!=="idle"&&i.revalidation==="idle"?{error:i.error,location:i.location,revalidation:i.revalidation}:{error:i.error!==void 0?i.error:s.error,location:s.location,revalidation:i.revalidation||s.revalidation}}componentDidCatch(i,s){this.props.onError?this.props.onError(i,s):console.error("React Router caught the following error during render",i)}render(){let i=this.state.error;if(this.context&&typeof i=="object"&&i&&"digest"in i&&typeof i.digest=="string"){const o=u0(i.digest);o&&(i=o)}let s=i!==void 0?T.createElement(je.Provider,{value:this.props.routeContext},T.createElement(kf.Provider,{value:i,children:this.props.component})):this.props.children;return this.context?T.createElement(h0,{error:i},s):s}};Lh.contextType=Mh;var Gf=new WeakMap;function h0({children:i,error:s}){let{basename:o}=T.useContext(me);if(typeof s=="object"&&s&&"digest"in s&&typeof s.digest=="string"){let f=n0(s.digest);if(f){let d=Gf.get(s);if(d)throw d;let y=Oh(f.location,o);if(Nh&&!Gf.get(s))if(y.isExternal||f.reloadDocument)window.location.href=y.absoluteURL||y.to;else{const b=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(y.to,{replace:f.replace}));throw Gf.set(s,b),b}return T.createElement("meta",{httpEquiv:"refresh",content:`0;url=${y.absoluteURL||y.to}`})}}return i}function m0({routeContext:i,match:s,children:o}){let f=T.useContext(Ba);return f&&f.static&&f.staticContext&&(s.route.errorElement||s.route.ErrorBoundary)&&(f.staticContext._deepestRenderedBoundaryId=s.route.id),T.createElement(je.Provider,{value:i},o)}function y0(i,s=[],o){let f=o?.state;if(i==null){if(!f)return null;if(f.errors)i=f.matches;else if(s.length===0&&!f.initialized&&f.matches.length>0)i=f.matches;else return null}let d=i,y=f?.errors;if(y!=null){let M=d.findIndex(x=>x.route.id&&y?.[x.route.id]!==void 0);xt(M>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(y).join(",")}`),d=d.slice(0,Math.min(d.length,M+1))}let b=!1,R=-1;if(o&&f){b=f.renderFallback;for(let M=0;M=0?d=d.slice(0,R+1):d=[d[0]];break}}}}let S=o?.onError,h=f&&S?(M,x)=>{S(M,{location:f.location,params:f.matches?.[0]?.params??{},unstable_pattern:Fv(f.matches),errorInfo:x})}:void 0;return d.reduceRight((M,x,B)=>{let $,w=!1,Y=null,H=null;f&&($=y&&x.route.id?y[x.route.id]:void 0,Y=x.route.errorElement||d0,b&&(R<0&&B===0?(Yh("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),w=!0,H=null):R===B&&(w=!0,H=x.route.hydrateFallbackElement||null)));let G=s.concat(d.slice(0,B+1)),Q=()=>{let J;return $?J=Y:w?J=H:x.route.Component?J=T.createElement(x.route.Component,null):x.route.element?J=x.route.element:J=M,T.createElement(m0,{match:x,routeContext:{outlet:M,matches:G,isDataRoute:f!=null},children:J})};return f&&(x.route.ErrorBoundary||x.route.errorElement||B===0)?T.createElement(Lh,{location:f.location,revalidation:f.revalidation,component:Y,error:$,children:Q(),routeContext:{outlet:null,matches:G,isDataRoute:!0},onError:h}):Q()},null)}function Ff(i){return`${i} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function v0(i){let s=T.useContext(Ba);return xt(s,Ff(i)),s}function g0(i){let s=T.useContext(di);return xt(s,Ff(i)),s}function p0(i){let s=T.useContext(je);return xt(s,Ff(i)),s}function If(i){let s=p0(i),o=s.matches[s.matches.length-1];return xt(o.route.id,`${i} can only be used on routes that contain a unique "id"`),o.route.id}function S0(){return If("useRouteId")}function b0(){let i=T.useContext(kf),s=g0("useRouteError"),o=If("useRouteError");return i!==void 0?i:s.errors?.[o]}function E0(){let{router:i}=v0("useNavigate"),s=If("useNavigate"),o=T.useRef(!1);return Hh(()=>{o.current=!0}),T.useCallback(async(d,y={})=>{Re(o.current,Uh),o.current&&(typeof d=="number"?await i.navigate(d):await i.navigate(d,{fromRouteId:s,...y}))},[i,s])}var Eh={};function Yh(i,s,o){!s&&!Eh[i]&&(Eh[i]=!0,Re(!1,o))}T.memo(_0);function _0({routes:i,future:s,state:o,isStatic:f,onError:d}){return qh(i,void 0,{state:o,isStatic:f,onError:d})}function T0({to:i,replace:s,state:o,relative:f}){xt(qa()," may be used only in the context of a component.");let{static:d}=T.useContext(me);Re(!d," must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.");let{matches:y}=T.useContext(je),{pathname:b}=Ye(),R=Bh(),S=oi(i,Wf(y),b,f==="path"),h=JSON.stringify(S);return T.useEffect(()=>{R(JSON.parse(h),{replace:s,state:o,relative:f})},[R,h,f,s,o]),null}function A0(i){return s0(i.context)}function Ua(i){xt(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function z0({basename:i="/",children:s=null,location:o,navigationType:f="POP",navigator:d,static:y=!1,unstable_useTransitions:b}){xt(!qa(),"You cannot render a inside another . You should never have more than one in your app.");let R=i.replace(/^\/*/,"/"),S=T.useMemo(()=>({basename:R,navigator:d,static:y,unstable_useTransitions:b,future:{}}),[R,d,y,b]);typeof o=="string"&&(o=Wl(o));let{pathname:h="/",search:M="",hash:x="",state:B=null,key:$="default",unstable_mask:w}=o,Y=T.useMemo(()=>{let H=nl(h,R);return H==null?null:{location:{pathname:H,search:M,hash:x,state:B,key:$,unstable_mask:w},navigationType:f}},[R,h,M,x,B,$,f,w]);return Re(Y!=null,` is not able to match the URL "${h}${M}${x}" because it does not start with the basename, so the won't render anything.`),Y==null?null:T.createElement(me.Provider,{value:S},T.createElement(Bn.Provider,{children:s,value:Y}))}function x0({children:i,location:s}){return r0(Jf(i),s)}function Jf(i,s=[]){let o=[];return T.Children.forEach(i,(f,d)=>{if(!T.isValidElement(f))return;let y=[...s,d];if(f.type===T.Fragment){o.push.apply(o,Jf(f.props.children,y));return}xt(f.type===Ua,`[${typeof f.type=="string"?f.type:f.type.name}] is not a component. All component children of must be a or `),xt(!f.props.index||!f.props.children,"An index route cannot have child routes.");let b={id:f.props.id||y.join("-"),caseSensitive:f.props.caseSensitive,element:f.props.element,Component:f.props.Component,index:f.props.index,path:f.props.path,middleware:f.props.middleware,loader:f.props.loader,action:f.props.action,hydrateFallbackElement:f.props.hydrateFallbackElement,HydrateFallback:f.props.HydrateFallback,errorElement:f.props.errorElement,ErrorBoundary:f.props.ErrorBoundary,hasErrorBoundary:f.props.hasErrorBoundary===!0||f.props.ErrorBoundary!=null||f.props.errorElement!=null,shouldRevalidate:f.props.shouldRevalidate,handle:f.props.handle,lazy:f.props.lazy};f.props.children&&(b.children=Jf(f.props.children,y)),o.push(b)}),o}var ni="get",ui="application/x-www-form-urlencoded";function hi(i){return typeof HTMLElement<"u"&&i instanceof HTMLElement}function R0(i){return hi(i)&&i.tagName.toLowerCase()==="button"}function N0(i){return hi(i)&&i.tagName.toLowerCase()==="form"}function O0(i){return hi(i)&&i.tagName.toLowerCase()==="input"}function D0(i){return!!(i.metaKey||i.altKey||i.ctrlKey||i.shiftKey)}function M0(i,s){return i.button===0&&(!s||s==="_self")&&!D0(i)}var li=null;function j0(){if(li===null)try{new FormData(document.createElement("form"),0),li=!1}catch{li=!0}return li}var C0=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function Xf(i){return i!=null&&!C0.has(i)?(Re(!1,`"${i}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${ui}"`),null):i}function U0(i,s){let o,f,d,y,b;if(N0(i)){let R=i.getAttribute("action");f=R?nl(R,s):null,o=i.getAttribute("method")||ni,d=Xf(i.getAttribute("enctype"))||ui,y=new FormData(i)}else if(R0(i)||O0(i)&&(i.type==="submit"||i.type==="image")){let R=i.form;if(R==null)throw new Error('Cannot submit a