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
This commit is contained in:
pj authored and GitHub committed 2026-04-22 19:55:45 +07:00
1 parent d5b6f6ccaf
commit 46abb28ed6
51 files changed
+297 -84

No files matched your search

+4 -4
View File
@@ -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
@@ -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
}
}
@@ -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 }
}
@@ -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 }
}
@@ -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<Any>()
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 }
}
@@ -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"
}
}
}
+1 -1
View File
@@ -35,7 +35,7 @@ const loggedIn = extract<boolean>(
(state) => (state.snapshots.logged_in as boolean) ?? false,
);
const route = extract<string>(
(state) => (state.snapshots.route as string) ?? "",
(state) => (state.snapshots.screen as string) ?? "",
);
const accounts = extract<AccountSnapshot[]>(
(state) => (state.snapshots.accounts as AccountSnapshot[]) ?? [],
File renamed without changes.
+1
View File
@@ -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;mLine truncated
+67
View File
@@ -0,0 +1,67 @@
function xf(e,t){for(var n=0;n<t.length;n++){const r=t[n];if(typeof r!="string"&&!Array.isArray(r)){for(const l in r)if(l!=="default"&&!(l in e)){const i=Object.getOwnPropertyDescriptor(r,l);i&&Object.defineProperty(e,l,i.get?i:{enumerable:!0,get:()=>r[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<s){for(var u=Array(s),a=0;a<s;a++)u[a]=arguments[a+2];l.children=u}if(e&&e.defaultProps)for(r in s=e.defaultProps,s)l[r]===void 0&&(l[r]=s[r]);return{$$typeof:sr,type:e,key:i,ref:o,props:l,_owner:co.current}}function zf(e,t){return{$$typeof:sr,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}function fo(e){return typeof e=="object"&&e!==null&&e.$$typeof===sr}function If(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(n){return t[n]})}var ds=/\/+/g;function $l(e,t){return typeof e=="object"&&e!==null&&e.key!=null?If(""+e.key):t.toString(36)}function Mr(e,t,n,r,l){var i=typeof e;(i==="undefined"||i==="boolean")&&(e=null);var o=!1;if(e===null)o=!0;else switch(i){case"string":case"number":o=!0;break;case"object":switch(e.$$typeof){case sr:case Sf:o=!0}}if(o)return o=e,l=l(o),e=r===""?"."+$l(o,0):r,fs(l)?(n="",e!=null&&(n=e.replace(ds,"$&/")+"/"),Mr(l,t,n,"",function(a){return a})):l!=null&&(fo(l)&&(l=zf(l,n+(!l.key||o&&o.key===l.key?"":(""+l.key).replace(ds,"$&/")+"/")+e)),t.push(l)),1;if(o=0,r=r===""?".":r+":",fs(e))for(var s=0;s<e.length;s++){i=e[s];var u=r+$l(i,s);o+=Mr(i,t,n,u,l)}else if(u=Rf(e),typeof u=="function")for(e=u.call(e),s=0;!(i=e.next()).done;)i=i.value,u=r+$l(i,s++),o+=Mr(i,t,n,u,l);else if(i==="object")throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.");return o}function vr(e,t,n){if(e==null)return e;var r=[],l=0;return Mr(e,r,"","",function(i){return t.call(n,i,l++)}),r}function Of(e){if(e._status===-1){var t=e._result;t=t(),t.then(function(n){(e._status===0||e._status===-1)&&(e._status=1,e._result=n)},function(n){(e._status===0||e._status===-1)&&(e._status=2,e._result=n)}),e._status===-1&&(e._status=0,e._result=t)}if(e._status===1)return e._result.default;throw e._result}var de={current:null},Fr={transition:null},Mf={ReactCurrentDispatcher:de,ReactCurrentBatchConfig:Fr,ReactCurrentOwner:co};function Yu(){throw Error("act(...) is not supported in production builds of React.")}O.Children={map:vr,forEach:function(e,t,n){vr(e,function(){t.apply(this,arguments)},n)},count:function(e){var t=0;return vr(e,function(){t++}),t},toArray:function(e){return vr(e,function(t){return t})||[]},only:function(e){if(!fo(e))throw Error("React.Children.only expected to receive a single React element child.");return e}};O.Component=mn;O.Fragment=kf;O.Profiler=Cf;O.PureComponent=uo;O.StrictMode=Ef;O.Suspense=Pf;O.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=Mf;O.act=Yu;O.cloneElement=function(e,t,n){if(e==null)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+e+".");var r=Wu({},e.props),l=e.key,i=e.ref,o=e._owner;if(t!=null){if(t.ref!==void 0&&(i=t.ref,o=co.current),t.key!==void 0&&(l=""+t.key),e.type&&e.type.defaultProps)var s=e.type.defaultProps;for(u in t)Ku.call(t,u)&&!Gu.hasOwnProperty(u)&&(r[u]=t[u]===void 0&&s!==void 0?s[u]:t[u])}var u=arguments.length-2;if(u===1)r.children=n;else if(1<u){s=Array(u);for(var a=0;a<u;a++)s[a]=arguments[a+2];r.children=s}return{$$typeof:sr,type:e.type,key:l,ref:i,props:r,_owner:o}};O.createContext=function(e){return e={$$typeof:jf,_currentValue:e,_currentValue2:e,_threadCount:0,ProviderLine truncated
* @license React
* react-jsx-runtime.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 Df=S,$f=Symbol.for("react.element"),Uf=Symbol.for("react.fragment"),Af=Object.prototype.hasOwnProperty,Vf=Df.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,Bf={key:!0,ref:!0,__self:!0,__source:!0};function Zu(e,t,n){var r,l={},i=null,o=null;n!==void 0&&(i=""+n),t.key!==void 0&&(i=""+t.key),t.ref!==void 0&&(o=t.ref);for(r in t)Af.call(t,r)&&!Bf.hasOwnProperty(r)&&(l[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps,t)l[r]===void 0&&(l[r]=t[r]);return{$$typeof:$f,type:e,key:i,ref:o,props:l,_owner:Vf.current}}yl.Fragment=Uf;yl.jsx=Zu;yl.jsxs=Zu;Au.exports=yl;var p=Au.exports,qu={exports:{}},Ee={},bu={exports:{}},ea={};/**
* @license React
* scheduler.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.
*/(function(e){function t(T,z){var I=T.length;T.push(z);e:for(;0<I;){var K=I-1>>>1,ee=T[K];if(0<l(ee,z))T[K]=z,T[I]=ee,I=K;else break e}}function n(T){return T.length===0?null:T[0]}function r(T){if(T.length===0)return null;var z=T[0],I=T.pop();if(I!==z){T[0]=I;e:for(var K=0,ee=T.length,hr=ee>>>1;K<hr;){var Et=2*(K+1)-1,Dl=T[Et],Ct=Et+1,mr=T[Ct];if(0>l(Dl,I))Ct<ee&&0>l(mr,Dl)?(T[K]=mr,T[Ct]=I,K=Ct):(T[K]=Dl,T[Et]=I,K=Et);else if(Ct<ee&&0>l(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()-L<R)}function Q(){if(P!==null){var T=e.unstable_now();L=T;var z=!0;try{z=P(!0,T)}finally{z?b():(_=!1,P=null)}}else _=!1}var b;if(typeof f=="function")b=function(){f(Q)};else if(typeof MessageChannel<"u"){var pr=new MessageChannel,yf=pr.port2;pr.port1.onmessage=Q,b=function(){yf.postMessage(null)}}else b=function(){N(Q,0)};function Ml(T){P=T,_||(_=!0,b())}function Fl(T,z){C=N(function(){T(e.unstable_now())},z)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(T){T.callback=null},e.unstable_continueExecution=function(){g||y||(g=!0,Ml(E))},e.unstable_forceFrameRate=function(T){0>T||125<T?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):R=0<T?Math.floor(1e3/T):5},e.unstable_getCurrentPriorityLevel=function(){return d},e.unstable_getFirstCallbackNode=function(){return n(u)},e.unstable_next=function(T){switch(d){case 1:case 2:case 3:var z=3;break;default:z=d}var I=d;d=z;try{return T()}finally{d=I}},e.unstable_pauseExecution=function(){},e.unstable_requestPaint=function(){},e.unstable_runWithPriority=function(T,z){switch(T){case 1:case 2:case 3:case 4:case 5:break;default:T=3}var I=d;d=T;try{return z()}finally{d=I}},e.unstable_scheduleCallback=function(T,z,I){var K=e.unstable_now();switch(typeof I=="object"&&I!==null?(I=I.delay,I=typeof I=="number"&&0<I?K+I:K):I=K,T){case 1:var ee=-1;break;case 2:ee=250;break;case 5:ee=1073741823;break;case 4:ee=1e4;break;default:ee=5e3}return ee=I+ee,T={id:h++,callback:z,priorityLevel:T,startTime:I,expirationTime:ee,sortIndex:-1},I>K?(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<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var ta=new Set,Bn={};function Dt(e,t){un(e,t),un(e+"Capture",t)}function un(e,t){for(Bn[e]=t,e=0;e<t.length;e++)ta.add(t[e])}var Je=!(typeof window>"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||!(2<t.length)||t[0]!=="o"&&t[0]!==" Line truncated
`+Ul+e}var Al=!1;function Vl(e,t){if(!e||Al)return"";Al=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(t,[])}catch(a){var r=a}Reflect.construct(e,[],t)}else{try{t.call()}catch(a){r=a}e.call(t.prototype)}else{try{throw Error()}catch(a){r=a}e()}}catch(a){if(a&&r&&typeof a.stack=="string"){for(var l=a.stack.split(`
`),i=r.stack.split(`
`),o=l.length-1,s=i.length-1;1<=o&&0<=s&&l[o]!==i[s];)s--;for(;1<=o&&0<=s;o--,s--)if(l[o]!==i[s]){if(o!==1||s!==1)do if(o--,s--,0>s||l[o]!==i[s]){var u=`
`+l[o].replace(" at new "," at ");return e.displayName&&u.includes("<anonymous>")&&(u=u.replace("<anonymous>",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<n.length;l++)t["$"+n[l]]=!0;for(n=0;n<e.length;n++)l=t.hasOwnProperty("$"+e[n].value),e[n].selected!==l&&(e[n].selected=l),l&&r&&(e[n].defaultSelected=!0)}else{for(n=""+gt(n),t=null,l=0;l<e.length;l++){if(e[l].value===n){e[l].selected=!0,r&&(e[l].defaultSelected=!0);return}t!==null||e[l].disabled||(t=e[l])}t!==null&&(t.selected=!0)}}function xi(e,t){if(t.dang Line truncated
`).replace(sp,"")}function jr(e,t,n){if(t=As(t),As(e)!==t&&n)throw Error(k(425))}function tl(){}var zi=null,Ii=null;function Oi(e,t){return e==="textarea"||e==="noscript"||typeof t.children=="string"||typeof t.children=="number"||typeof t.dangerouslySetInnerHTML=="object"&&t.dangerouslySetInnerHTML!==null&&t.dangerouslySetInnerHTML.__html!=null}var Mi=typeof setTimeout=="function"?setTimeout:void 0,up=typeof clearTimeout=="function"?clearTimeout:void 0,Vs=typeof Promise=="function"?Promise:void 0,ap=typeof queueMicrotask=="function"?queueMicrotask:typeof Vs<"u"?function(e){return Vs.resolve(null).then(e).catch(cp)}:Mi;function cp(e){setTimeout(function(){throw e})}function ei(e,t){var n=t,r=0;do{var l=n.nextSibling;if(e.removeChild(n),l&&l.nodeType===8)if(n=l.data,n==="/$"){if(r===0){e.removeChild(l),Gn(t);return}r--}else n!=="$"&&n!=="$?"&&n!=="$!"||r++;n=l}while(n);Gn(t)}function ft(e){for(;e!=null;e=e.nextSibling){var t=e.nodeType;if(t===1||t===3)break;if(t===8){if(t=e.data,t==="$"||t==="$!"||t==="$?")break;if(t==="/$")return null}}return e}function Bs(e){e=e.previousSibling;for(var t=0;e;){if(e.nodeType===8){var n=e.data;if(n==="$"||n==="$!"||n==="$?"){if(t===0)return e;t--}else n==="/$"&&t++}e=e.previousSibling}return null}var gn=Math.random().toString(36).slice(2),Ae="__reactFiber$"+gn,qn="__reactProps$"+gn,Ye="__reactContainer$"+gn,Fi="__reactEvents$"+gn,fp="__reactListeners$"+gn,dp="__reactHandles$"+gn;function _t(e){var t=e[Ae];if(t)return t;for(var n=e.parentNode;n;){if(t=n[Ye]||n[Ae]){if(n=t.alternate,t.child!==null||n!==null&&n.child!==null)for(e=Bs(e);e!==null;){if(n=e[Ae])return n;e=Bs(e)}return t}e=n,n=e.parentNode}return null}function cr(e){return e=e[Ae]||e[Ye],!e||e.tag!==5&&e.tag!==6&&e.tag!==13&&e.tag!==3?null:e}function Gt(e){if(e.tag===5||e.tag===6)return e.stateNode;throw Error(k(33))}function El(e){return e[qn]||null}var Di=[],Jt=-1;function wt(e){return{current:e}}function U(e){0>Jt||(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<n.length;e++){var r=n[e];do r=r(!0);while(r!==null)}He=null,Cl=!1}catch(l){throw He!==null&&(He=He.slice(e+1)),Sa(wo,St),l}finally{F=t,ti=!1}}return null}var Yt=[],Xt=0,ll=null,il=0,Ne=[],je=0,It=null,Qe=1,Ke="";function Nt(e,t){Yt[Xt++]=il,Yt[Xt++]=ll,ll=e,il=t}function Za(e,t,n){Ne[je++]=Qe,Ne[je++]=Ke,Ne[je++]=It,It=e;var r=Qe;e=Ke;var l=32-Me(r)-1;r&=~(1<<l),n+=1;var i=32-Me(t)+l;if(30<i){var o=l-l%5;i=(r&(1<<o)-1).toString(32),r>>=o,l-=o,Qe=1<<32-Me(t)+l|n<<l|r,Ke=i+e}else Qe=1<<i|n<<l|r,Ke=e}function To(e){e.return!==null&&(Nt(e,1),Za(e,1,0))}function Lo(e){for(;e===ll;)ll=Yt[--Xt],Yt[Xt]=null,il=Yt[--Xt],Yt[Xt]=null;for(;e===It;)It=Ne[--je],Ne[je]=null,Ke=Ne[--je],Ne[je]=null,Qe=Ne[--je],Ne[je]=null}var Se=null,we=null,A=!1,Oe=null;function qa(e,t){var n=_e(5,null,null,0);n.elementType="DELETED",n.stateNode=t,n.return=e,t=e.deletions,t===null?(e.deletions=[n],e.flags|=16):t.push(n)}function Qs(e,t){switch(e.tag){case 5:var n=e.type;return t=t.nodeType!==1||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t,t!==null?(e.stateNode=t,Se=e,we=ft(t.firstChild),!0):!1;case 6:return t=e.pendingProps===""||t.nodeType!==3?null:t,t!==null?(e.stateNode=t,Se=e,we=null,!0):!1;case 13:return t=t.nodeType!==8?null:t,t!==null?(n=It!==null?{id:Qe,overflow:Ke}:null,e.memoizedState={dehydrated:t,treeContext:n,retryLane:1073741824},n=_e(18,null,null,0),n.stateNode=t,n.return=e,e.child=n,Se=e,we=null,!0):!1;default:return!1}}function $i(e){return(e.mode&1)!==0&&(e.flags&128)===0}function Ui(e){if(A){var t=we;if(t){var n=t;if(!Qs(e,t)){if($i(e))throw Error(k(418));t=ft(n.nextSibling);var r=Se;t&&Qs(e,t)?qa(r,n):(e.flags=e.flags&-4097|2,A=!1,Se=e)}}else{if($i(e))throw Error(k(418));e.flags=e.flags&-4097|2,A=!1,Se=e}}}function Ks(e){for(e=e.return;e!==null&&e.t Line truncated
Error generating stack: `+i.message+`
`+i.stack}return{value:e,source:t,stack:l,digest:null}}function oi(e,t,n){return{value:e,source:null,stack:n??null,digest:t??null}}function Wi(e,t){try{console.error(t.value)}catch(n){setTimeout(function(){throw n})}}var kp=typeof WeakMap=="function"?WeakMap:Map;function Nc(e,t,n){n=Ge(-1,n),n.tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){pl||(pl=!0,bi=r),Wi(e,t)},n}function jc(e,t,n){n=Ge(-1,n),n.tag=3;var r=e.type.getDerivedStateFromError;if(typeof r=="function"){var l=t.value;n.payload=function(){return r(l)},n.callback=function(){Wi(e,t)}}var i=e.stateNode;return i!==null&&typeof i.componentDidCatch=="function"&&(n.callback=function(){Wi(e,t),typeof r!="function"&&(pt===null?pt=new Set([this]):pt.add(this));var o=t.stack;this.componentDidCatch(t.value,{componentStack:o!==null?o:""})}),n}function eu(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new kp;var l=new Set;r.set(t,l)}else l=r.get(t),l===void 0&&(l=new Set,r.set(t,l));l.has(n)||(l.add(n),e=Fp.bind(null,e,t,n),t.then(e,e))}function tu(e){do{var t;if((t=e.tag===13)&&(t=e.memoizedState,t=t!==null?t.dehydrated!==null:!0),t)return e;e=e.return}while(e!==null);return null}function nu(e,t,n,r,l){return e.mode&1?(e.flags|=65536,e.lanes=l,e):(e===t?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,n.tag===1&&(n.alternate===null?n.tag=17:(t=Ge(-1,1),t.tag=2,dt(n,t,1))),n.lanes|=1),e)}var Ep=qe.ReactCurrentOwner,me=!1;function ce(e,t,n,r){t.child=e===null?tc(t,null,n,r):fn(t,e.child,n,r)}function ru(e,t,n,r,l){n=n.render;var i=t.ref;return on(t,l),r=Vo(e,t,n,r,i,l),n=Bo(),e!==null&&!me?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~l,Ze(e,t,l)):(A&&n&&To(t),t.flags|=1,ce(e,t,r,l),t.child)}function lu(e,t,n,r,l){if(e===null){var i=n.type;return typeof i=="function"&&!qo(i)&&i.defaultProps===void 0&&n.compare===null&&n.defaultProps===void 0?(t.tag=15,t.type=i,_c(e,t,i,r,l)):(e=Kr(n.type,null,r,t,t.mode,l),e.ref=t.ref,e.return=t,t.child=e)}if(i=e.child,!(e.lanes&l)){var o=i.memoizedProps;if(n=n.compare,n=n!==null?n:Yn,n(o,r)&&e.ref===t.ref)return Ze(e,t,l)}return t.flags|=1,e=mt(i,r),e.ref=t.ref,e.return=t,t.child=e}function _c(e,t,n,r,l){if(e!==null){var i=e.memoizedProps;if(Yn(i,r)&&e.ref===t.ref)if(me=!1,t.pendingProps=r=i,(e.lanes&l)!==0)e.flags&131072&&(me=!0);else return t.lanes=e.lanes,Ze(e,t,l)}return Hi(e,t,n,r,l)}function Pc(e,t,n){var r=t.pendingProps,l=r.children,i=e!==null?e.memoizedState:null;if(r.mode==="hidden")if(!(t.mode&1))t.memoizedState={baseLanes:0,cachePool:null,transitions:null},D(bt,xe),xe|=n;else{if(!(n&1073741824))return e=i!==null?i.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e,cachePool:null,transitions:null},t.updateQueue=null,D(bt,xe),xe|=e,null;t.memoizedState={baseLanes:0,cachePool:null,transitions:null},r=i!==null?i.baseLanes:n,D(bt,xe),xe|=r}else i!==null?(r=i.baseLanes|n,t.memoizedState=null):r=n,D(bt,xe),xe|=r;return ce(e,t,l,n),t.child}function Tc(e,t){var n=t.ref;(e===null&&n!==null||e!==null&&e.ref!==n)&&(t.flags|=512,t.flags|=2097152)}function Hi(e,t,n,r,l){var i=ge(n)?zt:ae.current;return i=an(t,i),on(t,l),n=Vo(e,t,n,r,i,l),r=Bo(),e!==null&&!me?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~l,Ze(e,t,l)):(A&&r&&To(t),t.flags|=1,ce(e,t,n,l),t.child)}function iu(e,t,n,r,l){if(ge(n)){var i=!0;rl(t)}else i=!1;if(on(t,l),t.stateNode===null)Wr(e,t),Cc(t,n,r),Bi(t,n,r,l),r=!0;else if(e===null){var o=t.stateNode,s=t.memoizedProps;o.props=s;var u=o.context,a=n.contextType;typeof a=="object"&&a!==null?a=Te(a):(a=ge(n)?zt:ae.current,a=an(t,a));var h=n.getDerivedStateFromProps,c=typeof h=="function"||typeof o.getSnapshotBeforeUpdate=="function";c||typeof o.UNSAFE_componentWillReceiveProps!="function"&&typeof o.componentWillReceiveProps!="function"||(s!==r||u!==a)&&bs(t,o,r,a),nt=!1;var d=t.memoizedState;o.state=d,ul(t,r,o,l),u=t.memoizedState,s!==r||d!==u||ve.current||nt?(typeof h=="function"&&(Vi(t,n,h,r),u=t.memoizedState),(s=nt||qs(t,n,s,r,d,u,a))?(c||typeof o.UNSAFE_componentWillMount!="function"&&typeof o.componentWillMount!="function"||(typeof o.componentWillMount=="function"&&o.componentWillMount(),typeof o.UNSAFE_componentWillMount=="function"&&o.UNSAFE_componentWillMount()),typeof o.componentDidMount=="function"&&(t.flags|=4194308)):(typeof o.componentDidMount=="function"&&(t.flags|=4194308),t.memoizedProps=r,t.memoizedState=u),o.props=r,o.state=u,o.context=a,r=s):(typeof o.componentDidMount=="function"&&(t.flags|=4194308),r=!1)}else{o=t.stateNode,rc(e,t),s=t.memoizedProps,a=t.type===t.elementType?s:ze(t.type,s),o.props=a,c=t.pendingProps,d=o.context,u=n.contextType,typeof u=="object"&&u!==null?u=Te(u):(u=ge(n)?zt:ae.current,u=an(t,u));var y=n.getDerivedStateFromProps;(h=typeof y=="function"||typeof o.getSnapshotBeforeUpdate=="function")||typeof o.UNSAFE_componentWillReceiveProps!="function"&&typeof o.componentWillReceiveProps!="function"||(s!==c||d!==u)&&bs(t,o,r,u),nt=!1,d=t.memoizedState,o.state=d,ul(t,r,o,l);var g=t.memoizedState;s Line truncated
* @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<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},ir.apply(this,arguments)}var st;(function(e){e.Pop="POP",e.Push="PUSH",e.Replace="REPLACE"})(st||(st={}));const xu="popstate";function Jp(e){e===void 0&&(e={});function t(r,l){let{pathname:i,search:o,hash:s}=r.location;return ro("",{pathname:i,search:o,hash:s},l.state&&l.state.usr||null,l.state&&l.state.key||"default")}function n(r,l){return typeof l=="string"?l:gl(l)}return Xp(t,n,null,e)}function J(e,t){if(e===!1||e===null||typeof e>"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<o.length;++u){let a=fh(i);s=uh(o[u],a)}return s}function ef(e,t,n,r){t===void 0&&(t=[]),n===void 0&&(n=[]),r===void 0&&(r="");let l=(i,o,s)=>{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<r.length;++s){let u=r[s],a=s===r.length-1,h=i==="/"?t:t.slice(i.length)||"/",c=ah({path:u.relativePath,caseSensitive:u.caseSensitLine truncated
* 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<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},or.apply(this,arguments)}const ss=S.createContext(null),Sh=S.createContext(null),kt=S.createContext(null),Ol=S.createContext(null),be=S.createContext({outlet:null,matches:[],isDataRoute:!1}),rf=S.createContext(null);function kh(e,t){let{relative:n}=t===void 0?{}:t;xn()||J(!1);let{basename:r,navigator:l}=S.useContext(kt),{hash:i,pathname:o,search:s}=sf(e,{relative:n}),u=o;return r!=="/"&&(u=o==="/"?r:vt([r,o])),l.createHref({pathname:u,search:s,hash:i})}function xn(){return S.useContext(Ol)!=null}function dr(){return xn()||J(!1),S.useContext(Ol).location}function lf(e){S.useContext(kt).static||S.useLayoutEffect(e)}function us(){let{isDataRoute:e}=S.useContext(be);return e?Mh():Eh()}function Eh(){xn()||J(!1);let e=S.useContext(ss),{basename:t,future:n,navigator:r}=S.useContext(kt),{matches:l}=S.useContext(be),{pathname:i}=dr(),o=JSON.stringify(is(l,n.v7_relativeSplatPath)),s=S.useRef(!1);return lf(()=>{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<o.length;h++){let c=o[h];if((c.route.HydrateFallback||c.route.hydrateFallbackElement)&&(a=h),c.route.id){let{loaderData:d,errors:y}=n,g=c.route.loader&&d[c.route.id]===void 0&&(!y||y[c.route.id]===void 0);if(c.route.lazy||g){u=!0,a>=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 0Line truncated
* 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<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},io.apply(this,arguments)}function Vh(e,t){if(e==null)return{};var n={},r=Object.keys(e),l,i;for(i=0;i<r.length;i++)l=r[i],!(t.indexOf(l)>=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","dLine truncated
File renamed without changes.
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>sanderling inspect</title>
<script type="module" crossorigin src="/assets/index-DAhEzdrG.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BSJUf7yI.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
File renamed without changes.
File renamed without changes.
View File
Whitespace-only changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1 -1
View File
@@ -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 {
@@ -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 <T> snapshot(function: () -> T): SnapshotDelegate<T> = 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<T>(private val function: () -> T) {
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, T> {
Sanderling.extract(prop.name.camelToSnakeCase(), function as () -> Any?)
return ReadOnlyProperty { _, _ -> function() }
}
}
@@ -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()
}
}