From 46abb28ed67ded4a4ea6a7eab799eb7aed93fca6 Mon Sep 17 00:00:00 2001 From: pjay Date: Wed, 22 Apr 2026 19:55:45 +0700 Subject: [PATCH] feat(sdk-android): snapshot property delegate + feature-scoped files + screen fix (#34) * rename web to inspect ui * feat(sdk-android): add camelToSnakeCase conversion * feat(sdk-android): add snapshot() property delegate with tests * feat(folio): add feature-scoped sanderling snapshot objects * refactor(folio): slim FolioApplication to snapshot object references * fix(folio): rename route snapshot to screen, update spec.ts --- Makefile | 8 +- .../kotlin/app/folio/FolioApplication.kt | 86 ++--------------- .../app/folio/sanderling/AccountSnapshots.kt | 19 ++++ .../app/folio/sanderling/AuthSnapshots.kt | 11 +++ .../app/folio/sanderling/LedgerSnapshots.kt | 42 ++++++++ .../folio/sanderling/NavigationSnapshots.kt | 17 ++++ examples/folio/sanderling/spec.ts | 2 +- {web => inspect-ui}/bun.lock | 0 inspect-ui/dist/assets/index-BSJUf7yI.css | 1 + inspect-ui/dist/assets/index-DAhEzdrG.js | 67 +++++++++++++ .../public => inspect-ui/dist}/fonts/.gitkeep | 0 inspect-ui/dist/index.html | 13 +++ {web => inspect-ui}/index.html | 0 {web => inspect-ui}/package.json | 0 inspect-ui/public/fonts/.gitkeep | 0 {web => inspect-ui}/src/App.tsx | 0 {web => inspect-ui}/src/api.ts | 0 .../src/components/ResidualNode.css | 0 .../src/components/ResidualNode.tsx | 0 {web => inspect-ui}/src/components/Tabs.css | 0 {web => inspect-ui}/src/components/Tabs.tsx | 0 .../src/hooks/useKeyboardNav.ts | 0 {web => inspect-ui}/src/hooks/useSse.ts | 0 {web => inspect-ui}/src/hooks/useStep.ts | 0 {web => inspect-ui}/src/hooks/useTheme.ts | 0 {web => inspect-ui}/src/main.tsx | 0 {web => inspect-ui}/src/panels/ActionList.css | 0 {web => inspect-ui}/src/panels/ActionList.tsx | 0 .../src/panels/ExceptionsPanel.css | 0 .../src/panels/ExceptionsPanel.tsx | 0 .../src/panels/MetricsChart.css | 0 .../src/panels/MetricsChart.tsx | 0 {web => inspect-ui}/src/panels/Screenshot.css | 0 {web => inspect-ui}/src/panels/Screenshot.tsx | 0 .../src/panels/SnapshotTable.css | 0 .../src/panels/SnapshotTable.tsx | 0 {web => inspect-ui}/src/panels/Timeline.css | 0 {web => inspect-ui}/src/panels/Timeline.tsx | 0 .../src/panels/ViolationsPanel.css | 0 .../src/panels/ViolationsPanel.tsx | 0 {web => inspect-ui}/src/routes/RunDetail.tsx | 0 {web => inspect-ui}/src/routes/RunList.tsx | 0 {web => inspect-ui}/src/styles/app.css | 0 {web => inspect-ui}/src/styles/tokens.css | 0 {web => inspect-ui}/src/styles/typography.css | 0 {web => inspect-ui}/src/types.ts | 0 {web => inspect-ui}/tsconfig.json | 0 {web => inspect-ui}/vite.config.ts | 0 internal/inspect/assets.go | 2 +- .../kotlin/dev/sanderling/sdk/Sanderling.kt | 18 ++++ .../sanderling/sdk/SnapshotDelegateTest.kt | 95 +++++++++++++++++++ 51 files changed, 297 insertions(+), 84 deletions(-) create mode 100644 examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/AccountSnapshots.kt create mode 100644 examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/AuthSnapshots.kt create mode 100644 examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/LedgerSnapshots.kt create mode 100644 examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/NavigationSnapshots.kt rename {web => inspect-ui}/bun.lock (100%) create mode 100644 inspect-ui/dist/assets/index-BSJUf7yI.css create mode 100644 inspect-ui/dist/assets/index-DAhEzdrG.js rename {web/public => inspect-ui/dist}/fonts/.gitkeep (100%) create mode 100644 inspect-ui/dist/index.html rename {web => inspect-ui}/index.html (100%) rename {web => inspect-ui}/package.json (100%) create mode 100644 inspect-ui/public/fonts/.gitkeep rename {web => inspect-ui}/src/App.tsx (100%) rename {web => inspect-ui}/src/api.ts (100%) rename {web => inspect-ui}/src/components/ResidualNode.css (100%) rename {web => inspect-ui}/src/components/ResidualNode.tsx (100%) rename {web => inspect-ui}/src/components/Tabs.css (100%) rename {web => inspect-ui}/src/components/Tabs.tsx (100%) rename {web => inspect-ui}/src/hooks/useKeyboardNav.ts (100%) rename {web => inspect-ui}/src/hooks/useSse.ts (100%) rename {web => inspect-ui}/src/hooks/useStep.ts (100%) rename {web => inspect-ui}/src/hooks/useTheme.ts (100%) rename {web => inspect-ui}/src/main.tsx (100%) rename {web => inspect-ui}/src/panels/ActionList.css (100%) rename {web => inspect-ui}/src/panels/ActionList.tsx (100%) rename {web => inspect-ui}/src/panels/ExceptionsPanel.css (100%) rename {web => inspect-ui}/src/panels/ExceptionsPanel.tsx (100%) rename {web => inspect-ui}/src/panels/MetricsChart.css (100%) rename {web => inspect-ui}/src/panels/MetricsChart.tsx (100%) rename {web => inspect-ui}/src/panels/Screenshot.css (100%) rename {web => inspect-ui}/src/panels/Screenshot.tsx (100%) rename {web => inspect-ui}/src/panels/SnapshotTable.css (100%) rename {web => inspect-ui}/src/panels/SnapshotTable.tsx (100%) rename {web => inspect-ui}/src/panels/Timeline.css (100%) rename {web => inspect-ui}/src/panels/Timeline.tsx (100%) rename {web => inspect-ui}/src/panels/ViolationsPanel.css (100%) rename {web => inspect-ui}/src/panels/ViolationsPanel.tsx (100%) rename {web => inspect-ui}/src/routes/RunDetail.tsx (100%) rename {web => inspect-ui}/src/routes/RunList.tsx (100%) rename {web => inspect-ui}/src/styles/app.css (100%) rename {web => inspect-ui}/src/styles/tokens.css (100%) rename {web => inspect-ui}/src/styles/typography.css (100%) rename {web => inspect-ui}/src/types.ts (100%) rename {web => inspect-ui}/tsconfig.json (100%) rename {web => inspect-ui}/vite.config.ts (100%) create mode 100644 sdk/android/src/test/kotlin/dev/sanderling/sdk/SnapshotDelegateTest.kt diff --git a/Makefile b/Makefile index 9a24bd9..2b2e6fb 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ DIAGRAM_SRC := $(shell find docs/_diagrams -type f -name '*.d2' 2>/dev/null) DIAGRAM_OUT := $(patsubst docs/_diagrams/%.d2,build/site/_assets/diagrams/%.svg,$(DIAGRAM_SRC)) INSPECT_DIST := internal/inspect/dist -WEB_DIST := web/dist +WEB_DIST := inspect-ui/dist .PHONY: bootstrap proto sidecar sdk-android sdk-android-publish sanderling install test test-go test-kotlin test-spec-api web-typecheck web-build web-dev inspect-dev docs clean release-cli release-android-local release-npm-dry @@ -52,19 +52,19 @@ install: $(SIDECAR_EMBED) web-build @dest="$$($(GO) env GOBIN)"; [ -n "$$dest" ] || dest="$$($(GO) env GOPATH)/bin"; echo "installed sanderling to $$dest" web-build: - cd web && bun install --frozen-lockfile && bun run build + cd inspect-ui && bun install --frozen-lockfile && bun run build mkdir -p $(INSPECT_DIST) rm -rf $(INSPECT_DIST)/assets $(INSPECT_DIST)/fonts cp -R $(WEB_DIST)/. $(INSPECT_DIST)/ web-dev: - cd web && bun run dev + cd inspect-ui && bun run dev inspect-dev: $(SIDECAR_EMBED) $(GO) run -tags withsidecar ./cmd/sanderling inspect --dev web-typecheck: - cd web && bun install --frozen-lockfile && bun run typecheck + cd inspect-ui && bun install --frozen-lockfile && bun run typecheck $(SIDECAR_JAR): ANDROID_HOME=$(ANDROID_HOME) $(GRADLE) :sidecar:shadowJar diff --git a/examples/folio/composeApp/src/androidMain/kotlin/app/folio/FolioApplication.kt b/examples/folio/composeApp/src/androidMain/kotlin/app/folio/FolioApplication.kt index 768c666..ccb9629 100644 --- a/examples/folio/composeApp/src/androidMain/kotlin/app/folio/FolioApplication.kt +++ b/examples/folio/composeApp/src/androidMain/kotlin/app/folio/FolioApplication.kt @@ -3,14 +3,10 @@ package app.folio import android.app.Application import app.folio.data.AndroidLedgerContext import app.folio.data.Repository -import app.folio.data.TxnType -import app.folio.feature.account.AddAccountUiState -import app.folio.feature.auth.LoginUiState -import app.folio.feature.ledger.AddTransactionUiState -import app.folio.navigation.Navigator -import app.folio.navigation.Route -import app.folio.platform.balanceOf -import app.folio.platform.signedAmount +import app.folio.sanderling.AccountSnapshots +import app.folio.sanderling.AuthSnapshots +import app.folio.sanderling.LedgerSnapshots +import app.folio.sanderling.NavigationSnapshots import dev.sanderling.sdk.Sanderling class FolioApplication : Application() { @@ -19,75 +15,9 @@ class FolioApplication : Application() { AndroidLedgerContext.context = applicationContext Repository.init() Sanderling.start(this) - Sanderling.extract("logged_in") { Repository.session.value != null } - Sanderling.extract("account_count") { Repository.accounts.value.size } - Sanderling.extract("total_balance") { balanceOf(Repository.transactions.value) } - Sanderling.extract("route") { - when (Navigator.current.value) { - Route.Login -> "login" - Route.Home -> "home" - Route.AddAccount -> "add-account" - is Route.Ledger -> "ledger" - is Route.AddTransaction -> "add-transaction" - } - } - Sanderling.extract("auth_status") { - if (Repository.session.value != null) "logged-in" else "logged-out" - } - Sanderling.extract("accounts") { - val txns = Repository.transactions.value - Repository.accounts.value.map { a -> - val rows = txns.filter { it.accountId == a.id } - mapOf( - "id" to a.id, - "name" to a.name, - "balance" to balanceOf(rows), - "txnCount" to rows.size, - ) - } - } - Sanderling.extract("active_account_id") { - when (val r = Navigator.current.value) { - is Route.Ledger -> r.accountId - is Route.AddTransaction -> r.accountId - else -> null - } - } - Sanderling.extract("ledger_rows") { - val active = when (val r = Navigator.current.value) { - is Route.Ledger -> r.accountId - is Route.AddTransaction -> r.accountId - else -> null - } - if (active == null) emptyList() - else Repository.transactions.value - .filter { it.accountId == active } - .map { - mapOf( - "id" to it.id, - "accountId" to it.accountId, - "type" to if (it.type == TxnType.credit) "credit" else "debit", - "amount" to it.amount, - "signed" to signedAmount(it), - ) - } - } - Sanderling.extract("ledger_balance") { - val active = when (val r = Navigator.current.value) { - is Route.Ledger -> r.accountId - is Route.AddTransaction -> r.accountId - else -> null - } - if (active == null) 0L - else balanceOf(Repository.transactions.value.filter { it.accountId == active }) - } - Sanderling.extract("focused_input") { FocusTracker.current.value } - Sanderling.extract("txn_form_type") { AddTransactionUiState.txnFormType.value } - Sanderling.extract("txn_form_account_id") { - (Navigator.current.value as? Route.AddTransaction)?.accountId - } - Sanderling.extract("login_error") { LoginUiState.loginError.value } - Sanderling.extract("add_account_error") { AddAccountUiState.addAccountError.value } - Sanderling.extract("txn_error") { AddTransactionUiState.txnError.value } + AuthSnapshots + AccountSnapshots + LedgerSnapshots + NavigationSnapshots } } diff --git a/examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/AccountSnapshots.kt b/examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/AccountSnapshots.kt new file mode 100644 index 0000000..1f4be1c --- /dev/null +++ b/examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/AccountSnapshots.kt @@ -0,0 +1,19 @@ +package app.folio.sanderling + +import app.folio.data.Repository +import app.folio.feature.account.AddAccountUiState +import app.folio.platform.balanceOf +import dev.sanderling.sdk.Sanderling + +object AccountSnapshots { + val accountCount by Sanderling.snapshot { Repository.accounts.value.size } + val totalBalance by Sanderling.snapshot { balanceOf(Repository.transactions.value) } + val accounts by Sanderling.snapshot { + val txns = Repository.transactions.value + Repository.accounts.value.map { a -> + val rows = txns.filter { it.accountId == a.id } + mapOf("id" to a.id, "name" to a.name, "balance" to balanceOf(rows), "txnCount" to rows.size) + } + } + val addAccountError by Sanderling.snapshot { AddAccountUiState.addAccountError.value } +} diff --git a/examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/AuthSnapshots.kt b/examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/AuthSnapshots.kt new file mode 100644 index 0000000..d8be6ab --- /dev/null +++ b/examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/AuthSnapshots.kt @@ -0,0 +1,11 @@ +package app.folio.sanderling + +import app.folio.data.Repository +import app.folio.feature.auth.LoginUiState +import dev.sanderling.sdk.Sanderling + +object AuthSnapshots { + val loggedIn by Sanderling.snapshot { Repository.session.value != null } + val authStatus by Sanderling.snapshot { if (Repository.session.value != null) "logged-in" else "logged-out" } + val loginError by Sanderling.snapshot { LoginUiState.loginError.value } +} diff --git a/examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/LedgerSnapshots.kt b/examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/LedgerSnapshots.kt new file mode 100644 index 0000000..778eaf0 --- /dev/null +++ b/examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/LedgerSnapshots.kt @@ -0,0 +1,42 @@ +package app.folio.sanderling + +import app.folio.FocusTracker +import app.folio.data.Repository +import app.folio.data.TxnType +import app.folio.feature.ledger.AddTransactionUiState +import app.folio.navigation.Navigator +import app.folio.navigation.Route +import app.folio.platform.balanceOf +import app.folio.platform.signedAmount +import dev.sanderling.sdk.Sanderling + +object LedgerSnapshots { + private val activeId + get() = when (val r = Navigator.current.value) { + is Route.Ledger -> r.accountId + is Route.AddTransaction -> r.accountId + else -> null + } + + val activeAccountId by Sanderling.snapshot { activeId } + val ledgerRows by Sanderling.snapshot { + val active = activeId ?: return@snapshot emptyList() + Repository.transactions.value.filter { it.accountId == active }.map { + mapOf( + "id" to it.id, + "accountId" to it.accountId, + "type" to if (it.type == TxnType.credit) "credit" else "debit", + "amount" to it.amount, + "signed" to signedAmount(it), + ) + } + } + val ledgerBalance by Sanderling.snapshot { + val active = activeId ?: return@snapshot 0L + balanceOf(Repository.transactions.value.filter { it.accountId == active }) + } + val focusedInput by Sanderling.snapshot { FocusTracker.current.value } + val txnFormType by Sanderling.snapshot { AddTransactionUiState.txnFormType.value } + val txnFormAccountId by Sanderling.snapshot { (Navigator.current.value as? Route.AddTransaction)?.accountId } + val txnError by Sanderling.snapshot { AddTransactionUiState.txnError.value } +} diff --git a/examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/NavigationSnapshots.kt b/examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/NavigationSnapshots.kt new file mode 100644 index 0000000..6da97ac --- /dev/null +++ b/examples/folio/composeApp/src/androidMain/kotlin/app/folio/sanderling/NavigationSnapshots.kt @@ -0,0 +1,17 @@ +package app.folio.sanderling + +import app.folio.navigation.Navigator +import app.folio.navigation.Route +import dev.sanderling.sdk.Sanderling + +object NavigationSnapshots { + val screen by Sanderling.snapshot { + when (Navigator.current.value) { + Route.Login -> "login" + Route.Home -> "home" + Route.AddAccount -> "add-account" + is Route.Ledger -> "ledger" + is Route.AddTransaction -> "add-transaction" + } + } +} diff --git a/examples/folio/sanderling/spec.ts b/examples/folio/sanderling/spec.ts index 414eb93..07be367 100644 --- a/examples/folio/sanderling/spec.ts +++ b/examples/folio/sanderling/spec.ts @@ -35,7 +35,7 @@ const loggedIn = extract( (state) => (state.snapshots.logged_in as boolean) ?? false, ); const route = extract( - (state) => (state.snapshots.route as string) ?? "", + (state) => (state.snapshots.screen as string) ?? "", ); const accounts = extract( (state) => (state.snapshots.accounts as AccountSnapshot[]) ?? [], diff --git a/web/bun.lock b/inspect-ui/bun.lock similarity index 100% rename from web/bun.lock rename to inspect-ui/bun.lock diff --git a/inspect-ui/dist/assets/index-BSJUf7yI.css b/inspect-ui/dist/assets/index-BSJUf7yI.css new file mode 100644 index 0000000..7689c23 --- /dev/null +++ b/inspect-ui/dist/assets/index-BSJUf7yI.css @@ -0,0 +1 @@ +@font-face{font-family:JetBrains Mono;font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/JetBrainsMono-Regular.woff2) format("woff2")}@font-face{font-family:JetBrains Mono;font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/JetBrainsMono-Medium.woff2) format("woff2")}@font-face{font-family:JetBrains Mono;font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/JetBrainsMono-Bold.woff2) format("woff2")}body{font-family:var(--font-mono);font-size:13px;line-height:1.5;color:var(--text-primary);background:var(--background);margin:0}:root{--background: #ffffff;--surface: #f7f7f7;--surface-elevated: #ffffff;--border: #e4e4e4;--border-strong: #c8c8c8;--text-primary: #111111;--text-muted: #6b6b6b;--accent-violation: #d32f2f;--accent-positive: #2e7d32;--font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace}:root[data-theme=dark],:root[data-theme=dark] body{--background: #0e0e0e;--surface: #161616;--surface-elevated: #1d1d1d;--border: #2a2a2a;--border-strong: #3a3a3a;--text-primary: #f0f0f0;--text-muted: #9a9a9a;--accent-violation: #f06b6b;--accent-positive: #7cc47c}@media (prefers-color-scheme: dark){:root:not([data-theme=light]){--background: #0e0e0e;--surface: #161616;--surface-elevated: #1d1d1d;--border: #2a2a2a;--border-strong: #3a3a3a;--text-primary: #f0f0f0;--text-muted: #9a9a9a;--accent-violation: #f06b6b;--accent-positive: #7cc47c}}body{background:var(--background);color:var(--text-primary);margin:0;font-family:var(--font-mono)}*,*:before,*:after{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{overflow:hidden}a{color:inherit;text-decoration:none}a:hover{text-decoration:underline}button{font:inherit;color:inherit;background:var(--surface);border:1px solid var(--border);padding:4px 10px;cursor:pointer}button:hover{border-color:var(--border-strong)}.app-shell{height:100vh;display:flex;flex-direction:column;overflow:hidden}.app-main{flex:1 1 auto;min-height:0;padding:0;display:flex;flex-direction:column}.app-main>*{flex:1 1 auto;min-height:0}.run-table{width:100%;border-collapse:collapse;align-self:flex-start;flex:0 0 auto}.run-table th,.run-table td{text-align:left;padding:8px 12px;border-bottom:1px solid var(--border)}.run-table th{color:var(--text-muted);font-weight:500;font-size:12px;text-transform:uppercase;letter-spacing:.04em}.run-table tr:hover td{background:var(--surface)}.chip{display:inline-block;padding:2px 8px;border:1px solid var(--border-strong);border-radius:999px;font-size:11px}.chip-violation{border-color:var(--accent-violation);color:var(--accent-violation)}.chip-progress{border-color:var(--border-strong);color:var(--text-muted)}.detail-root{display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden}.detail-toolbar{display:flex;align-items:center;justify-content:space-between;padding:4px 8px;border-bottom:1px solid var(--border);flex:0 0 auto}.detail-toolbar-meta{display:flex;gap:16px;align-items:baseline;font-size:12px;color:var(--text-muted)}.detail-toolbar-meta strong{color:var(--text-primary);font-weight:500}.theme-toggle{display:inline-flex;align-items:center;justify-content:center;width:28px;height:24px;padding:0;color:var(--text-muted)}.theme-toggle:hover{color:var(--text-primary)}.theme-toggle svg{display:block}.detail-grid{flex:1 1 auto;display:grid;grid-template-columns:340px minmax(0,1fr) minmax(0,1fr);grid-template-rows:minmax(0,1fr) minmax(0,130px);grid-template-areas:"actions before after" "metrics metrics metrics";gap:0;padding:0;min-height:0;overflow:hidden}.detail-grid>.detail-actions{grid-area:actions;min-height:0;overflow:hidden}.detail-grid>.detail-state-before,.detail-grid>.detail-state-after{display:flex;flex-direction:column;gap:0;min-height:0;min-width:0;overflow:hidden}.detail-grid>.detail-state-before{grid-area:before}.detail-grid>.detail-state-after{grid-area:after}.detail-grid>.detail-actions,.detail-grid>.detail-state-before{border-right:1px solid var(--border)}.detail-grid>.detail-state-before .screenshot-frame,.detail-grid>.detail-state-after .screenshot-frame,.detail-grid>.detail-state-before .screenshot-placeholder,.detail-grid>.detail-state-after .screenshot-placeholder{flex:1 1 auto;max-height:100%;max-width:100%;margin:0 auto;min-height:0}.detail-grid>.detail-metrics{grid-area:metrics;overflow:hidden;display:flex;flex-direction:column;min-height:0;border-top:1px solid var(--border)}.detail-grid>.detail-metrics .metrics-chart{flex:1 1 auto;min-height:0;max-height:100%}.detail-metrics .detail-panel-body{overflow:hidden}.detail-metrics-exceptions{padding:4px 8px;border-top:1px solid var(--border);overflow:auto;max-height:80px}.detail-panel{border:none;background:transparent;padding:0;min-height:0;display:flex;flex-direction:column}.detail-panel h2{margin:0;padding:4px 8px;font-size:10px;font-weight:500;color:var(--text-muted);text-transform:uppercase;letter-spacing:.06em;border-bottom:1px solid var(--border);flex:0 0 auto}.detail-panel-body{flex:1 1 auto;min-height:0;overflow:auto;display:flex;flex-direction:column}.detail-actions .detail-panel-body{padding:0}.status-block{padding:12px;color:var(--text-muted)}.status-error{color:var(--accent-violation)}.action-list{list-style:none;padding:0;margin:0;font-family:var(--font-mono);font-size:11px}.action-list-item{display:block;padding:3px 6px;border-left:2px solid transparent;cursor:pointer;color:var(--text-primary);outline:none}.action-list-item:focus-visible{outline:1px solid var(--text-primary);outline-offset:-1px}.action-list-row{display:grid;grid-template-columns:20px minmax(0,1fr) auto auto;align-items:baseline;column-gap:4px}.action-list-index{text-align:left;color:var(--text-muted);font-variant-numeric:tabular-nums}.action-list-body{display:inline-flex;gap:6px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.action-list-verb{color:var(--text-primary);font-weight:500}.action-list-target{color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.action-list-target-tag{color:var(--text-primary)}.action-list-markers{display:inline-flex;align-items:center;gap:6px;min-width:0}.action-list-elapsed{color:var(--text-muted);font-variant-numeric:tabular-nums;text-align:right;padding-left:8px}.action-list-item:hover{background:color-mix(in srgb,currentColor 6%,transparent)}.action-list-item:focus-visible{background:color-mix(in srgb,currentColor 8%,transparent)}.action-list-item[data-active=true]{background:color-mix(in srgb,currentColor 10%,transparent);border-left-color:currentColor}.action-list-item[data-active=true][data-violations=true]{border-left-color:var(--accent-violation)}.action-list-marker-violation{width:8px;height:8px;border-radius:50%;background:var(--accent-violation)}.action-list-marker-exception{width:8px;height:8px;border-radius:50%;border:1px solid var(--text-muted);background:transparent}.action-list-details{display:grid;grid-template-columns:20px 1fr;column-gap:4px;padding:2px 0;font-size:10px}.action-list-detail-row{grid-column:2;display:grid;grid-template-columns:70px 1fr;gap:6px;color:var(--text-muted)}.action-list-detail-label{color:var(--text-muted)}.action-list-detail-value{color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.screenshot-frame{position:relative;width:100%;max-width:100%;max-height:100%;margin:0 auto;background:var(--surface);overflow:hidden}.screenshot-image{display:block;width:100%;height:100%;object-fit:contain}.screenshot-overlay{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;pointer-events:none}.screenshot-placeholder{display:flex;align-items:center;justify-content:center;width:100%;height:100%;min-height:240px;background:var(--surface);border:1px dashed var(--border-strong);color:var(--text-muted);font-family:var(--font-mono);font-size:12px;text-transform:uppercase;letter-spacing:.06em}.snapshot-table{margin:0;padding:0;font-family:var(--font-mono);font-size:12px;color:var(--text-primary)}.snapshot-row{display:grid;grid-template-columns:minmax(0,160px) minmax(0,1fr);gap:12px;align-items:baseline;padding:4px 8px;border-left:2px solid transparent}.snapshot-row[data-changed=true]{border-left-color:var(--border-strong)}.snapshot-path{margin:0;color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.snapshot-value{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:right;font-variant-numeric:tabular-nums}.snapshot-row[data-long-value=true] .snapshot-value{white-space:pre-wrap;max-height:6em;overflow-y:auto;text-align:left}.residual{font-family:var(--font-mono);font-size:12px;color:var(--text-primary);line-height:1.6;word-break:break-word}.residual-leaf,.residual-unary,.residual-binary,.residual-group{display:inline}.residual-unary,.residual-binary{display:inline-flex;flex-wrap:wrap;align-items:baseline;gap:4px}.op-label{font-family:var(--font-mono);font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);padding:1px 4px;border:1px solid var(--border);border-radius:3px;background:var(--surface)}.residual-bound{color:var(--text-muted);font-size:11px}.residual-error{display:inline-flex;align-items:center;gap:6px;padding:2px 6px;border:1px solid var(--accent-violation);border-radius:3px;color:var(--accent-violation)}.residual-error .op-label{color:var(--accent-violation);border-color:var(--accent-violation);background:transparent}.residual-error-message{font-size:12px}.violations-panel{display:flex;flex-direction:column;gap:8px;font-family:var(--font-mono);color:var(--text-primary)}.violations-panel-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.violations-panel-title{font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);margin:0}.violations-panel-jump{font-family:var(--font-mono);font-size:11px;text-transform:lowercase;padding:4px 8px;background:var(--surface);color:var(--text-primary);border:1px solid var(--border);border-radius:3px;cursor:pointer}.violations-panel-jump:hover:not(:disabled){border-color:var(--border-strong)}.violations-panel-jump:disabled{color:var(--text-muted);cursor:not-allowed;opacity:.6}.violations-panel-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.violations-panel-row{border:1px solid var(--border);border-radius:3px;padding:8px;background:var(--surface-elevated)}.violations-panel-row[data-status=violated]{border-color:var(--accent-violation)}.violations-panel-row-head{display:flex;align-items:center;gap:8px}.violations-panel-badge{font-size:10px;text-transform:uppercase;letter-spacing:.06em;padding:2px 6px;border-radius:3px;border:1px solid var(--border);background:var(--surface);color:var(--text-muted)}.violations-panel-badge[data-status=violated]{color:var(--accent-violation);border-color:var(--accent-violation);background:transparent}.violations-panel-badge[data-status=holds]{color:var(--text-muted);opacity:.7}.violations-panel-name{font-weight:700;font-size:13px}.violations-panel-residual{margin-top:6px;font-size:12px}.violations-panel-residual summary{cursor:pointer;color:var(--text-muted);font-size:11px;text-transform:uppercase;letter-spacing:.06em;padding:2px 0;-webkit-user-select:none;user-select:none}.violations-panel-residual[open] summary{margin-bottom:6px}.exceptions-panel{display:flex;flex-direction:column;gap:8px;font-family:var(--font-mono);font-size:12px;color:var(--text-primary)}.exceptions-panel-toolbar{display:flex;justify-content:flex-end}.exceptions-panel-jump{font-family:var(--font-mono);font-size:11px}.exceptions-panel-jump:disabled{opacity:.5;cursor:not-allowed}.exceptions-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:6px}.exceptions-row details{border:1px dashed var(--border-strong);background:var(--surface);padding:6px 8px}.exceptions-row details[open]{border-color:var(--text-primary)}.exceptions-summary{display:grid;grid-template-columns:8px auto auto minmax(0,1fr) auto;align-items:baseline;gap:6px;cursor:pointer;list-style:none;outline:none}.exceptions-summary::-webkit-details-marker{display:none}.exceptions-marker{width:8px;height:8px;border:1px dashed var(--text-primary);background:transparent;align-self:center}.exceptions-class{font-weight:700;white-space:nowrap}.exceptions-colon{color:var(--text-muted)}.exceptions-message{color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.exceptions-time{color:var(--text-muted);font-variant-numeric:tabular-nums;margin-left:auto}.exceptions-stack{margin:8px 0 0;padding:8px;font-family:var(--font-mono);font-size:11px;background:var(--background);border:1px solid var(--border);max-height:220px;overflow-y:auto;white-space:pre}.metrics-chart{display:flex;flex-direction:column;width:100%;height:100%;min-height:0;font-family:var(--font-mono);font-size:9px;color:var(--text-muted)}.metrics-lanes{flex:1 1 auto;position:relative;display:flex;flex-direction:column;min-height:0}.metrics-lane{flex:1 1 0;display:grid;grid-template-columns:18px minmax(0,1fr) 32px;align-items:stretch;min-height:0;border-bottom:1px solid var(--border)}.metrics-lane:last-of-type{border-bottom:none}.metrics-lane-label{display:flex;align-items:center;justify-content:center;writing-mode:vertical-rl;transform:rotate(180deg);font-size:8px;font-weight:600;letter-spacing:.12em;border-right:1px solid var(--border)}.metrics-lane-plot{position:relative;min-width:0;min-height:0}.metrics-lane-canvas{position:absolute;top:4px;right:0;bottom:4px;left:0}.metrics-lane-svg{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;display:block}.metrics-lane-path{fill:none;stroke:var(--text-primary);stroke-width:1;vector-effect:non-scaling-stroke}.metrics-lane-dot{position:absolute;width:5px;height:5px;border-radius:50%;background:var(--text-primary);transform:translate(-50%,-50%);pointer-events:none}.metrics-lane-dot[data-active=true]{width:7px;height:7px}.metrics-lane-tooltip{position:absolute;padding:2px 6px;border:1px solid var(--border-strong);background:var(--surface);color:var(--text-primary);font-variant-numeric:tabular-nums;font-size:10px;white-space:nowrap;pointer-events:none;z-index:2}.metrics-lane-tooltip[data-placement=above]{transform:translate(-50%,calc(-100% - 6px))}.metrics-lane-tooltip[data-placement=below]{transform:translate(-50%,6px)}.metrics-lane-highlight{position:absolute;top:0;bottom:0;width:1px;background:var(--text-primary);opacity:.7;pointer-events:none}.metrics-lane-ticks{display:flex;flex-direction:column;justify-content:space-between;align-items:flex-start;padding:2px 6px;border-left:1px solid var(--border);font-variant-numeric:tabular-nums;font-size:9px}.metrics-hits{position:absolute;top:0;right:32px;bottom:0;left:18px;display:block;pointer-events:none}.metrics-hit{position:absolute;top:0;bottom:0;background:transparent;border:0;padding:0;margin:0;cursor:pointer;pointer-events:auto}.metrics-hit:hover{background:color-mix(in srgb,var(--text-primary) 5%,transparent)}.metrics-axis{flex:0 0 auto;position:relative;height:20px;margin:0 32px 0 18px;border-top:1px solid var(--border)}.metrics-axis-label{position:absolute;top:2px;transform:translate(-50%);font-variant-numeric:tabular-nums;font-size:9px;white-space:nowrap}.tabs{display:flex;flex-direction:column;min-height:0;flex:1 1 auto;font-family:var(--font-mono)}.tabs-header{display:flex;gap:0;border-bottom:1px solid var(--border);flex:0 0 auto;padding:0 4px}.tabs-tab{font-family:var(--font-mono);font-size:10px;text-transform:uppercase;letter-spacing:.08em;padding:4px 10px;background:transparent;border:none;border-bottom:1px solid transparent;color:var(--text-muted);cursor:pointer;margin-bottom:-1px;display:inline-flex;align-items:center;gap:6px;outline:none}.tabs-tab:focus-visible{outline:1px solid var(--text-primary);outline-offset:-1px}.tabs-badge{display:inline-flex;align-items:center;justify-content:center;min-width:16px;padding:0 4px;border:1px solid var(--border-strong);border-radius:999px;font-size:9px;line-height:1;letter-spacing:0}.tabs-tab[data-active=true] .tabs-badge{border-color:var(--text-primary)}.tabs-badge[data-kind=violation]{border-color:var(--accent-violation);color:var(--accent-violation)}.tabs-tab:hover{color:var(--text-primary)}.tabs-tab[data-active=true]{color:var(--text-primary);border-bottom-color:var(--text-primary)}.tabs-panel{flex:1 1 auto;min-height:0;overflow:auto;display:flex;flex-direction:column} diff --git a/inspect-ui/dist/assets/index-DAhEzdrG.js b/inspect-ui/dist/assets/index-DAhEzdrG.js new file mode 100644 index 0000000..959be5d --- /dev/null +++ b/inspect-ui/dist/assets/index-DAhEzdrG.js @@ -0,0 +1,67 @@ +function xf(e,t){for(var n=0;nr[l]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const l of document.querySelectorAll('link[rel="modulepreload"]'))r(l);new MutationObserver(l=>{for(const i of l)if(i.type==="childList")for(const o of i.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&r(o)}).observe(document,{childList:!0,subtree:!0});function n(l){const i={};return l.integrity&&(i.integrity=l.integrity),l.referrerPolicy&&(i.referrerPolicy=l.referrerPolicy),l.crossOrigin==="use-credentials"?i.credentials="include":l.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(l){if(l.ep)return;l.ep=!0;const i=n(l);fetch(l.href,i)}})();function wf(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Au={exports:{}},yl={},Vu={exports:{}},O={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var sr=Symbol.for("react.element"),Sf=Symbol.for("react.portal"),kf=Symbol.for("react.fragment"),Ef=Symbol.for("react.strict_mode"),Cf=Symbol.for("react.profiler"),Nf=Symbol.for("react.provider"),jf=Symbol.for("react.context"),_f=Symbol.for("react.forward_ref"),Pf=Symbol.for("react.suspense"),Tf=Symbol.for("react.memo"),Lf=Symbol.for("react.lazy"),cs=Symbol.iterator;function Rf(e){return e===null||typeof e!="object"?null:(e=cs&&e[cs]||e["@@iterator"],typeof e=="function"?e:null)}var Bu={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Wu=Object.assign,Hu={};function mn(e,t,n){this.props=e,this.context=t,this.refs=Hu,this.updater=n||Bu}mn.prototype.isReactComponent={};mn.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};mn.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function Qu(){}Qu.prototype=mn.prototype;function uo(e,t,n){this.props=e,this.context=t,this.refs=Hu,this.updater=n||Bu}var ao=uo.prototype=new Qu;ao.constructor=uo;Wu(ao,mn.prototype);ao.isPureReactComponent=!0;var fs=Array.isArray,Ku=Object.prototype.hasOwnProperty,co={current:null},Gu={key:!0,ref:!0,__self:!0,__source:!0};function Ju(e,t,n){var r,l={},i=null,o=null;if(t!=null)for(r in t.ref!==void 0&&(o=t.ref),t.key!==void 0&&(i=""+t.key),t)Ku.call(t,r)&&!Gu.hasOwnProperty(r)&&(l[r]=t[r]);var s=arguments.length-2;if(s===1)l.children=n;else if(1>>1,ee=T[K];if(0>>1;Kl(Dl,I))Ctl(mr,Dl)?(T[K]=mr,T[Ct]=I,K=Ct):(T[K]=Dl,T[Et]=I,K=Et);else if(Ctl(mr,I))T[K]=mr,T[Ct]=I,K=Ct;else break e}}return z}function l(T,z){var I=T.sortIndex-z.sortIndex;return I!==0?I:T.id-z.id}if(typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var u=[],a=[],h=1,c=null,d=3,y=!1,g=!1,w=!1,N=typeof setTimeout=="function"?setTimeout:null,m=typeof clearTimeout=="function"?clearTimeout:null,f=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function v(T){for(var z=n(a);z!==null;){if(z.callback===null)r(a);else if(z.startTime<=T)r(a),z.sortIndex=z.expirationTime,t(u,z);else break;z=n(a)}}function x(T){if(w=!1,v(T),!g)if(n(u)!==null)g=!0,Ml(E);else{var z=n(a);z!==null&&Fl(x,z.startTime-T)}}function E(T,z){g=!1,w&&(w=!1,m(C),C=-1),y=!0;var I=d;try{for(v(z),c=n(u);c!==null&&(!(c.expirationTime>z)||T&&!X());){var K=c.callback;if(typeof K=="function"){c.callback=null,d=c.priorityLevel;var ee=K(c.expirationTime<=z);z=e.unstable_now(),typeof ee=="function"?c.callback=ee:c===n(u)&&r(u),v(z)}else r(u);c=n(u)}if(c!==null)var hr=!0;else{var Et=n(a);Et!==null&&Fl(x,Et.startTime-z),hr=!1}return hr}finally{c=null,d=I,y=!1}}var _=!1,P=null,C=-1,R=5,L=-1;function X(){return!(e.unstable_now()-LT||125K?(T.sortIndex=I,t(a,T),n(u)===null&&T===n(a)&&(w?(m(C),C=-1):w=!0,Fl(x,I-K))):(T.sortIndex=ee,t(u,T),g||y||(g=!0,Ml(E))),T},e.unstable_shouldYield=X,e.unstable_wrapCallback=function(T){var z=d;return function(){var I=d;d=z;try{return T.apply(this,arguments)}finally{d=I}}}})(ea);bu.exports=ea;var Wf=bu.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Hf=S,ke=Wf;function k(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),fi=Object.prototype.hasOwnProperty,Qf=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,ps={},hs={};function Kf(e){return fi.call(hs,e)?!0:fi.call(ps,e)?!1:Qf.test(e)?hs[e]=!0:(ps[e]=!0,!1)}function Gf(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function Jf(e,t,n,r){if(t===null||typeof t>"u"||Gf(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function pe(e,t,n,r,l,i,o){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=o}var ie={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){ie[e]=new pe(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];ie[t]=new pe(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){ie[e]=new pe(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){ie[e]=new pe(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){ie[e]=new pe(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){ie[e]=new pe(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){ie[e]=new pe(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){ie[e]=new pe(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){ie[e]=new pe(e,5,!1,e.toLowerCase(),null,!1,!1)});var po=/[\-:]([a-z])/g;function ho(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(po,ho);ie[t]=new pe(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(po,ho);ie[t]=new pe(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(po,ho);ie[t]=new pe(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){ie[e]=new pe(e,1,!1,e.toLowerCase(),null,!1,!1)});ie.xlinkHref=new pe("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){ie[e]=new pe(e,1,!1,e.toLowerCase(),null,!0,!0)});function mo(e,t,n,r){var l=ie.hasOwnProperty(t)?ie[t]:null;(l!==null?l.type!==0:r||!(2s||l[o]!==i[s]){var u=` +`+l[o].replace(" at new "," at ");return e.displayName&&u.includes("")&&(u=u.replace("",e.displayName)),u}while(1<=o&&0<=s);break}}}finally{Al=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?Pn(e):""}function Yf(e){switch(e.tag){case 5:return Pn(e.type);case 16:return Pn("Lazy");case 13:return Pn("Suspense");case 19:return Pn("SuspenseList");case 0:case 2:case 15:return e=Vl(e.type,!1),e;case 11:return e=Vl(e.type.render,!1),e;case 1:return e=Vl(e.type,!0),e;default:return""}}function mi(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Wt:return"Fragment";case Bt:return"Portal";case di:return"Profiler";case vo:return"StrictMode";case pi:return"Suspense";case hi:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case ra:return(e.displayName||"Context")+".Consumer";case na:return(e._context.displayName||"Context")+".Provider";case go:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case yo:return t=e.displayName||null,t!==null?t:mi(e.type)||"Memo";case tt:t=e._payload,e=e._init;try{return mi(e(t))}catch{}}return null}function Xf(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return mi(t);case 8:return t===vo?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function gt(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function ia(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Zf(e){var t=ia(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(o){r=""+o,i.call(this,o)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(o){r=""+o},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function yr(e){e._valueTracker||(e._valueTracker=Zf(e))}function oa(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=ia(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Gr(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function vi(e,t){var n=t.checked;return W({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function vs(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=gt(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function sa(e,t){t=t.checked,t!=null&&mo(e,"checked",t,!1)}function gi(e,t){sa(e,t);var n=gt(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?yi(e,t.type,n):t.hasOwnProperty("defaultValue")&&yi(e,t.type,gt(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function gs(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function yi(e,t,n){(t!=="number"||Gr(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Tn=Array.isArray;function tn(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=xr.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Wn(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var In={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},qf=["Webkit","ms","Moz","O"];Object.keys(In).forEach(function(e){qf.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),In[t]=In[e]})});function fa(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||In.hasOwnProperty(e)&&In[e]?(""+t).trim():t+"px"}function da(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,l=fa(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,l):e[n]=l}}var bf=W({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Si(e,t){if(t){if(bf[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(k(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(k(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(k(61))}if(t.style!=null&&typeof t.style!="object")throw Error(k(62))}}function ki(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Ei=null;function xo(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Ci=null,nn=null,rn=null;function ws(e){if(e=cr(e)){if(typeof Ci!="function")throw Error(k(280));var t=e.stateNode;t&&(t=El(t),Ci(e.stateNode,e.type,t))}}function pa(e){nn?rn?rn.push(e):rn=[e]:nn=e}function ha(){if(nn){var e=nn,t=rn;if(rn=nn=null,ws(e),t)for(e=0;e>>=0,e===0?32:31-(cd(e)/fd|0)|0}var wr=64,Sr=4194304;function Ln(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64: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&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Zr(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,l=e.suspendedLanes,i=e.pingedLanes,o=n&268435455;if(o!==0){var s=o&~l;s!==0?r=Ln(s):(i&=o,i!==0&&(r=Ln(i)))}else o=n&~l,o!==0?r=Ln(o):i!==0&&(r=Ln(i));if(r===0)return 0;if(t!==0&&t!==r&&!(t&l)&&(l=r&-r,i=t&-t,l>=i||l===16&&(i&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function ur(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Me(t),e[t]=n}function md(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Mn),Ts=" ",Ls=!1;function Oa(e,t){switch(e){case"keyup":return Wd.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Ma(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Ht=!1;function Qd(e,t){switch(e){case"compositionend":return Ma(t);case"keypress":return t.which!==32?null:(Ls=!0,Ts);case"textInput":return e=t.data,e===Ts&&Ls?null:e;default:return null}}function Kd(e,t){if(Ht)return e==="compositionend"||!_o&&Oa(e,t)?(e=za(),$r=Co=it=null,Ht=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=Os(n)}}function Ua(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Ua(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Aa(){for(var e=window,t=Gr();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Gr(e.document)}return t}function Po(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function tp(e){var t=Aa(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&Ua(n.ownerDocument.documentElement,n)){if(r!==null&&Po(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,i=Math.min(r.start,l);r=r.end===void 0?i:Math.min(r.end,l),!e.extend&&i>r&&(l=r,r=i,i=l),l=Ms(n,i);var o=Ms(n,r);l&&o&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==o.node||e.focusOffset!==o.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(o.node,o.offset)):(t.setEnd(o.node,o.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Qt=null,Li=null,Dn=null,Ri=!1;function Fs(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Ri||Qt==null||Qt!==Gr(r)||(r=Qt,"selectionStart"in r&&Po(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Dn&&Yn(Dn,r)||(Dn=r,r=el(Li,"onSelect"),0Jt||(e.current=Di[Jt],Di[Jt]=null,Jt--)}function D(e,t){Jt++,Di[Jt]=e.current,e.current=t}var yt={},ae=wt(yt),ve=wt(!1),zt=yt;function an(e,t){var n=e.type.contextTypes;if(!n)return yt;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var l={},i;for(i in n)l[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function ge(e){return e=e.childContextTypes,e!=null}function nl(){U(ve),U(ae)}function Ws(e,t,n){if(ae.current!==yt)throw Error(k(168));D(ae,t),D(ve,n)}function Ya(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var l in r)if(!(l in t))throw Error(k(108,Xf(e)||"Unknown",l));return W({},n,r)}function rl(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||yt,zt=ae.current,D(ae,e),D(ve,ve.current),!0}function Hs(e,t,n){var r=e.stateNode;if(!r)throw Error(k(169));n?(e=Ya(e,t,zt),r.__reactInternalMemoizedMergedChildContext=e,U(ve),U(ae),D(ae,e)):U(ve),D(ve,n)}var He=null,Cl=!1,ti=!1;function Xa(e){He===null?He=[e]:He.push(e)}function pp(e){Cl=!0,Xa(e)}function St(){if(!ti&&He!==null){ti=!0;var e=0,t=F;try{var n=He;for(F=1;e>=o,l-=o,Qe=1<<32-Me(t)+l|n<C?(R=P,P=null):R=P.sibling;var L=d(m,P,v[C],x);if(L===null){P===null&&(P=R);break}e&&P&&L.alternate===null&&t(m,P),f=i(L,f,C),_===null?E=L:_.sibling=L,_=L,P=R}if(C===v.length)return n(m,P),A&&Nt(m,C),E;if(P===null){for(;CC?(R=P,P=null):R=P.sibling;var X=d(m,P,L.value,x);if(X===null){P===null&&(P=R);break}e&&P&&X.alternate===null&&t(m,P),f=i(X,f,C),_===null?E=X:_.sibling=X,_=X,P=R}if(L.done)return n(m,P),A&&Nt(m,C),E;if(P===null){for(;!L.done;C++,L=v.next())L=c(m,L.value,x),L!==null&&(f=i(L,f,C),_===null?E=L:_.sibling=L,_=L);return A&&Nt(m,C),E}for(P=r(m,P);!L.done;C++,L=v.next())L=y(P,m,C,L.value,x),L!==null&&(e&&L.alternate!==null&&P.delete(L.key===null?C:L.key),f=i(L,f,C),_===null?E=L:_.sibling=L,_=L);return e&&P.forEach(function(Q){return t(m,Q)}),A&&Nt(m,C),E}function N(m,f,v,x){if(typeof v=="object"&&v!==null&&v.type===Wt&&v.key===null&&(v=v.props.children),typeof v=="object"&&v!==null){switch(v.$$typeof){case gr:e:{for(var E=v.key,_=f;_!==null;){if(_.key===E){if(E=v.type,E===Wt){if(_.tag===7){n(m,_.sibling),f=l(_,v.props.children),f.return=m,m=f;break e}}else if(_.elementType===E||typeof E=="object"&&E!==null&&E.$$typeof===tt&&Gs(E)===_.type){n(m,_.sibling),f=l(_,v.props),f.ref=Nn(m,_,v),f.return=m,m=f;break e}n(m,_);break}else t(m,_);_=_.sibling}v.type===Wt?(f=Rt(v.props.children,m.mode,x,v.key),f.return=m,m=f):(x=Kr(v.type,v.key,v.props,null,m.mode,x),x.ref=Nn(m,f,v),x.return=m,m=x)}return o(m);case Bt:e:{for(_=v.key;f!==null;){if(f.key===_)if(f.tag===4&&f.stateNode.containerInfo===v.containerInfo&&f.stateNode.implementation===v.implementation){n(m,f.sibling),f=l(f,v.children||[]),f.return=m,m=f;break e}else{n(m,f);break}else t(m,f);f=f.sibling}f=ai(v,m.mode,x),f.return=m,m=f}return o(m);case tt:return _=v._init,N(m,f,_(v._payload),x)}if(Tn(v))return g(m,f,v,x);if(wn(v))return w(m,f,v,x);Pr(m,v)}return typeof v=="string"&&v!==""||typeof v=="number"?(v=""+v,f!==null&&f.tag===6?(n(m,f.sibling),f=l(f,v),f.return=m,m=f):(n(m,f),f=ui(v,m.mode,x),f.return=m,m=f),o(m)):n(m,f)}return N}var fn=ec(!0),tc=ec(!1),ol=wt(null),sl=null,Zt=null,zo=null;function Io(){zo=Zt=sl=null}function Oo(e){var t=ol.current;U(ol),e._currentValue=t}function Ai(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function on(e,t){sl=e,zo=Zt=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(me=!0),e.firstContext=null)}function Te(e){var t=e._currentValue;if(zo!==e)if(e={context:e,memoizedValue:t,next:null},Zt===null){if(sl===null)throw Error(k(308));Zt=e,sl.dependencies={lanes:0,firstContext:e}}else Zt=Zt.next=e;return t}var Pt=null;function Mo(e){Pt===null?Pt=[e]:Pt.push(e)}function nc(e,t,n,r){var l=t.interleaved;return l===null?(n.next=n,Mo(t)):(n.next=l.next,l.next=n),t.interleaved=n,Xe(e,r)}function Xe(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var nt=!1;function Fo(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function rc(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Ge(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function dt(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,M&2){var l=r.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),r.pending=t,Xe(e,n)}return l=r.interleaved,l===null?(t.next=t,Mo(r)):(t.next=l.next,l.next=t),r.interleaved=t,Xe(e,n)}function Ar(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,So(e,n)}}function Js(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var l=null,i=null;if(n=n.firstBaseUpdate,n!==null){do{var o={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};i===null?l=i=o:i=i.next=o,n=n.next}while(n!==null);i===null?l=i=t:i=i.next=t}else l=i=t;n={baseState:r.baseState,firstBaseUpdate:l,lastBaseUpdate:i,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function ul(e,t,n,r){var l=e.updateQueue;nt=!1;var i=l.firstBaseUpdate,o=l.lastBaseUpdate,s=l.shared.pending;if(s!==null){l.shared.pending=null;var u=s,a=u.next;u.next=null,o===null?i=a:o.next=a,o=u;var h=e.alternate;h!==null&&(h=h.updateQueue,s=h.lastBaseUpdate,s!==o&&(s===null?h.firstBaseUpdate=a:s.next=a,h.lastBaseUpdate=u))}if(i!==null){var c=l.baseState;o=0,h=a=u=null,s=i;do{var d=s.lane,y=s.eventTime;if((r&d)===d){h!==null&&(h=h.next={eventTime:y,lane:0,tag:s.tag,payload:s.payload,callback:s.callback,next:null});e:{var g=e,w=s;switch(d=t,y=n,w.tag){case 1:if(g=w.payload,typeof g=="function"){c=g.call(y,c,d);break e}c=g;break e;case 3:g.flags=g.flags&-65537|128;case 0:if(g=w.payload,d=typeof g=="function"?g.call(y,c,d):g,d==null)break e;c=W({},c,d);break e;case 2:nt=!0}}s.callback!==null&&s.lane!==0&&(e.flags|=64,d=l.effects,d===null?l.effects=[s]:d.push(s))}else y={eventTime:y,lane:d,tag:s.tag,payload:s.payload,callback:s.callback,next:null},h===null?(a=h=y,u=c):h=h.next=y,o|=d;if(s=s.next,s===null){if(s=l.shared.pending,s===null)break;d=s,s=d.next,d.next=null,l.lastBaseUpdate=d,l.shared.pending=null}}while(!0);if(h===null&&(u=c),l.baseState=u,l.firstBaseUpdate=a,l.lastBaseUpdate=h,t=l.shared.interleaved,t!==null){l=t;do o|=l.lane,l=l.next;while(l!==t)}else i===null&&(l.shared.lanes=0);Mt|=o,e.lanes=o,e.memoizedState=c}}function Ys(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=ri.transition;ri.transition={};try{e(!1),t()}finally{F=n,ri.transition=r}}function wc(){return Le().memoizedState}function gp(e,t,n){var r=ht(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Sc(e))kc(t,n);else if(n=nc(e,t,n,r),n!==null){var l=fe();Fe(n,e,r,l),Ec(n,t,r)}}function yp(e,t,n){var r=ht(e),l={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Sc(e))kc(t,l);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var o=t.lastRenderedState,s=i(o,n);if(l.hasEagerState=!0,l.eagerState=s,De(s,o)){var u=t.interleaved;u===null?(l.next=l,Mo(t)):(l.next=u.next,u.next=l),t.interleaved=l;return}}catch{}finally{}n=nc(e,t,l,r),n!==null&&(l=fe(),Fe(n,e,r,l),Ec(n,t,r))}}function Sc(e){var t=e.alternate;return e===B||t!==null&&t===B}function kc(e,t){$n=cl=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Ec(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,So(e,n)}}var fl={readContext:Te,useCallback:oe,useContext:oe,useEffect:oe,useImperativeHandle:oe,useInsertionEffect:oe,useLayoutEffect:oe,useMemo:oe,useReducer:oe,useRef:oe,useState:oe,useDebugValue:oe,useDeferredValue:oe,useTransition:oe,useMutableSource:oe,useSyncExternalStore:oe,useId:oe,unstable_isNewReconciler:!1},xp={readContext:Te,useCallback:function(e,t){return Ue().memoizedState=[e,t===void 0?null:t],e},useContext:Te,useEffect:Zs,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Br(4194308,4,mc.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Br(4194308,4,e,t)},useInsertionEffect:function(e,t){return Br(4,2,e,t)},useMemo:function(e,t){var n=Ue();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=Ue();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=gp.bind(null,B,e),[r.memoizedState,e]},useRef:function(e){var t=Ue();return e={current:e},t.memoizedState=e},useState:Xs,useDebugValue:Ho,useDeferredValue:function(e){return Ue().memoizedState=e},useTransition:function(){var e=Xs(!1),t=e[0];return e=vp.bind(null,e[1]),Ue().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=B,l=Ue();if(A){if(n===void 0)throw Error(k(407));n=n()}else{if(n=t(),ne===null)throw Error(k(349));Ot&30||sc(r,t,n)}l.memoizedState=n;var i={value:n,getSnapshot:t};return l.queue=i,Zs(ac.bind(null,r,i,e),[e]),r.flags|=2048,rr(9,uc.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=Ue(),t=ne.identifierPrefix;if(A){var n=Ke,r=Qe;n=(r&~(1<<32-Me(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=tr++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=o.createElement(n,{is:r.is}):(e=o.createElement(n),n==="select"&&(o=e,r.multiple?o.multiple=!0:r.size&&(o.size=r.size))):e=o.createElementNS(e,n),e[Ae]=t,e[qn]=r,Ic(e,t,!1,!1),t.stateNode=e;e:{switch(o=ki(n,r),n){case"dialog":$("cancel",e),$("close",e),l=r;break;case"iframe":case"object":case"embed":$("load",e),l=r;break;case"video":case"audio":for(l=0;lhn&&(t.flags|=128,r=!0,jn(i,!1),t.lanes=4194304)}else{if(!r)if(e=al(o),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),jn(i,!0),i.tail===null&&i.tailMode==="hidden"&&!o.alternate&&!A)return se(t),null}else 2*G()-i.renderingStartTime>hn&&n!==1073741824&&(t.flags|=128,r=!0,jn(i,!1),t.lanes=4194304);i.isBackwards?(o.sibling=t.child,t.child=o):(n=i.last,n!==null?n.sibling=o:t.child=o,i.last=o)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=G(),t.sibling=null,n=V.current,D(V,r?n&1|2:n&1),t):(se(t),null);case 22:case 23:return Xo(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?xe&1073741824&&(se(t),t.subtreeFlags&6&&(t.flags|=8192)):se(t),null;case 24:return null;case 25:return null}throw Error(k(156,t.tag))}function _p(e,t){switch(Lo(t),t.tag){case 1:return ge(t.type)&&nl(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return dn(),U(ve),U(ae),Uo(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return $o(t),null;case 13:if(U(V),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(k(340));cn()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return U(V),null;case 4:return dn(),null;case 10:return Oo(t.type._context),null;case 22:case 23:return Xo(),null;case 24:return null;default:return null}}var Lr=!1,ue=!1,Pp=typeof WeakSet=="function"?WeakSet:Set,j=null;function qt(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){H(e,t,r)}else n.current=null}function Yi(e,t,n){try{n()}catch(r){H(e,t,r)}}var uu=!1;function Tp(e,t){if(zi=qr,e=Aa(),Po(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var o=0,s=-1,u=-1,a=0,h=0,c=e,d=null;t:for(;;){for(var y;c!==n||l!==0&&c.nodeType!==3||(s=o+l),c!==i||r!==0&&c.nodeType!==3||(u=o+r),c.nodeType===3&&(o+=c.nodeValue.length),(y=c.firstChild)!==null;)d=c,c=y;for(;;){if(c===e)break t;if(d===n&&++a===l&&(s=o),d===i&&++h===r&&(u=o),(y=c.nextSibling)!==null)break;c=d,d=c.parentNode}c=y}n=s===-1||u===-1?null:{start:s,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for(Ii={focusedElem:e,selectionRange:n},qr=!1,j=t;j!==null;)if(t=j,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,j=e;else for(;j!==null;){t=j;try{var g=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(g!==null){var w=g.memoizedProps,N=g.memoizedState,m=t.stateNode,f=m.getSnapshotBeforeUpdate(t.elementType===t.type?w:ze(t.type,w),N);m.__reactInternalSnapshotBeforeUpdate=f}break;case 3:var v=t.stateNode.containerInfo;v.nodeType===1?v.textContent="":v.nodeType===9&&v.documentElement&&v.removeChild(v.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(k(163))}}catch(x){H(t,t.return,x)}if(e=t.sibling,e!==null){e.return=t.return,j=e;break}j=t.return}return g=uu,uu=!1,g}function Un(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var i=l.destroy;l.destroy=void 0,i!==void 0&&Yi(t,n,i)}l=l.next}while(l!==r)}}function _l(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Xi(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Fc(e){var t=e.alternate;t!==null&&(e.alternate=null,Fc(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Ae],delete t[qn],delete t[Fi],delete t[fp],delete t[dp])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Dc(e){return e.tag===5||e.tag===3||e.tag===4}function au(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Dc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Zi(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=tl));else if(r!==4&&(e=e.child,e!==null))for(Zi(e,t,n),e=e.sibling;e!==null;)Zi(e,t,n),e=e.sibling}function qi(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(qi(e,t,n),e=e.sibling;e!==null;)qi(e,t,n),e=e.sibling}var re=null,Ie=!1;function et(e,t,n){for(n=n.child;n!==null;)$c(e,t,n),n=n.sibling}function $c(e,t,n){if(Ve&&typeof Ve.onCommitFiberUnmount=="function")try{Ve.onCommitFiberUnmount(xl,n)}catch{}switch(n.tag){case 5:ue||qt(n,t);case 6:var r=re,l=Ie;re=null,et(e,t,n),re=r,Ie=l,re!==null&&(Ie?(e=re,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):re.removeChild(n.stateNode));break;case 18:re!==null&&(Ie?(e=re,n=n.stateNode,e.nodeType===8?ei(e.parentNode,n):e.nodeType===1&&ei(e,n),Gn(e)):ei(re,n.stateNode));break;case 4:r=re,l=Ie,re=n.stateNode.containerInfo,Ie=!0,et(e,t,n),re=r,Ie=l;break;case 0:case 11:case 14:case 15:if(!ue&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var i=l,o=i.destroy;i=i.tag,o!==void 0&&(i&2||i&4)&&Yi(n,t,o),l=l.next}while(l!==r)}et(e,t,n);break;case 1:if(!ue&&(qt(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(s){H(n,t,s)}et(e,t,n);break;case 21:et(e,t,n);break;case 22:n.mode&1?(ue=(r=ue)||n.memoizedState!==null,et(e,t,n),ue=r):et(e,t,n);break;default:et(e,t,n)}}function cu(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new Pp),t.forEach(function(r){var l=$p.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function Re(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=o),r&=~i}if(r=l,r=G()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Rp(r/1960))-r,10e?16:e,ot===null)var r=!1;else{if(e=ot,ot=null,hl=0,M&6)throw Error(k(331));var l=M;for(M|=4,j=e.current;j!==null;){var i=j,o=i.child;if(j.flags&16){var s=i.deletions;if(s!==null){for(var u=0;uG()-Jo?Lt(e,0):Go|=n),ye(e,t)}function Kc(e,t){t===0&&(e.mode&1?(t=Sr,Sr<<=1,!(Sr&130023424)&&(Sr=4194304)):t=1);var n=fe();e=Xe(e,t),e!==null&&(ur(e,t,n),ye(e,n))}function Dp(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Kc(e,n)}function $p(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(k(314))}r!==null&&r.delete(t),Kc(e,n)}var Gc;Gc=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||ve.current)me=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return me=!1,Np(e,t,n);me=!!(e.flags&131072)}else me=!1,A&&t.flags&1048576&&Za(t,il,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Wr(e,t),e=t.pendingProps;var l=an(t,ae.current);on(t,n),l=Vo(null,t,r,e,l,n);var i=Bo();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,ge(r)?(i=!0,rl(t)):i=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,Fo(t),l.updater=jl,t.stateNode=l,l._reactInternals=t,Bi(t,r,e,n),t=Qi(null,t,r,!0,i,n)):(t.tag=0,A&&i&&To(t),ce(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Wr(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=Ap(r),e=ze(r,e),l){case 0:t=Hi(null,t,r,e,n);break e;case 1:t=iu(null,t,r,e,n);break e;case 11:t=ru(null,t,r,e,n);break e;case 14:t=lu(null,t,r,ze(r.type,e),n);break e}throw Error(k(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),Hi(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),iu(e,t,r,l,n);case 3:e:{if(Lc(t),e===null)throw Error(k(387));r=t.pendingProps,i=t.memoizedState,l=i.element,rc(e,t),ul(t,r,null,n);var o=t.memoizedState;if(r=o.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:o.cache,pendingSuspenseBoundaries:o.pendingSuspenseBoundaries,transitions:o.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){l=pn(Error(k(423)),t),t=ou(e,t,r,n,l);break e}else if(r!==l){l=pn(Error(k(424)),t),t=ou(e,t,r,n,l);break e}else for(we=ft(t.stateNode.containerInfo.firstChild),Se=t,A=!0,Oe=null,n=tc(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(cn(),r===l){t=Ze(e,t,n);break e}ce(e,t,r,n)}t=t.child}return t;case 5:return lc(t),e===null&&Ui(t),r=t.type,l=t.pendingProps,i=e!==null?e.memoizedProps:null,o=l.children,Oi(r,l)?o=null:i!==null&&Oi(r,i)&&(t.flags|=32),Tc(e,t),ce(e,t,o,n),t.child;case 6:return e===null&&Ui(t),null;case 13:return Rc(e,t,n);case 4:return Do(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=fn(t,null,r,n):ce(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),ru(e,t,r,l,n);case 7:return ce(e,t,t.pendingProps,n),t.child;case 8:return ce(e,t,t.pendingProps.children,n),t.child;case 12:return ce(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,i=t.memoizedProps,o=l.value,D(ol,r._currentValue),r._currentValue=o,i!==null)if(De(i.value,o)){if(i.children===l.children&&!ve.current){t=Ze(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var s=i.dependencies;if(s!==null){o=i.child;for(var u=s.firstContext;u!==null;){if(u.context===r){if(i.tag===1){u=Ge(-1,n&-n),u.tag=2;var a=i.updateQueue;if(a!==null){a=a.shared;var h=a.pending;h===null?u.next=u:(u.next=h.next,h.next=u),a.pending=u}}i.lanes|=n,u=i.alternate,u!==null&&(u.lanes|=n),Ai(i.return,n,t),s.lanes|=n;break}u=u.next}}else if(i.tag===10)o=i.type===t.type?null:i.child;else if(i.tag===18){if(o=i.return,o===null)throw Error(k(341));o.lanes|=n,s=o.alternate,s!==null&&(s.lanes|=n),Ai(o,n,t),o=i.sibling}else o=i.child;if(o!==null)o.return=i;else for(o=i;o!==null;){if(o===t){o=null;break}if(i=o.sibling,i!==null){i.return=o.return,o=i;break}o=o.return}i=o}ce(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,on(t,n),l=Te(l),r=r(l),t.flags|=1,ce(e,t,r,n),t.child;case 14:return r=t.type,l=ze(r,t.pendingProps),l=ze(r.type,l),lu(e,t,r,l,n);case 15:return _c(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),Wr(e,t),t.tag=1,ge(r)?(e=!0,rl(t)):e=!1,on(t,n),Cc(t,r,l),Bi(t,r,l,n),Qi(null,t,r,!0,e,n);case 19:return zc(e,t,n);case 22:return Pc(e,t,n)}throw Error(k(156,t.tag))};function Jc(e,t){return Sa(e,t)}function Up(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function _e(e,t,n,r){return new Up(e,t,n,r)}function qo(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Ap(e){if(typeof e=="function")return qo(e)?1:0;if(e!=null){if(e=e.$$typeof,e===go)return 11;if(e===yo)return 14}return 2}function mt(e,t){var n=e.alternate;return n===null?(n=_e(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Kr(e,t,n,r,l,i){var o=2;if(r=e,typeof e=="function")qo(e)&&(o=1);else if(typeof e=="string")o=5;else e:switch(e){case Wt:return Rt(n.children,l,i,t);case vo:o=8,l|=8;break;case di:return e=_e(12,n,t,l|2),e.elementType=di,e.lanes=i,e;case pi:return e=_e(13,n,t,l),e.elementType=pi,e.lanes=i,e;case hi:return e=_e(19,n,t,l),e.elementType=hi,e.lanes=i,e;case la:return Tl(n,l,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case na:o=10;break e;case ra:o=9;break e;case go:o=11;break e;case yo:o=14;break e;case tt:o=16,r=null;break e}throw Error(k(130,e==null?e:typeof e,""))}return t=_e(o,n,t,l),t.elementType=e,t.type=r,t.lanes=i,t}function Rt(e,t,n,r){return e=_e(7,e,r,t),e.lanes=n,e}function Tl(e,t,n,r){return e=_e(22,e,r,t),e.elementType=la,e.lanes=n,e.stateNode={isHidden:!1},e}function ui(e,t,n){return e=_e(6,e,null,t),e.lanes=n,e}function ai(e,t,n){return t=_e(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Vp(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Wl(0),this.expirationTimes=Wl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Wl(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function bo(e,t,n,r,l,i,o,s,u){return e=new Vp(e,t,n,s,u),t===1?(t=1,i===!0&&(t|=8)):t=0,i=_e(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Fo(i),e}function Bp(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(qc)}catch(e){console.error(e)}}qc(),qu.exports=Ee;var Gp=qu.exports,bc,yu=Gp;bc=yu.createRoot,yu.hydrateRoot;/** + * @remix-run/router v1.23.2 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function ir(){return ir=Object.assign?Object.assign.bind():function(e){for(var t=1;t"u")throw new Error(t)}function rs(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function Yp(){return Math.random().toString(36).substr(2,8)}function wu(e,t){return{usr:e.state,key:e.key,idx:t}}function ro(e,t,n,r){return n===void 0&&(n=null),ir({pathname:typeof e=="string"?e:e.pathname,search:"",hash:""},typeof t=="string"?yn(t):t,{state:n,key:t&&t.key||r||Yp()})}function gl(e){let{pathname:t="/",search:n="",hash:r=""}=e;return n&&n!=="?"&&(t+=n.charAt(0)==="?"?n:"?"+n),r&&r!=="#"&&(t+=r.charAt(0)==="#"?r:"#"+r),t}function yn(e){let t={};if(e){let n=e.indexOf("#");n>=0&&(t.hash=e.substr(n),e=e.substr(0,n));let r=e.indexOf("?");r>=0&&(t.search=e.substr(r),e=e.substr(0,r)),e&&(t.pathname=e)}return t}function Xp(e,t,n,r){r===void 0&&(r={});let{window:l=document.defaultView,v5Compat:i=!1}=r,o=l.history,s=st.Pop,u=null,a=h();a==null&&(a=0,o.replaceState(ir({},o.state,{idx:a}),""));function h(){return(o.state||{idx:null}).idx}function c(){s=st.Pop;let N=h(),m=N==null?null:N-a;a=N,u&&u({action:s,location:w.location,delta:m})}function d(N,m){s=st.Push;let f=ro(w.location,N,m);a=h()+1;let v=wu(f,a),x=w.createHref(f);try{o.pushState(v,"",x)}catch(E){if(E instanceof DOMException&&E.name==="DataCloneError")throw E;l.location.assign(x)}i&&u&&u({action:s,location:w.location,delta:1})}function y(N,m){s=st.Replace;let f=ro(w.location,N,m);a=h();let v=wu(f,a),x=w.createHref(f);o.replaceState(v,"",x),i&&u&&u({action:s,location:w.location,delta:0})}function g(N){let m=l.location.origin!=="null"?l.location.origin:l.location.href,f=typeof N=="string"?N:gl(N);return f=f.replace(/ $/,"%20"),J(m,"No window.location.(origin|href) available to create URL for href: "+f),new URL(f,m)}let w={get action(){return s},get location(){return e(l,o)},listen(N){if(u)throw new Error("A history only accepts one active listener");return l.addEventListener(xu,c),u=N,()=>{l.removeEventListener(xu,c),u=null}},createHref(N){return t(l,N)},createURL:g,encodeLocation(N){let m=g(N);return{pathname:m.pathname,search:m.search,hash:m.hash}},push:d,replace:y,go(N){return o.go(N)}};return w}var Su;(function(e){e.data="data",e.deferred="deferred",e.redirect="redirect",e.error="error"})(Su||(Su={}));function Zp(e,t,n){return n===void 0&&(n="/"),qp(e,t,n)}function qp(e,t,n,r){let l=typeof t=="string"?yn(t):t,i=ls(l.pathname||"/",n);if(i==null)return null;let o=ef(e);bp(o);let s=null;for(let u=0;s==null&&u{let u={relativePath:s===void 0?i.path||"":s,caseSensitive:i.caseSensitive===!0,childrenIndex:o,route:i};u.relativePath.startsWith("/")&&(J(u.relativePath.startsWith(r),'Absolute route path "'+u.relativePath+'" nested under path '+('"'+r+'" is not valid. An absolute child route path ')+"must start with the combined path of all its parent routes."),u.relativePath=u.relativePath.slice(r.length));let a=vt([r,u.relativePath]),h=n.concat(u);i.children&&i.children.length>0&&(J(i.index!==!0,"Index routes must not have child routes. Please remove "+('all child routes from route path "'+a+'".')),ef(i.children,t,h,a)),!(i.path==null&&!i.index)&&t.push({path:a,score:oh(a,i.index),routesMeta:h})};return e.forEach((i,o)=>{var s;if(i.path===""||!((s=i.path)!=null&&s.includes("?")))l(i,o);else for(let u of tf(i.path))l(i,o,u)}),t}function tf(e){let t=e.split("/");if(t.length===0)return[];let[n,...r]=t,l=n.endsWith("?"),i=n.replace(/\?$/,"");if(r.length===0)return l?[i,""]:[i];let o=tf(r.join("/")),s=[];return s.push(...o.map(u=>u===""?i:[i,u].join("/"))),l&&s.push(...o),s.map(u=>e.startsWith("/")&&u===""?"/":u)}function bp(e){e.sort((t,n)=>t.score!==n.score?n.score-t.score:sh(t.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}const eh=/^:[\w-]+$/,th=3,nh=2,rh=1,lh=10,ih=-2,ku=e=>e==="*";function oh(e,t){let n=e.split("/"),r=n.length;return n.some(ku)&&(r+=ih),t&&(r+=nh),n.filter(l=>!ku(l)).reduce((l,i)=>l+(eh.test(i)?th:i===""?rh:lh),r)}function sh(e,t){return e.length===t.length&&e.slice(0,-1).every((r,l)=>r===t[l])?e[e.length-1]-t[t.length-1]:0}function uh(e,t,n){let{routesMeta:r}=e,l={},i="/",o=[];for(let s=0;s{let{paramName:d,isOptional:y}=h;if(d==="*"){let w=s[c]||"";o=i.slice(0,i.length-w.length).replace(/(.)\/+$/,"$1")}const g=s[c];return y&&!g?a[d]=void 0:a[d]=(g||"").replace(/%2F/g,"/"),a},{}),pathname:i,pathnameBase:o,pattern:e}}function ch(e,t,n){t===void 0&&(t=!1),n===void 0&&(n=!0),rs(e==="*"||!e.endsWith("*")||e.endsWith("/*"),'Route path "'+e+'" will be treated as if it were '+('"'+e.replace(/\*$/,"/*")+'" because the `*` character must ')+"always follow a `/` in the pattern. To get rid of this warning, "+('please change the route path to "'+e.replace(/\*$/,"/*")+'".'));let r=[],l="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(o,s,u)=>(r.push({paramName:s,isOptional:u!=null}),u?"/?([^\\/]+)?":"/([^\\/]+)"));return e.endsWith("*")?(r.push({paramName:"*"}),l+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?l+="\\/*$":e!==""&&e!=="/"&&(l+="(?:(?=\\/|$))"),[new RegExp(l,t?void 0:"i"),r]}function fh(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return rs(!1,'The URL path "'+e+'" could not be decoded because it is is a malformed URL segment. This is probably due to a bad percent '+("encoding ("+t+").")),e}}function ls(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith("/")?t.length-1:t.length,r=e.charAt(n);return r&&r!=="/"?null:e.slice(n)||"/"}const dh=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,ph=e=>dh.test(e);function hh(e,t){t===void 0&&(t="/");let{pathname:n,search:r="",hash:l=""}=typeof e=="string"?yn(e):e,i;if(n)if(ph(n))i=n;else{if(n.includes("//")){let o=n;n=n.replace(/\/\/+/g,"/"),rs(!1,"Pathnames cannot have embedded double slashes - normalizing "+(o+" -> "+n))}n.startsWith("/")?i=Eu(n.substring(1),"/"):i=Eu(n,t)}else i=t;return{pathname:i,search:gh(r),hash:yh(l)}}function Eu(e,t){let n=t.replace(/\/+$/,"").split("/");return e.split("/").forEach(l=>{l===".."?n.length>1&&n.pop():l!=="."&&n.push(l)}),n.length>1?n.join("/"):"/"}function ci(e,t,n,r){return"Cannot include a '"+e+"' character in a manually specified "+("`to."+t+"` field ["+JSON.stringify(r)+"]. Please separate it out to the ")+("`to."+n+"` field. Alternatively you may provide the full path as ")+'a string in and the router will parse it for you.'}function mh(e){return e.filter((t,n)=>n===0||t.route.path&&t.route.path.length>0)}function is(e,t){let n=mh(e);return t?n.map((r,l)=>l===n.length-1?r.pathname:r.pathnameBase):n.map(r=>r.pathnameBase)}function os(e,t,n,r){r===void 0&&(r=!1);let l;typeof e=="string"?l=yn(e):(l=ir({},e),J(!l.pathname||!l.pathname.includes("?"),ci("?","pathname","search",l)),J(!l.pathname||!l.pathname.includes("#"),ci("#","pathname","hash",l)),J(!l.search||!l.search.includes("#"),ci("#","search","hash",l)));let i=e===""||l.pathname==="",o=i?"/":l.pathname,s;if(o==null)s=n;else{let c=t.length-1;if(!r&&o.startsWith("..")){let d=o.split("/");for(;d[0]==="..";)d.shift(),c-=1;l.pathname=d.join("/")}s=c>=0?t[c]:"/"}let u=hh(l,s),a=o&&o!=="/"&&o.endsWith("/"),h=(i||o===".")&&n.endsWith("/");return!u.pathname.endsWith("/")&&(a||h)&&(u.pathname+="/"),u}const vt=e=>e.join("/").replace(/\/\/+/g,"/"),vh=e=>e.replace(/\/+$/,"").replace(/^\/*/,"/"),gh=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,yh=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e;function xh(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}const nf=["post","put","patch","delete"];new Set(nf);const wh=["get",...nf];new Set(wh);/** + * React Router v6.30.3 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function or(){return or=Object.assign?Object.assign.bind():function(e){for(var t=1;t{s.current=!0}),S.useCallback(function(a,h){if(h===void 0&&(h={}),!s.current)return;if(typeof a=="number"){r.go(a);return}let c=os(a,JSON.parse(o),i,h.relative==="path");e==null&&t!=="/"&&(c.pathname=c.pathname==="/"?t:vt([t,c.pathname])),(h.replace?r.replace:r.push)(c,h.state,h)},[t,r,o,i,e])}function of(){let{matches:e}=S.useContext(be),t=e[e.length-1];return t?t.params:{}}function sf(e,t){let{relative:n}=t===void 0?{}:t,{future:r}=S.useContext(kt),{matches:l}=S.useContext(be),{pathname:i}=dr(),o=JSON.stringify(is(l,r.v7_relativeSplatPath));return S.useMemo(()=>os(e,JSON.parse(o),i,n==="path"),[e,o,i,n])}function Ch(e,t){return Nh(e,t)}function Nh(e,t,n,r){xn()||J(!1);let{navigator:l}=S.useContext(kt),{matches:i}=S.useContext(be),o=i[i.length-1],s=o?o.params:{};o&&o.pathname;let u=o?o.pathnameBase:"/";o&&o.route;let a=dr(),h;if(t){var c;let N=typeof t=="string"?yn(t):t;u==="/"||(c=N.pathname)!=null&&c.startsWith(u)||J(!1),h=N}else h=a;let d=h.pathname||"/",y=d;if(u!=="/"){let N=u.replace(/^\//,"").split("/");y="/"+d.replace(/^\//,"").split("/").slice(N.length).join("/")}let g=Zp(e,{pathname:y}),w=Lh(g&&g.map(N=>Object.assign({},N,{params:Object.assign({},s,N.params),pathname:vt([u,l.encodeLocation?l.encodeLocation(N.pathname).pathname:N.pathname]),pathnameBase:N.pathnameBase==="/"?u:vt([u,l.encodeLocation?l.encodeLocation(N.pathnameBase).pathname:N.pathnameBase])})),i,n,r);return t&&w?S.createElement(Ol.Provider,{value:{location:or({pathname:"/",search:"",hash:"",state:null,key:"default"},h),navigationType:st.Pop}},w):w}function jh(){let e=Oh(),t=xh(e)?e.status+" "+e.statusText:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,l={padding:"0.5rem",backgroundColor:"rgba(200,200,200, 0.5)"};return S.createElement(S.Fragment,null,S.createElement("h2",null,"Unexpected Application Error!"),S.createElement("h3",{style:{fontStyle:"italic"}},t),n?S.createElement("pre",{style:l},n):null,null)}const _h=S.createElement(jh,null);class Ph extends S.Component{constructor(t){super(t),this.state={location:t.location,revalidation:t.revalidation,error:t.error}}static getDerivedStateFromError(t){return{error:t}}static getDerivedStateFromProps(t,n){return n.location!==t.location||n.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error!==void 0?t.error:n.error,location:n.location,revalidation:t.revalidation||n.revalidation}}componentDidCatch(t,n){console.error("React Router caught the following error during render",t,n)}render(){return this.state.error!==void 0?S.createElement(be.Provider,{value:this.props.routeContext},S.createElement(rf.Provider,{value:this.state.error,children:this.props.component})):this.props.children}}function Th(e){let{routeContext:t,match:n,children:r}=e,l=S.useContext(ss);return l&&l.static&&l.staticContext&&(n.route.errorElement||n.route.ErrorBoundary)&&(l.staticContext._deepestRenderedBoundaryId=n.route.id),S.createElement(be.Provider,{value:t},r)}function Lh(e,t,n,r){var l;if(t===void 0&&(t=[]),n===void 0&&(n=null),r===void 0&&(r=null),e==null){var i;if(!n)return null;if(n.errors)e=n.matches;else if((i=r)!=null&&i.v7_partialHydration&&t.length===0&&!n.initialized&&n.matches.length>0)e=n.matches;else return null}let o=e,s=(l=n)==null?void 0:l.errors;if(s!=null){let h=o.findIndex(c=>c.route.id&&(s==null?void 0:s[c.route.id])!==void 0);h>=0||J(!1),o=o.slice(0,Math.min(o.length,h+1))}let u=!1,a=-1;if(n&&r&&r.v7_partialHydration)for(let h=0;h=0?o=o.slice(0,a+1):o=[o[0]];break}}}return o.reduceRight((h,c,d)=>{let y,g=!1,w=null,N=null;n&&(y=s&&c.route.id?s[c.route.id]:void 0,w=c.route.errorElement||_h,u&&(a<0&&d===0?(Fh("route-fallback"),g=!0,N=null):a===d&&(g=!0,N=c.route.hydrateFallbackElement||null)));let m=t.concat(o.slice(0,d+1)),f=()=>{let v;return y?v=w:g?v=N:c.route.Component?v=S.createElement(c.route.Component,null):c.route.element?v=c.route.element:v=h,S.createElement(Th,{match:c,routeContext:{outlet:h,matches:m,isDataRoute:n!=null},children:v})};return n&&(c.route.ErrorBoundary||c.route.errorElement||d===0)?S.createElement(Ph,{location:n.location,revalidation:n.revalidation,component:w,error:y,children:f(),routeContext:{outlet:null,matches:m,isDataRoute:!0}}):f()},null)}var uf=function(e){return e.UseBlocker="useBlocker",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e}(uf||{}),af=function(e){return e.UseBlocker="useBlocker",e.UseLoaderData="useLoaderData",e.UseActionData="useActionData",e.UseRouteError="useRouteError",e.UseNavigation="useNavigation",e.UseRouteLoaderData="useRouteLoaderData",e.UseMatches="useMatches",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e.UseRouteId="useRouteId",e}(af||{});function Rh(e){let t=S.useContext(ss);return t||J(!1),t}function zh(e){let t=S.useContext(Sh);return t||J(!1),t}function Ih(e){let t=S.useContext(be);return t||J(!1),t}function cf(e){let t=Ih(),n=t.matches[t.matches.length-1];return n.route.id||J(!1),n.route.id}function Oh(){var e;let t=S.useContext(rf),n=zh(),r=cf();return t!==void 0?t:(e=n.errors)==null?void 0:e[r]}function Mh(){let{router:e}=Rh(uf.UseNavigateStable),t=cf(af.UseNavigateStable),n=S.useRef(!1);return lf(()=>{n.current=!0}),S.useCallback(function(l,i){i===void 0&&(i={}),n.current&&(typeof l=="number"?e.navigate(l):e.navigate(l,or({fromRouteId:t},i)))},[e,t])}const Cu={};function Fh(e,t,n){Cu[e]||(Cu[e]=!0)}function Dh(e,t){e==null||e.v7_startTransition,e==null||e.v7_relativeSplatPath}function $h(e){let{to:t,replace:n,state:r,relative:l}=e;xn()||J(!1);let{future:i,static:o}=S.useContext(kt),{matches:s}=S.useContext(be),{pathname:u}=dr(),a=us(),h=os(t,is(s,i.v7_relativeSplatPath),u,l==="path"),c=JSON.stringify(h);return S.useEffect(()=>a(JSON.parse(c),{replace:n,state:r,relative:l}),[a,c,l,n,r]),null}function zn(e){J(!1)}function Uh(e){let{basename:t="/",children:n=null,location:r,navigationType:l=st.Pop,navigator:i,static:o=!1,future:s}=e;xn()&&J(!1);let u=t.replace(/^\/*/,"/"),a=S.useMemo(()=>({basename:u,navigator:i,static:o,future:or({v7_relativeSplatPath:!1},s)}),[u,s,i,o]);typeof r=="string"&&(r=yn(r));let{pathname:h="/",search:c="",hash:d="",state:y=null,key:g="default"}=r,w=S.useMemo(()=>{let N=ls(h,u);return N==null?null:{location:{pathname:N,search:c,hash:d,state:y,key:g},navigationType:l}},[u,h,c,d,y,g,l]);return w==null?null:S.createElement(kt.Provider,{value:a},S.createElement(Ol.Provider,{children:n,value:w}))}function Ah(e){let{children:t,location:n}=e;return Ch(lo(t),n)}new Promise(()=>{});function lo(e,t){t===void 0&&(t=[]);let n=[];return S.Children.forEach(e,(r,l)=>{if(!S.isValidElement(r))return;let i=[...t,l];if(r.type===S.Fragment){n.push.apply(n,lo(r.props.children,i));return}r.type!==zn&&J(!1),!r.props.index||!r.props.children||J(!1);let o={id:r.props.id||i.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,loader:r.props.loader,action:r.props.action,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(o.children=lo(r.props.children,i)),n.push(o)}),n}/** + * React Router DOM v6.30.3 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function io(){return io=Object.assign?Object.assign.bind():function(e){for(var t=1;t=0)&&(n[l]=e[l]);return n}function Bh(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function Wh(e,t){return e.button===0&&(!t||t==="_self")&&!Bh(e)}const Hh=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset","viewTransition"],Qh="6";try{window.__reactRouterVersion=Qh}catch{}const Kh="startTransition",Nu=Ff[Kh];function Gh(e){let{basename:t,children:n,future:r,window:l}=e,i=S.useRef();i.current==null&&(i.current=Jp({window:l,v5Compat:!0}));let o=i.current,[s,u]=S.useState({action:o.action,location:o.location}),{v7_startTransition:a}=r||{},h=S.useCallback(c=>{a&&Nu?Nu(()=>u(c)):u(c)},[u,a]);return S.useLayoutEffect(()=>o.listen(h),[o,h]),S.useEffect(()=>Dh(r),[r]),S.createElement(Uh,{basename:t,children:n,location:s.location,navigationType:s.action,navigator:o,future:r})}const Jh=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",Yh=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,ff=S.forwardRef(function(t,n){let{onClick:r,relative:l,reloadDocument:i,replace:o,state:s,target:u,to:a,preventScrollReset:h,viewTransition:c}=t,d=Vh(t,Hh),{basename:y}=S.useContext(kt),g,w=!1;if(typeof a=="string"&&Yh.test(a)&&(g=a,Jh))try{let v=new URL(window.location.href),x=a.startsWith("//")?new URL(v.protocol+a):new URL(a),E=ls(x.pathname,y);x.origin===v.origin&&E!=null?a=E+x.search+x.hash:w=!0}catch{}let N=kh(a,{relative:l}),m=Xh(a,{replace:o,state:s,target:u,preventScrollReset:h,relative:l,viewTransition:c});function f(v){r&&r(v),v.defaultPrevented||m(v)}return S.createElement("a",io({},d,{href:g||N,onClick:w||i?r:f,ref:n,target:u}))});var ju;(function(e){e.UseScrollRestoration="useScrollRestoration",e.UseSubmit="useSubmit",e.UseSubmitFetcher="useSubmitFetcher",e.UseFetcher="useFetcher",e.useViewTransitionState="useViewTransitionState"})(ju||(ju={}));var _u;(function(e){e.UseFetcher="useFetcher",e.UseFetchers="useFetchers",e.UseScrollRestoration="useScrollRestoration"})(_u||(_u={}));function Xh(e,t){let{target:n,replace:r,state:l,preventScrollReset:i,relative:o,viewTransition:s}=t===void 0?{}:t,u=us(),a=dr(),h=sf(e,{relative:o});return S.useCallback(c=>{if(Wh(c,n)){c.preventDefault();let d=r!==void 0?r:gl(a)===gl(h);u(e,{replace:d,state:l,preventScrollReset:i,relative:o,viewTransition:s})}},[a,u,h,r,l,n,e,i,o,s])}async function as(e){const t=await fetch(e,{headers:{Accept:"application/json"}});if(!t.ok)throw new Error(`request failed: ${t.status} ${t.statusText} (${e})`);return await t.json()}function Zh(){return as("/api/runs")}function qh(e){return as(`/api/runs/${encodeURIComponent(e)}`)}function bh(e,t){return as(`/api/runs/${encodeURIComponent(e)}/steps/${t}`)}function Pu(e,t){return`/api/runs/${encodeURIComponent(e)}/screenshots/${encodeURIComponent(t)}`}function em(e,t){S.useEffect(()=>{if(typeof EventSource>"u")return;const n=new EventSource("/api/events"),r=()=>{t()};return n.addEventListener(e,r),()=>{n.removeEventListener(e,r),n.close()}},[e,t])}function tm(e){if(!e)return"-";if(e<1e3)return`${e}ms`;const t=e/1e3;if(t<60)return`${t.toFixed(1)}s`;const n=Math.floor(t/60),r=Math.round(t-n*60);return`${n}m${r}s`}function nm(e){const t=new Date(e);return Number.isNaN(t.getTime())?e:t.toLocaleString()}function rm(){const[e,t]=S.useState(null),[n,r]=S.useState(null),l=S.useCallback(()=>{Zh().then(t).catch(i=>{r(i instanceof Error?i.message:String(i))})},[]);return S.useEffect(()=>{l()},[l]),em("runs.changed",l),n?p.jsxs("div",{className:"status-block status-error",children:["failed to load runs: ",n]}):e?e.length===0?p.jsx("div",{className:"status-block",children:"no runs yet. run `sanderling test` to produce some."}):p.jsxs("table",{className:"run-table",children:[p.jsx("thead",{children:p.jsxs("tr",{children:[p.jsx("th",{children:"started"}),p.jsx("th",{children:"spec"}),p.jsx("th",{children:"seed"}),p.jsx("th",{children:"platform"}),p.jsx("th",{children:"duration"}),p.jsx("th",{children:"steps"}),p.jsx("th",{children:"violations"}),p.jsx("th",{})]})}),p.jsx("tbody",{children:e.map(i=>p.jsxs("tr",{children:[p.jsx("td",{children:p.jsx(ff,{to:`/runs/${i.id}`,children:nm(i.started_at)})}),p.jsx("td",{children:i.spec_path}),p.jsx("td",{children:i.seed}),p.jsx("td",{children:i.platform}),p.jsx("td",{children:tm(i.duration_millis)}),p.jsx("td",{children:i.step_count}),p.jsx("td",{children:i.violation_count>0?p.jsx("span",{className:"chip chip-violation",children:i.violation_count}):"0"}),p.jsx("td",{children:i.in_progress?p.jsx("span",{className:"chip chip-progress",children:"in progress"}):null})]},i.id))})]}):p.jsx("div",{className:"status-block",children:"loading runs..."})}const lm=["id","text","textPrefix","desc","descPrefix","class","classPrefix","package"];function df(e){const t=e.indexOf(":");if(t<=0)return null;const n=e.slice(0,t),r=e.slice(t+1);return lm.includes(n)?{kind:n,value:r}:null}function im(e){const t=df(e);return t?t.kind.endsWith("Prefix")?`${t.value}...`:t.value:e}function om(e){const t=e.action_kind,n=e.action_label??"";if(!t)return e.screen?{verb:"Observe",target:`@ ${e.screen}`,targetIsTag:!1}:{verb:"Observe",target:"",targetIsTag:!1};switch(t){case"Tap":return n?n.startsWith("(")&&n.endsWith(")")?{verb:"Click",target:n,targetIsTag:!1}:df(n)?{verb:"Click",target:im(n),targetIsTag:!0}:{verb:"Click",target:n,targetIsTag:!1}:{verb:"Click",target:"",targetIsTag:!1};case"InputText":return{verb:"Type",target:n,targetIsTag:!1};case"Swipe":return{verb:"Swipe",target:n,targetIsTag:!0};case"PressKey":return{verb:"Press",target:n,targetIsTag:!0};case"Wait":return{verb:"Wait",target:n,targetIsTag:!0};default:return{verb:t,target:n,targetIsTag:!1}}}function sm(e){const t=Math.max(0,Math.floor(e)),n=Math.floor(t/1e3),r=Math.floor(n/60),l=n%60,i=t%1e3,o=u=>String(u).padStart(2,"0"),s=u=>String(u).padStart(3,"0");return`${o(r)}:${o(l)}.${s(i)}`}function um(e,t){return e?t?p.jsx("span",{className:"action-list-target action-list-target-tag",children:`<${e}/>`}):p.jsx("span",{className:"action-list-target",children:e}):null}function am(e){const t=e.action;return t&&typeof t.text=="string"?t.text:""}function cm(e){const t=e.action;return t?t.tap_point?`${t.tap_point.x.toFixed(1)}, ${t.tap_point.y.toFixed(1)}`:typeof t.x=="number"&&typeof t.y=="number"?`${t.x.toFixed(1)}, ${t.y.toFixed(1)}`:typeof t.from_x=="number"&&typeof t.from_y=="number"?`${t.from_x.toFixed(1)}, ${t.from_y.toFixed(1)}`:null:null}function fm({steps:e,selectedIndex:t,onSelect:n,runStartMillis:r,selectedStep:l}){const i=S.useRef(new Map),o=r??(e[0]?new Date(e[0].timestamp).getTime():0);S.useEffect(()=>{const a=i.current.get(t);a&&typeof a.scrollIntoView=="function"&&a.scrollIntoView({block:"nearest"})},[t]);const s=a=>{const h=i.current.get(a);h&&typeof h.focus=="function"&&h.focus()},u=(a,h)=>{var d,y;const c=e.findIndex(g=>g.index===h);switch(a.key){case"Enter":case" ":a.preventDefault(),n(h);return;case"ArrowDown":{if(c<0||c>=e.length-1)return;a.preventDefault();const g=e[c+1].index;n(g),s(g);return}case"ArrowUp":{if(c<=0)return;a.preventDefault();const g=e[c-1].index;n(g),s(g);return}case"Home":{a.preventDefault();const g=(d=e[0])==null?void 0:d.index;g!==void 0&&(n(g),s(g));return}case"End":{a.preventDefault();const g=(y=e[e.length-1])==null?void 0:y.index;g!==void 0&&(n(g),s(g));return}}};return p.jsx("ol",{className:"action-list",role:"listbox","aria-label":"Steps",children:e.map(a=>{const h=a.index===t,{verb:c,target:d,targetIsTag:y}=om(a),g=new Date(a.timestamp).getTime()-o,w=sm(g),N=d?y?`<${d}/>`:d:"",m=N?`Step ${a.index} ${c} ${N}`:`Step ${a.index} ${c}`,f=h&&l&&l.step===a.index,v=f?cm(l):null,x=f?am(l):"";return p.jsxs("li",{ref:E=>{E?i.current.set(a.index,E):i.current.delete(a.index)},className:"action-list-item",role:"option",tabIndex:h?0:-1,"aria-selected":h,"aria-label":m,"data-active":h?"true":"false","data-violations":a.has_violations?"true":"false","data-exceptions":a.has_exceptions?"true":"false",onClick:()=>n(a.index),onKeyDown:E=>u(E,a.index),title:d||void 0,children:[p.jsxs("div",{className:"action-list-row",children:[p.jsxs("span",{className:"action-list-index",children:[a.index,"."]}),p.jsxs("span",{className:"action-list-body",children:[p.jsx("span",{className:"action-list-verb",children:c}),um(d,y)]}),p.jsxs("span",{className:"action-list-markers",children:[a.has_exceptions?p.jsx("span",{className:"action-list-marker-exception","aria-label":"exceptions",role:"img"}):null,a.has_violations?p.jsx("span",{className:"action-list-marker-violation","aria-label":"violations",role:"img"}):null]}),p.jsx("span",{className:"action-list-elapsed",children:w})]}),f?p.jsxs("div",{className:"action-list-details",children:[p.jsxs("div",{className:"action-list-detail-row",children:[p.jsx("span",{className:"action-list-detail-label",children:"Position"}),p.jsx("span",{className:"action-list-detail-value",children:v??""})]}),p.jsxs("div",{className:"action-list-detail-row",children:[p.jsx("span",{className:"action-list-detail-label",children:"Content"}),p.jsx("span",{className:"action-list-detail-value",children:x||'""'})]})]}):null]},a.index)})})}const dm=1080,pm=1920;function Tu({src:e,action:t,deviceWidth:n,deviceHeight:r}){const[l,i]=S.useState(null),[o,s]=S.useState(!1),u=S.useRef(e),h=`screenshot-spotlight-${S.useId().replace(/:/g,"")}`;if(S.useEffect(()=>{u.current!==e&&(u.current=e,s(!1),i(null))},[e]),!e||o)return p.jsx("div",{className:"screenshot-placeholder","data-testid":"screenshot-placeholder",children:"no screenshot"});const c=n??(l==null?void 0:l.width)??dm,d=r??(l==null?void 0:l.height)??pm,y=Math.max(2,c/200),g=Math.max(12,c/60),w=Math.max(18,c/40),N=g*3,m=t==null?void 0:t.resolved_bounds,f=t==null?void 0:t.tap_point,v=(t==null?void 0:t.kind)==="Swipe"&&t.from_x!==void 0&&t.from_y!==void 0&&t.to_x!==void 0&&t.to_y!==void 0;return p.jsxs("div",{className:"screenshot-frame",style:{aspectRatio:`${c} / ${d}`},children:[p.jsx("img",{className:"screenshot-image",src:e,alt:"device screenshot",onLoad:x=>{const E=x.currentTarget;E.naturalWidth>0&&E.naturalHeight>0&&i({width:E.naturalWidth,height:E.naturalHeight})},onError:()=>s(!0)}),p.jsxs("svg",{className:"screenshot-overlay",viewBox:`0 0 ${c} ${d}`,preserveAspectRatio:"xMidYMid meet","aria-hidden":"true",children:[f&&p.jsxs(p.Fragment,{children:[p.jsxs("defs",{children:[p.jsxs("radialGradient",{id:`${h}-gradient`,cx:f.x,cy:f.y,r:N,gradientUnits:"userSpaceOnUse",children:[p.jsx("stop",{offset:"0%",stopColor:"black"}),p.jsx("stop",{offset:"55%",stopColor:"black"}),p.jsx("stop",{offset:"100%",stopColor:"white"})]}),p.jsx("mask",{id:h,maskUnits:"userSpaceOnUse",x:"0",y:"0",width:c,height:d,children:p.jsx("rect",{x:"0",y:"0",width:c,height:d,fill:`url(#${h}-gradient)`})})]}),p.jsx("rect",{"data-testid":"screenshot-spotlight",x:"0",y:"0",width:c,height:d,fill:"black",opacity:"0.5",mask:`url(#${h})`})]}),m&&p.jsx("rect",{x:m.x,y:m.y,width:m.width,height:m.height,fill:"none",stroke:"var(--accent-violation)",strokeWidth:y}),v&&p.jsx(hm,{fromX:t.from_x,fromY:t.from_y,toX:t.to_x,toY:t.to_y,stroke:y,headSize:w})]})]})}function hm({fromX:e,fromY:t,toX:n,toY:r,stroke:l,headSize:i}){const o=Math.atan2(r-t,n-e)*180/Math.PI,s=i/2,u=`${n},${r} ${n-i},${r-s} ${n-i},${r+s}`;return p.jsxs("g",{children:[p.jsx("line",{x1:e,y1:t,x2:n,y2:r,stroke:"var(--text-muted)",strokeWidth:l,strokeLinecap:"round"}),p.jsx("polygon",{points:u,fill:"var(--text-muted)",transform:`rotate(${o} ${n} ${r})`})]})}const mm=2;function pf(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)&&Object.getPrototypeOf(e)===Object.prototype}function Lu(e){const t=[],n=(r,l)=>{if(pf(r)){const i=Object.keys(r).sort();if(i.length===0){t.push({path:l,value:{}});return}for(const o of i){const s=l===""?o:`${l}.${o}`;n(r[o],s)}return}if(Array.isArray(r)){if(r.length<=mm){t.push({path:l,value:r});return}for(let i=0;ir.pathl.path?1:0)}function vm(e,t){if(!e)return;if(Object.prototype.hasOwnProperty.call(e,t))return e[t];const n=t.split(/\.|\[(\d+)\]/).filter(l=>l!==void 0&&l!=="");let r=e;for(const l of n){if(r==null)return;if(Array.isArray(r)){const i=Number(l);if(Number.isNaN(i))return;r=r[i];continue}if(typeof r=="object"){r=r[l];continue}return}return r}function oo(e){if(Array.isArray(e))return e.map(oo);if(pf(e)){const t={};for(const n of Object.keys(e).sort())t[n]=oo(e[n]);return t}return e}function so(e){return JSON.stringify(oo(e))}function Ru(e){return e===null?"null":e===void 0?"undefined":typeof e=="string"?JSON.stringify(e):typeof e=="number"||typeof e=="boolean"?String(e):so(e)}function zu({snapshots:e,previousSnapshots:t}){if(!e||Object.keys(e).length===0)return p.jsx("div",{className:"status-block",children:"no snapshots"});const n=Lu(e),r=t!==void 0,l=r?Lu(t):[],i=new Map(l.map(o=>[o.path,o.value]));return p.jsx("dl",{className:"snapshot-table",children:n.map(o=>{const s=Ru(o.value);let u=!1,a;if(r){const c=i.has(o.path)?i.get(o.path):vm(t,o.path);so(c)!==so(o.value)&&(u=!0,a=Ru(c))}const h={};return u&&(h["data-changed"]="true",h.title=`was: ${a}`),p.jsxs("div",{className:"snapshot-row",...h,children:[p.jsx("dt",{className:"snapshot-path",title:o.path,children:o.path}),p.jsx("dd",{className:"snapshot-value",title:s,children:s})]},o.path)})})}function At({children:e}){return p.jsx("span",{className:"op-label",children:e})}function Vt({node:e}){return p.jsxs("span",{className:"residual-group",children:["(",p.jsx(hf,{node:e}),")"]})}function hf({node:e}){switch(e.op){case"true":return p.jsx("span",{className:"residual-leaf",children:"true"});case"false":return p.jsx("span",{className:"residual-leaf",children:"false"});case"predicate":return p.jsxs("span",{className:"residual-leaf",children:[p.jsx(At,{children:"pred"}),e.name?p.jsxs(p.Fragment,{children:["(",e.name,")"]}):null]});case"error":return p.jsxs("span",{className:"residual-error",role:"status",children:[p.jsx(At,{children:"error"}),p.jsx("span",{className:"residual-error-message",children:e.message})]});case"always":case"now":case"next":case"not":return p.jsxs("span",{className:"residual-unary",children:[p.jsx(At,{children:e.op}),p.jsx(Vt,{node:e.arg})]});case"eventually":return p.jsxs("span",{className:"residual-unary",children:[p.jsx(At,{children:"eventually"}),e.within?p.jsxs("span",{className:"residual-bound",children:["within ",e.within.amount," ",e.within.unit]}):null,p.jsx(Vt,{node:e.arg})]});case"and":case"or":return p.jsxs("span",{className:"residual-binary",children:[p.jsx(Vt,{node:e.left}),p.jsx(At,{children:e.op}),p.jsx(Vt,{node:e.right})]});case"implies":return p.jsxs("span",{className:"residual-binary",children:[p.jsx(Vt,{node:e.left}),p.jsx(At,{children:"=>"}),p.jsx(Vt,{node:e.right})]})}}function gm({node:e}){return p.jsx("span",{className:"residual",children:p.jsx(hf,{node:e})})}const Iu={violated:0,pending:1,holds:2};function ym(e,t,n){if(t.has(e))return"violated";const r=n==null?void 0:n[e];return r&&r.op==="true"?"holds":"pending"}function Ir({propertyNames:e,violations:t,residuals:n,onJumpToFirstViolation:r,hasFirstViolation:l,violationsOnly:i=!1}){const o=S.useMemo(()=>new Set(t),[t]),s=S.useMemo(()=>{const a=[...e].sort((c,d)=>c.localeCompare(d)).map(c=>({name:c,status:ym(c,o,n)}));return(i?a.filter(c=>c.status==="violated"):a).sort((c,d)=>{const y=Iu[c.status]-Iu[d.status];return y!==0?y:c.name.localeCompare(d.name)})},[e,o,n,i]);return i&&s.length===0?p.jsx("div",{className:"status-block",children:"no violations"}):p.jsxs("section",{className:"violations-panel",children:[i?null:p.jsxs("header",{className:"violations-panel-header",children:[p.jsx("h2",{className:"violations-panel-title",children:"properties"}),p.jsx("button",{type:"button",className:"violations-panel-jump",onClick:r,disabled:!l,children:"jump to first violation"})]}),p.jsx("ul",{className:"violations-panel-list",children:s.map(({name:u,status:a})=>{const h=n==null?void 0:n[u];return p.jsxs("li",{className:"violations-panel-row","data-status":a,children:[p.jsxs("div",{className:"violations-panel-row-head",children:[p.jsx("span",{className:"violations-panel-badge","data-status":a,"aria-label":`status ${a}`,children:a}),p.jsx("span",{className:"violations-panel-name",children:u})]}),h?p.jsxs("details",{className:"violations-panel-residual",children:[p.jsx("summary",{children:"residual"}),p.jsx(gm,{node:h})]}):null]},u)})})]})}function xm(e){const t=new Date(e),n=String(t.getHours()).padStart(2,"0"),r=String(t.getMinutes()).padStart(2,"0"),l=String(t.getSeconds()).padStart(2,"0"),i=String(t.getMilliseconds()).padStart(3,"0");return`${n}:${r}:${l}.${i}`}function wm({exceptions:e,onJumpToFirstException:t,hasFirstException:n}){return p.jsxs("div",{className:"exceptions-panel",children:[p.jsx("div",{className:"exceptions-panel-toolbar",children:p.jsx("button",{type:"button",className:"exceptions-panel-jump",onClick:t,disabled:!n,children:"jump to first exception"})}),!e||e.length===0?p.jsx("div",{className:"status-block",children:"no exceptions"}):p.jsx("ol",{className:"exceptions-list",children:e.map((r,l)=>p.jsx("li",{className:"exceptions-row",children:p.jsxs("details",{open:l===0,children:[p.jsxs("summary",{className:"exceptions-summary",children:[p.jsx("span",{className:"exceptions-marker","aria-hidden":"true"}),p.jsx("span",{className:"exceptions-class",children:r.class}),r.message?p.jsxs(p.Fragment,{children:[p.jsx("span",{className:"exceptions-colon",children:":"}),p.jsx("span",{className:"exceptions-message",children:r.message})]}):null,r.unix_millis!==void 0?p.jsx("span",{className:"exceptions-time",children:xm(r.unix_millis)}):null]}),r.stack_trace?p.jsx("pre",{className:"exceptions-stack",children:r.stack_trace}):null]})},l))})]})}const Or=1024*1024;function Ou(e){return e<=0?"0B":e{const s=t(i);if(s===void 0){l="M";return}const u=en(o,e.length),h=1-(n===0?0:Math.min(s/n,1));r.push(`${l}${u.toFixed(4)},${h.toFixed(4)}`),l="L"}),r.join(" ")}function Fu({label:e,path:t,dots:n,topTickLabel:r,bottomTickLabel:l,selectedFraction:i,hover:o}){return p.jsxs("div",{className:"metrics-lane",children:[p.jsx("div",{className:"metrics-lane-label",children:e}),p.jsxs("div",{className:"metrics-lane-plot",children:[i!==null?p.jsx("div",{className:"metrics-lane-highlight",style:{left:`${i*100}%`}}):null,p.jsxs("div",{className:"metrics-lane-canvas",children:[p.jsx("svg",{className:"metrics-lane-svg",viewBox:"0 0 1 1",preserveAspectRatio:"none","aria-hidden":"true",children:t?p.jsx("path",{d:t,className:"metrics-lane-path"}):null}),n.map(s=>p.jsx("div",{className:"metrics-lane-dot",style:{left:`${s.x*100}%`,top:`${s.y*100}%`},"data-active":o!==null&&Math.abs(o.fraction-s.x)<1e-6?"true":void 0},s.key)),o?p.jsx("div",{className:"metrics-lane-tooltip","data-placement":o.y<.35?"below":"above",style:{left:`${o.fraction*100}%`,top:`${o.y*100}%`},children:o.label}):null]})]}),p.jsxs("div",{className:"metrics-lane-ticks",children:[p.jsx("span",{children:r}),p.jsx("span",{children:l})]})]})}function Du(e,t,n){const r=[];return e.forEach((l,i)=>{const o=t(l);if(o===void 0)return;const s=n===0?0:Math.min(o/n,1);r.push({key:l.stepIndex,x:en(i,e.length),y:1-s})}),r}function km({samples:e,selectedIndex:t,onSelect:n,runStartMillis:r}){var _,P;const[l,i]=S.useState(null);if(e.length===0||!e.some(C=>C.metrics!==void 0))return p.jsx("div",{className:"status-block",children:"no metrics"});const o=e.reduce((C,R)=>{var L;return Math.max(C,((L=R.metrics)==null?void 0:L.heap_bytes)??0)},0),s=e.reduce((C,R)=>{var L;return Math.max(C,((L=R.metrics)==null?void 0:L.cpu_percent)??0)},0),u=Math.max(100,s),a=Mu(e,C=>{var R;return(R=C.metrics)==null?void 0:R.heap_bytes},o),h=Mu(e,C=>{var R;return(R=C.metrics)==null?void 0:R.cpu_percent},u),c=Du(e,C=>{var R;return(R=C.metrics)==null?void 0:R.heap_bytes},o),d=Du(e,C=>{var R;return(R=C.metrics)==null?void 0:R.cpu_percent},u),y=r??new Date(e[0].timestamp).getTime(),g=Math.min(5,e.length),w=Array.from({length:g},(C,R)=>{const L=g===1?0:Math.round(R/(g-1)*(e.length-1)),X=e[L],Q=new Date(X.timestamp).getTime(),b=Number.isFinite(Q)&&Number.isFinite(y)?Q-y:NaN;return{key:X.stepIndex,fraction:en(L,e.length),label:Number.isFinite(b)?Sm(b):String(X.stepIndex)}}),N=e.findIndex(C=>C.stepIndex===t),m=N>=0?en(N,e.length):null,f=l!==null&&l>=0&&l{const L=(()=>{if(e.length===1)return 0;const Q=.5/(e.length-1);return Math.max(0,en(R,e.length)-Q)})(),X=e.length===1?1:1/(e.length-1);return p.jsx("button",{type:"button",className:"metrics-hit",style:{left:`${L*100}%`,width:`${X*100}%`},onClick:()=>n(C.stepIndex),onPointerEnter:()=>i(R),onPointerLeave:()=>i(Q=>Q===R?null:Q),"aria-label":`select step ${C.stepIndex}`},C.stepIndex)})})]}),p.jsx("div",{className:"metrics-axis",children:w.map(C=>p.jsx("span",{className:"metrics-axis-label",style:{left:`${C.fraction*100}%`},children:C.label},C.key))})]})}function $u({tabs:e,defaultTabId:t,ariaLabel:n}){var c;const r=t&&e.some(d=>d.id===t)?t:(c=e[0])==null?void 0:c.id,[l,i]=S.useState(r),o=S.useRef(new Map);if(e.length===0)return null;const s=e.find(d=>d.id===l)??e[0],u=d=>{i(d);const y=o.current.get(d);y&&y.focus()},a=d=>{const y=e.findIndex(g=>g.id===s.id);if(!(y<0))switch(d.key){case"ArrowRight":case"ArrowDown":{d.preventDefault();const g=e[(y+1)%e.length];u(g.id);return}case"ArrowLeft":case"ArrowUp":{d.preventDefault();const g=e[(y-1+e.length)%e.length];u(g.id);return}case"Home":{d.preventDefault(),u(e[0].id);return}case"End":{d.preventDefault(),u(e[e.length-1].id);return}}},h=`${n??"tabs"}-panel`.replace(/\s+/g,"-");return p.jsxs("div",{className:"tabs",children:[p.jsx("div",{className:"tabs-header",role:"tablist","aria-label":n,onKeyDown:a,children:e.map(d=>{const y=d.id===s.id;return p.jsxs("button",{ref:g=>{g?o.current.set(d.id,g):o.current.delete(d.id)},type:"button",role:"tab",id:`${h}-tab-${d.id}`,className:"tabs-tab","data-active":y?"true":"false","aria-selected":y,"aria-controls":h,tabIndex:y?0:-1,onClick:()=>i(d.id),children:[p.jsx("span",{children:d.label}),d.badge!==void 0?p.jsx("span",{className:"tabs-badge",children:d.badge}):null]},d.id)})}),p.jsx("div",{className:"tabs-panel",role:"tabpanel",id:h,"aria-labelledby":`${h}-tab-${s.id}`,children:s.content})]})}function Em(e){const t=us(),{id:n,step:r}=of(),l=n??"",i=Number(r??"1"),o=Number.isFinite(i)&&i>0?i:1,s=Uu(o,e);return S.useEffect(()=>{s!==o&&l!==""&&t(`/runs/${l}/steps/${s}`,{replace:!0})},[s,o,l,t]),{runId:l,stepIndex:s,goTo:a=>{const h=Uu(a,e);h!==o&&l!==""&&t(`/runs/${l}/steps/${h}`)}}}function Uu(e,t){return e<1?1:t!==void 0&&e>t?t:e}const Cm=new Set(["INPUT","TEXTAREA","SELECT"]),Nm=new Set(["tab","tablist","option","listbox","menuitem","menu"]);function jm(e){var n;let t=e;for(;t;){const r=(n=t.getAttribute)==null?void 0:n.call(t,"role");if(r&&Nm.has(r))return!0;t=t.parentElement}return!1}function _m(e){S.useEffect(()=>{const t=n=>{const r=n.target;if(!(r&&(Cm.has(r.tagName)||r.isContentEditable)||n.key.startsWith("Arrow")&&jm(r))&&!(n.metaKey||n.ctrlKey||n.altKey))switch(n.key){case"ArrowLeft":case"k":n.shiftKey?e.onJumpPrev10():e.onPrev(),n.preventDefault();return;case"ArrowRight":case"j":n.shiftKey?e.onJumpNext10():e.onNext(),n.preventDefault();return;case"g":e.onJumpStart(),n.preventDefault();return;case"G":e.onJumpEnd(),n.preventDefault();return;case".":e.onJumpNextViolation(),n.preventDefault();return}};return window.addEventListener("keydown",t),()=>window.removeEventListener("keydown",t)},[e])}const mf="sanderling-inspect-theme";function Pm(){if(typeof window>"u")return"light";const e=window.localStorage.getItem(mf);return e==="light"||e==="dark"?e:window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function Tm(){const[e,t]=S.useState(()=>Pm());return S.useEffect(()=>{if(!(typeof document>"u")){document.documentElement.dataset.theme=e;try{window.localStorage.setItem(mf,e)}catch{}}},[e]),{theme:e,toggle:()=>t(n=>n==="dark"?"light":"dark")}}function Lm(){const[e,t]=S.useState(null),[n,r]=S.useState(null),[l,i]=S.useState(null),{theme:o,toggle:s}=Tm(),u=e==null?void 0:e.steps.length,{runId:a,stepIndex:h,goTo:c}=Em(u);S.useEffect(()=>{if(!a)return;let Q=!1;return t(null),r(null),i(null),qh(a).then(async b=>{if(Q)return;t(b);const pr=await Rm(b);Q||r(pr)}).catch(b=>{Q||i(b instanceof Error?b.message:String(b))}),()=>{Q=!0}},[a]);const d=(n==null?void 0:n.steps[h-1])??null,y=h>1?(n==null?void 0:n.steps[h-2])??null:null,g=n&&h{n!=null&&n.firstViolationStep&&c(n.firstViolationStep)},[n,c]),N=S.useCallback(()=>{n!=null&&n.firstExceptionStep&&c(n.firstExceptionStep)},[n,c]),m=S.useCallback(()=>{if(!e)return;const Q=e.steps.find(b=>b.index>h&&b.has_violations);Q&&c(Q.index)},[e,h,c]);_m({onPrev:()=>c(h-1),onNext:()=>c(h+1),onJumpStart:()=>c(1),onJumpEnd:()=>u&&c(u),onJumpPrev10:()=>c(h-10),onJumpNext10:()=>c(h+10),onJumpNextViolation:m});const f=S.useMemo(()=>{if(!(!a||!d))return Pu(a,`step-${String(d.step).padStart(5,"0")}.png`)},[a,d]),v=S.useMemo(()=>{if(!(!a||!d))return Pu(a,`step-${String(d.step).padStart(5,"0")}-after.png`)},[a,d]),x=S.useMemo(()=>e!=null&&e.steps.length?new Date(e.steps[0].timestamp).getTime():0,[e]);if(l)return p.jsxs("div",{className:"status-block status-error",children:["failed: ",l]});if(!e)return p.jsx("div",{className:"status-block",children:"loading run..."});const E=(d==null?void 0:d.violations)??[],_=(g==null?void 0:g.violations)??E,P=d==null?void 0:d.residuals,C=(g==null?void 0:g.residuals)??P,R=d==null?void 0:d.exceptions,L=[{id:"screenshot",label:"Screenshot",content:p.jsx(Tu,{src:f,action:d==null?void 0:d.action})},{id:"snapshots",label:"Snapshots",content:p.jsx(zu,{snapshots:d==null?void 0:d.snapshots,previousSnapshots:(y==null?void 0:y.snapshots)??void 0})},{id:"properties",label:"Properties",content:p.jsx(Ir,{propertyNames:(n==null?void 0:n.names)??[],violations:E,residuals:P,onJumpToFirstViolation:w,hasFirstViolation:(n==null?void 0:n.firstViolationStep)!==void 0})},{id:"violations",label:"Violations",badge:E.length>0?p.jsx("span",{className:"tabs-badge","data-kind":"violation",children:E.length}):void 0,content:p.jsx(Ir,{propertyNames:(n==null?void 0:n.names)??[],violations:E,residuals:P,onJumpToFirstViolation:w,hasFirstViolation:(n==null?void 0:n.firstViolationStep)!==void 0,violationsOnly:!0})}],X=[{id:"screenshot",label:"Screenshot",content:p.jsx(Tu,{src:v,action:void 0})},{id:"snapshots",label:"Snapshots",content:p.jsx(zu,{snapshots:(g==null?void 0:g.snapshots)??(d==null?void 0:d.snapshots),previousSnapshots:(d==null?void 0:d.snapshots)??void 0})},{id:"properties",label:"Properties",content:p.jsx(Ir,{propertyNames:(n==null?void 0:n.names)??[],violations:_,residuals:C,onJumpToFirstViolation:w,hasFirstViolation:(n==null?void 0:n.firstViolationStep)!==void 0})},{id:"violations",label:"Violations",badge:_.length>0?p.jsx("span",{className:"tabs-badge","data-kind":"violation",children:_.length}):void 0,content:p.jsx(Ir,{propertyNames:(n==null?void 0:n.names)??[],violations:_,residuals:C,onJumpToFirstViolation:w,hasFirstViolation:(n==null?void 0:n.firstViolationStep)!==void 0,violationsOnly:!0})}];return p.jsxs("div",{className:"detail-root",children:[p.jsxs("div",{className:"detail-toolbar",children:[p.jsxs("div",{className:"detail-toolbar-meta",children:[p.jsx(ff,{to:"/",children:"runs"}),p.jsx("span",{children:e.id}),p.jsxs("span",{children:[p.jsx("strong",{children:e.spec_path})," seed=",e.seed]}),p.jsxs("span",{children:["step ",h," / ",u??0]})]}),p.jsx("button",{type:"button",className:"theme-toggle",onClick:s,"aria-label":o==="dark"?"switch to light theme":"switch to dark theme",title:o==="dark"?"switch to light theme":"switch to dark theme",children:o==="dark"?p.jsxs("svg",{viewBox:"0 0 16 16",width:"14",height:"14","aria-hidden":"true",focusable:"false",children:[p.jsx("circle",{cx:"8",cy:"8",r:"3",fill:"none",stroke:"currentColor",strokeWidth:"1.25"}),p.jsxs("g",{stroke:"currentColor",strokeWidth:"1.25",strokeLinecap:"round",children:[p.jsx("line",{x1:"8",y1:"1.5",x2:"8",y2:"3.5"}),p.jsx("line",{x1:"8",y1:"12.5",x2:"8",y2:"14.5"}),p.jsx("line",{x1:"1.5",y1:"8",x2:"3.5",y2:"8"}),p.jsx("line",{x1:"12.5",y1:"8",x2:"14.5",y2:"8"}),p.jsx("line",{x1:"3.4",y1:"3.4",x2:"4.8",y2:"4.8"}),p.jsx("line",{x1:"11.2",y1:"11.2",x2:"12.6",y2:"12.6"}),p.jsx("line",{x1:"3.4",y1:"12.6",x2:"4.8",y2:"11.2"}),p.jsx("line",{x1:"11.2",y1:"4.8",x2:"12.6",y2:"3.4"})]})]}):p.jsx("svg",{viewBox:"0 0 16 16",width:"14",height:"14","aria-hidden":"true",focusable:"false",children:p.jsx("path",{d:"M13.2 9.8A5.2 5.2 0 0 1 6.2 2.8a5.2 5.2 0 1 0 7 7Z",fill:"none",stroke:"currentColor",strokeWidth:"1.25",strokeLinejoin:"round"})})})]}),p.jsxs("div",{className:"detail-grid",children:[p.jsxs("aside",{className:"detail-actions detail-panel",children:[p.jsx("h2",{children:"actions"}),p.jsx("div",{className:"detail-panel-body",children:p.jsx(fm,{steps:e.steps,selectedIndex:h,onSelect:c,runStartMillis:x,selectedStep:d??void 0})})]}),p.jsxs("section",{className:"detail-state-before detail-panel",children:[p.jsx("h2",{children:"state before"}),p.jsx("div",{className:"detail-panel-body",children:p.jsx($u,{tabs:L,defaultTabId:"screenshot",ariaLabel:"state before"})})]}),p.jsxs("section",{className:"detail-state-after detail-panel",children:[p.jsx("h2",{children:"state after"}),p.jsx("div",{className:"detail-panel-body",children:p.jsx($u,{tabs:X,defaultTabId:"screenshot",ariaLabel:"state after"})})]}),p.jsx("section",{className:"detail-metrics detail-panel",children:p.jsxs("div",{className:"detail-panel-body",children:[p.jsx(km,{samples:(n==null?void 0:n.metricsSamples)??[],selectedIndex:h,onSelect:c,runStartMillis:x}),R&&R.length>0||(n==null?void 0:n.firstExceptionStep)!==void 0?p.jsx("div",{className:"detail-metrics-exceptions",children:p.jsx(wm,{exceptions:R,onJumpToFirstException:N,hasFirstException:(n==null?void 0:n.firstExceptionStep)!==void 0})}):null]})})]})]})}async function Rm(e){var a,h;const t=await Promise.all(e.steps.map(c=>bh(e.id,c.index).catch(()=>null))),n=zm(t),r=n.map(c=>({name:c,statuses:t.map(d=>Im(c,d))})),l=(a=e.steps.find(c=>c.has_violations))==null?void 0:a.index,i=(h=e.steps.find(c=>c.has_exceptions))==null?void 0:h.index,o=e.steps.filter(c=>c.has_exceptions).map(c=>c.index),s=e.steps.filter(c=>c.has_violations).map(c=>c.index),u=e.steps.map((c,d)=>{var y;return{stepIndex:c.index,timestamp:c.timestamp,metrics:(y=t[d])==null?void 0:y.metrics}});return{names:n,lanes:Om(r),firstViolationStep:l,firstExceptionStep:i,exceptionStepIndices:o,violationStepIndices:s,metricsSamples:u,steps:t}}function zm(e){const t=new Set;for(const n of e)if(n!=null&&n.residuals)for(const r of Object.keys(n.residuals))t.add(r);return[...t].sort()}function Im(e,t){var r,l;if(!t)return"pending";if((r=t.violations)!=null&&r.includes(e))return"violated";const n=(l=t.residuals)==null?void 0:l[e];return n&&n.op==="true"?"holds":"pending"}function Om(e){const t=n=>{const r=n.statuses[n.statuses.length-1];return n.statuses.includes("violated")?0:r==="pending"?1:2};return[...e].sort((n,r)=>{const l=t(n)-t(r);return l!==0?l:n.name.localeCompare(r.name)})}function Mm(){const{id:e}=of();return e?p.jsx($h,{to:`/runs/${e}/steps/1`,replace:!0}):p.jsx(vf,{})}function vf(){return p.jsx("div",{className:"status-block",children:"not found"})}function Fm(){return p.jsx(Gh,{children:p.jsx("div",{className:"app-shell",children:p.jsx("main",{className:"app-main",children:p.jsxs(Ah,{children:[p.jsx(zn,{path:"/",element:p.jsx(rm,{})}),p.jsx(zn,{path:"/runs/:id",element:p.jsx(Mm,{})}),p.jsx(zn,{path:"/runs/:id/steps/:step",element:p.jsx(Lm,{})}),p.jsx(zn,{path:"*",element:p.jsx(vf,{})})]})})})})}const gf=document.getElementById("root");if(!gf)throw new Error("missing #root element");bc(gf).render(p.jsx(Xu.StrictMode,{children:p.jsx(Fm,{})})); diff --git a/web/public/fonts/.gitkeep b/inspect-ui/dist/fonts/.gitkeep similarity index 100% rename from web/public/fonts/.gitkeep rename to inspect-ui/dist/fonts/.gitkeep diff --git a/inspect-ui/dist/index.html b/inspect-ui/dist/index.html new file mode 100644 index 0000000..8424fca --- /dev/null +++ b/inspect-ui/dist/index.html @@ -0,0 +1,13 @@ + + + + + + sanderling inspect + + + + +
+ + diff --git a/web/index.html b/inspect-ui/index.html similarity index 100% rename from web/index.html rename to inspect-ui/index.html diff --git a/web/package.json b/inspect-ui/package.json similarity index 100% rename from web/package.json rename to inspect-ui/package.json diff --git a/inspect-ui/public/fonts/.gitkeep b/inspect-ui/public/fonts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/web/src/App.tsx b/inspect-ui/src/App.tsx similarity index 100% rename from web/src/App.tsx rename to inspect-ui/src/App.tsx diff --git a/web/src/api.ts b/inspect-ui/src/api.ts similarity index 100% rename from web/src/api.ts rename to inspect-ui/src/api.ts diff --git a/web/src/components/ResidualNode.css b/inspect-ui/src/components/ResidualNode.css similarity index 100% rename from web/src/components/ResidualNode.css rename to inspect-ui/src/components/ResidualNode.css diff --git a/web/src/components/ResidualNode.tsx b/inspect-ui/src/components/ResidualNode.tsx similarity index 100% rename from web/src/components/ResidualNode.tsx rename to inspect-ui/src/components/ResidualNode.tsx diff --git a/web/src/components/Tabs.css b/inspect-ui/src/components/Tabs.css similarity index 100% rename from web/src/components/Tabs.css rename to inspect-ui/src/components/Tabs.css diff --git a/web/src/components/Tabs.tsx b/inspect-ui/src/components/Tabs.tsx similarity index 100% rename from web/src/components/Tabs.tsx rename to inspect-ui/src/components/Tabs.tsx diff --git a/web/src/hooks/useKeyboardNav.ts b/inspect-ui/src/hooks/useKeyboardNav.ts similarity index 100% rename from web/src/hooks/useKeyboardNav.ts rename to inspect-ui/src/hooks/useKeyboardNav.ts diff --git a/web/src/hooks/useSse.ts b/inspect-ui/src/hooks/useSse.ts similarity index 100% rename from web/src/hooks/useSse.ts rename to inspect-ui/src/hooks/useSse.ts diff --git a/web/src/hooks/useStep.ts b/inspect-ui/src/hooks/useStep.ts similarity index 100% rename from web/src/hooks/useStep.ts rename to inspect-ui/src/hooks/useStep.ts diff --git a/web/src/hooks/useTheme.ts b/inspect-ui/src/hooks/useTheme.ts similarity index 100% rename from web/src/hooks/useTheme.ts rename to inspect-ui/src/hooks/useTheme.ts diff --git a/web/src/main.tsx b/inspect-ui/src/main.tsx similarity index 100% rename from web/src/main.tsx rename to inspect-ui/src/main.tsx diff --git a/web/src/panels/ActionList.css b/inspect-ui/src/panels/ActionList.css similarity index 100% rename from web/src/panels/ActionList.css rename to inspect-ui/src/panels/ActionList.css diff --git a/web/src/panels/ActionList.tsx b/inspect-ui/src/panels/ActionList.tsx similarity index 100% rename from web/src/panels/ActionList.tsx rename to inspect-ui/src/panels/ActionList.tsx diff --git a/web/src/panels/ExceptionsPanel.css b/inspect-ui/src/panels/ExceptionsPanel.css similarity index 100% rename from web/src/panels/ExceptionsPanel.css rename to inspect-ui/src/panels/ExceptionsPanel.css diff --git a/web/src/panels/ExceptionsPanel.tsx b/inspect-ui/src/panels/ExceptionsPanel.tsx similarity index 100% rename from web/src/panels/ExceptionsPanel.tsx rename to inspect-ui/src/panels/ExceptionsPanel.tsx diff --git a/web/src/panels/MetricsChart.css b/inspect-ui/src/panels/MetricsChart.css similarity index 100% rename from web/src/panels/MetricsChart.css rename to inspect-ui/src/panels/MetricsChart.css diff --git a/web/src/panels/MetricsChart.tsx b/inspect-ui/src/panels/MetricsChart.tsx similarity index 100% rename from web/src/panels/MetricsChart.tsx rename to inspect-ui/src/panels/MetricsChart.tsx diff --git a/web/src/panels/Screenshot.css b/inspect-ui/src/panels/Screenshot.css similarity index 100% rename from web/src/panels/Screenshot.css rename to inspect-ui/src/panels/Screenshot.css diff --git a/web/src/panels/Screenshot.tsx b/inspect-ui/src/panels/Screenshot.tsx similarity index 100% rename from web/src/panels/Screenshot.tsx rename to inspect-ui/src/panels/Screenshot.tsx diff --git a/web/src/panels/SnapshotTable.css b/inspect-ui/src/panels/SnapshotTable.css similarity index 100% rename from web/src/panels/SnapshotTable.css rename to inspect-ui/src/panels/SnapshotTable.css diff --git a/web/src/panels/SnapshotTable.tsx b/inspect-ui/src/panels/SnapshotTable.tsx similarity index 100% rename from web/src/panels/SnapshotTable.tsx rename to inspect-ui/src/panels/SnapshotTable.tsx diff --git a/web/src/panels/Timeline.css b/inspect-ui/src/panels/Timeline.css similarity index 100% rename from web/src/panels/Timeline.css rename to inspect-ui/src/panels/Timeline.css diff --git a/web/src/panels/Timeline.tsx b/inspect-ui/src/panels/Timeline.tsx similarity index 100% rename from web/src/panels/Timeline.tsx rename to inspect-ui/src/panels/Timeline.tsx diff --git a/web/src/panels/ViolationsPanel.css b/inspect-ui/src/panels/ViolationsPanel.css similarity index 100% rename from web/src/panels/ViolationsPanel.css rename to inspect-ui/src/panels/ViolationsPanel.css diff --git a/web/src/panels/ViolationsPanel.tsx b/inspect-ui/src/panels/ViolationsPanel.tsx similarity index 100% rename from web/src/panels/ViolationsPanel.tsx rename to inspect-ui/src/panels/ViolationsPanel.tsx diff --git a/web/src/routes/RunDetail.tsx b/inspect-ui/src/routes/RunDetail.tsx similarity index 100% rename from web/src/routes/RunDetail.tsx rename to inspect-ui/src/routes/RunDetail.tsx diff --git a/web/src/routes/RunList.tsx b/inspect-ui/src/routes/RunList.tsx similarity index 100% rename from web/src/routes/RunList.tsx rename to inspect-ui/src/routes/RunList.tsx diff --git a/web/src/styles/app.css b/inspect-ui/src/styles/app.css similarity index 100% rename from web/src/styles/app.css rename to inspect-ui/src/styles/app.css diff --git a/web/src/styles/tokens.css b/inspect-ui/src/styles/tokens.css similarity index 100% rename from web/src/styles/tokens.css rename to inspect-ui/src/styles/tokens.css diff --git a/web/src/styles/typography.css b/inspect-ui/src/styles/typography.css similarity index 100% rename from web/src/styles/typography.css rename to inspect-ui/src/styles/typography.css diff --git a/web/src/types.ts b/inspect-ui/src/types.ts similarity index 100% rename from web/src/types.ts rename to inspect-ui/src/types.ts diff --git a/web/tsconfig.json b/inspect-ui/tsconfig.json similarity index 100% rename from web/tsconfig.json rename to inspect-ui/tsconfig.json diff --git a/web/vite.config.ts b/inspect-ui/vite.config.ts similarity index 100% rename from web/vite.config.ts rename to inspect-ui/vite.config.ts diff --git a/internal/inspect/assets.go b/internal/inspect/assets.go index 43c35e0..75a28ea 100644 --- a/internal/inspect/assets.go +++ b/internal/inspect/assets.go @@ -10,7 +10,7 @@ var distFS embed.FS // Assets returns the embedded SPA bundle rooted at the dist directory. // In Stage 2 this contains a stub index.html. Stage 4 wires the real -// bundle in via Makefile (copy web/dist -> internal/inspect/dist). +// bundle in via Makefile (copy inspect-ui/dist -> internal/inspect/dist). func Assets() fs.FS { sub, err := fs.Sub(distFS, "dist") if err != nil { diff --git a/sdk/android/src/main/kotlin/dev/sanderling/sdk/Sanderling.kt b/sdk/android/src/main/kotlin/dev/sanderling/sdk/Sanderling.kt index 13189da..849ce4b 100644 --- a/sdk/android/src/main/kotlin/dev/sanderling/sdk/Sanderling.kt +++ b/sdk/android/src/main/kotlin/dev/sanderling/sdk/Sanderling.kt @@ -2,6 +2,15 @@ package dev.sanderling.sdk import android.app.Application import android.util.Log +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty + +internal fun String.camelToSnakeCase(): String = buildString { + for ((i, c) in this@camelToSnakeCase.withIndex()) { + if (c.isUpperCase() && i > 0) append('_') + append(c.lowercaseChar()) + } +} data class Configuration( val socketName: String = "sanderling-agent", @@ -36,6 +45,8 @@ object Sanderling { activeRuntime.register(name, function) } + fun snapshot(function: () -> T): SnapshotDelegate = SnapshotDelegate(function) + /** * Records a caught [Throwable] so it surfaces in the next STATE message's * exceptions field. Useful for coroutine CoroutineExceptionHandler, @@ -52,3 +63,10 @@ object Sanderling { runtime = null } } + +class SnapshotDelegate(private val function: () -> T) { + operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty { + Sanderling.extract(prop.name.camelToSnakeCase(), function as () -> Any?) + return ReadOnlyProperty { _, _ -> function() } + } +} diff --git a/sdk/android/src/test/kotlin/dev/sanderling/sdk/SnapshotDelegateTest.kt b/sdk/android/src/test/kotlin/dev/sanderling/sdk/SnapshotDelegateTest.kt new file mode 100644 index 0000000..d16c762 --- /dev/null +++ b/sdk/android/src/test/kotlin/dev/sanderling/sdk/SnapshotDelegateTest.kt @@ -0,0 +1,95 @@ +package dev.sanderling.sdk + +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Test + +class SnapshotDelegateTest { + + @After fun tearDown() = Sanderling.stopForTest() + + @Test fun camelToSnakeCaseConvertsKnownNames() { + assertEquals("logged_in", "loggedIn".camelToSnakeCase()) + assertEquals("total_balance", "totalBalance".camelToSnakeCase()) + assertEquals("txn_form_type", "txnFormType".camelToSnakeCase()) + assertEquals("active_account_id", "activeAccountId".camelToSnakeCase()) + assertEquals("add_account_error", "addAccountError".camelToSnakeCase()) + assertEquals("ledger_balance", "ledgerBalance".camelToSnakeCase()) + assertEquals("ledger_rows", "ledgerRows".camelToSnakeCase()) + assertEquals("auth_status", "authStatus".camelToSnakeCase()) + assertEquals("login_error", "loginError".camelToSnakeCase()) + assertEquals("txn_error", "txnError".camelToSnakeCase()) + assertEquals("account_count", "accountCount".camelToSnakeCase()) + assertEquals("focused_input", "focusedInput".camelToSnakeCase()) + assertEquals("txn_form_account_id", "txnFormAccountId".camelToSnakeCase()) + } + + @Test fun camelToSnakeCaseLeavesAlreadyLowercase() { + assertEquals("screen", "screen".camelToSnakeCase()) + assertEquals("accounts", "accounts".camelToSnakeCase()) + } + + @Test fun snapshotDelegateRegistersWithDerivedKey() { + val transport = SocketClientTest.FakeTransport() + val frameThread = PauserTest.FakeFrameThread() + val runtime = SanderlingRuntime( + transport = transport, + pauser = Pauser(frameThread, pauseTimeoutMillis = 2_000L), + version = "0.0.1", + platform = "android", + appPackage = "com.example.test", + ) + runtime.start() + // Inject runtime into Sanderling via reflection so snapshot() can register + val runtimeField = Sanderling::class.java.getDeclaredField("runtime") + runtimeField.isAccessible = true + runtimeField.set(Sanderling, runtime) + + var callCount = 0 + val obj = object { + val loggedIn by Sanderling.snapshot { callCount++; true } + } + + val snapshot = runtime.snapshot() + assertEquals(true, snapshot["logged_in"]) + assertEquals(1, callCount) + + // getValue delegates back to lambda + callCount = 0 + val value = obj.loggedIn + assertEquals(true, value) + assertEquals(1, callCount) + + runtime.stop() + frameThread.shutdown() + } + + @Test fun snapshotDelegateGetValueReturnsFreshResult() { + val transport = SocketClientTest.FakeTransport() + val frameThread = PauserTest.FakeFrameThread() + val runtime = SanderlingRuntime( + transport = transport, + pauser = Pauser(frameThread, pauseTimeoutMillis = 2_000L), + version = "0.0.1", + platform = "android", + appPackage = "com.example.test", + ) + runtime.start() + val runtimeField = Sanderling::class.java.getDeclaredField("runtime") + runtimeField.isAccessible = true + runtimeField.set(Sanderling, runtime) + + var counter = 0 + val obj = object { + val accountCount by Sanderling.snapshot { counter } + } + + counter = 5 + assertEquals(5, obj.accountCount) + counter = 10 + assertEquals(10, obj.accountCount) + + runtime.stop() + frameThread.shutdown() + } +}