diff --git a/apps/fabro-web/app/install-app.test.tsx b/apps/fabro-web/app/install-app.test.tsx index b4f27f842..bff6a80c2 100644 --- a/apps/fabro-web/app/install-app.test.tsx +++ b/apps/fabro-web/app/install-app.test.tsx @@ -6,6 +6,10 @@ import InstallApp from "./install-app"; const INSTALL_ERROR_MESSAGE = "GitHub App setup failed before Fabro could save the app credentials. Continue again to retry the callback."; +const INSTALL_PREFILL = { + canonical_url: "https://fabro.example.com", + object_store_local_root: "/home/test/.fabro/storage/objects", +}; const SESSION_RESPONSE = { completed_steps: ["server", "object_store", "llm"], @@ -13,7 +17,7 @@ const SESSION_RESPONSE = { server: { canonical_url: "https://fabro.example.com" }, object_store: { provider: "local" }, github: null, - prefill: { canonical_url: "https://fabro.example.com" }, + prefill: INSTALL_PREFILL, }; type TestWindow = { @@ -201,7 +205,7 @@ describe("InstallApp", () => { slug: "fabro-brynary", allowed_username: "brynary", }, - prefill: { canonical_url: "https://fabro.example.com" }, + prefill: INSTALL_PREFILL, }; const fetchMock = mock((input: RequestInfo | URL) => { expect(String(input)).toBe("/install/session"); @@ -270,7 +274,7 @@ describe("InstallApp", () => { server: { canonical_url: "https://fabro.example.com" }, object_store: null, github: null, - prefill: { canonical_url: "https://fabro.example.com" }, + prefill: INSTALL_PREFILL, }), { status: 200, @@ -291,7 +295,7 @@ describe("InstallApp", () => { server: { canonical_url: "https://fabro.example.com" }, object_store: { provider: "local" }, github: null, - prefill: { canonical_url: "https://fabro.example.com" }, + prefill: INSTALL_PREFILL, }), { status: 200, @@ -345,7 +349,12 @@ describe("InstallApp", () => { "/install/object-store", "/install/session", ]); - expect(fetchCalls[1]?.init?.body).toBe(JSON.stringify({ provider: "local" })); + expect(fetchCalls[1]?.init?.body).toBe( + JSON.stringify({ + provider: "local", + root: INSTALL_PREFILL.object_store_local_root, + }), + ); await act(async () => { renderer?.unmount(); @@ -384,7 +393,7 @@ describe("InstallApp", () => { manual_credentials_saved: true, }, github: null, - prefill: { canonical_url: "https://fabro.example.com" }, + prefill: INSTALL_PREFILL, }), { status: 200, @@ -459,7 +468,7 @@ describe("InstallApp", () => { manual_credentials_saved: true, }, github: { strategy: "token", username: "octocat" }, - prefill: { canonical_url: "https://fabro.example.com" }, + prefill: INSTALL_PREFILL, }), { status: 200, diff --git a/apps/fabro-web/app/install-app.tsx b/apps/fabro-web/app/install-app.tsx index b3dabc520..c04b5988e 100644 --- a/apps/fabro-web/app/install-app.tsx +++ b/apps/fabro-web/app/install-app.tsx @@ -84,6 +84,7 @@ type ObjectStoreProvider = "local" | "s3"; type ObjectStoreCredentialMode = "runtime" | "access_key"; type ObjectStoreForm = { provider: ObjectStoreProvider; + localRoot: string; bucket: string; region: string; credentialMode: ObjectStoreCredentialMode; @@ -120,6 +121,7 @@ export default function InstallApp() { const [finishState, setFinishState] = useState(null); const [timedOut, setTimedOut] = useState(false); const canonicalUrlInputRef = useRef(null); + const localRootInputRef = useRef(null); const bucketInputRef = useRef(null); const regionInputRef = useRef(null); const accessKeyIdInputRef = useRef(null); @@ -421,7 +423,13 @@ export default function InstallApp() { } backHref="/install/server" onSubmit={async () => { - if (objectStoreForm.provider === "s3") { + if (objectStoreForm.provider === "local") { + if (!objectStoreForm.localRoot.trim()) { + setSaveError("Enter the local object-store directory before continuing."); + focusInput(localRootInputRef); + return; + } + } else { if (!objectStoreForm.bucket.trim()) { setSaveError("Enter the S3 bucket before continuing."); focusInput(bucketInputRef); @@ -473,6 +481,8 @@ export default function InstallApp() { setObjectStoreForm((current) => ({ ...current, provider })); if (provider === "s3") { focusInput(bucketInputRef); + } else { + focusInput(localRootInputRef); } }} /> @@ -574,9 +584,31 @@ export default function InstallApp() { )} ) : ( -

- Fabro will keep using local disk for both SlateDB and run artifacts. -

+
+ + + setObjectStoreForm((current) => ({ + ...current, + localRoot: event.target.value, + })) + } + className={`${INPUT_CLASS} font-mono`} + placeholder="Local object-store directory" + spellCheck={false} + autoCapitalize="off" + /> + +

+ Fabro will store SlateDB and run artifacts under this directory. +

+
)} ) : location.pathname === "/install/github/done" ? ( @@ -1614,9 +1646,10 @@ function defaultProviderSelection(): ProviderSelection { ); } -function defaultObjectStoreForm(): ObjectStoreForm { +function defaultObjectStoreForm(localRoot = ""): ObjectStoreForm { return { provider: "local", + localRoot, bucket: "", region: "", credentialMode: "runtime", @@ -1643,10 +1676,13 @@ function hydrateProviderSelection( function hydrateObjectStoreForm(session: InstallSessionResponse): ObjectStoreForm { const summary = session.object_store; if (!summary || summary.provider === "local") { - return defaultObjectStoreForm(); + return defaultObjectStoreForm( + summary?.root ?? session.prefill.object_store_local_root, + ); } return { provider: "s3", + localRoot: session.prefill.object_store_local_root, bucket: summary.bucket ?? "", region: summary.region ?? "", credentialMode: summary.credential_mode === "access_key" ? "access_key" : "runtime", @@ -1658,7 +1694,7 @@ function hydrateObjectStoreForm(session: InstallSessionResponse): ObjectStoreFor function buildObjectStorePayload(form: ObjectStoreForm): InstallObjectStoreInput { if (form.provider === "local") { - return { provider: "local" }; + return { provider: "local", root: form.localRoot.trim() }; } const payload: InstallObjectStoreInput = { @@ -1727,7 +1763,12 @@ function renderObjectStoreSummaryRows( return ; } if (objectStore.provider === "local") { - return ; + return ( + <> + + + + ); } return ( <> diff --git a/docs/administration/server-configuration.mdx b/docs/administration/server-configuration.mdx index 1d96421d8..475cb1249 100644 --- a/docs/administration/server-configuration.mdx +++ b/docs/administration/server-configuration.mdx @@ -192,8 +192,9 @@ region = "us-east-1" ``` The browser install wizard's `Object store` step manages both `[server.slatedb]` and -`[server.artifacts]` together. `Local disk` leaves both sections implicit and keeps the built-in -local defaults. `AWS S3` writes one shared bucket with fixed prefixes `slatedb` and `artifacts`. +`[server.artifacts]` together. `Local disk` uses the detected local object-store root, defaulting +to `/objects`, with fixed prefixes `slatedb` and `artifacts`. `AWS S3` writes one +shared bucket with the same fixed prefixes. The wizard only covers AWS S3 bucket/region plus one of: diff --git a/docs/api-reference/fabro-api.yaml b/docs/api-reference/fabro-api.yaml index 72ce406ed..c640dbf98 100644 --- a/docs/api-reference/fabro-api.yaml +++ b/docs/api-reference/fabro-api.yaml @@ -2556,10 +2556,13 @@ components: type: object required: - canonical_url + - object_store_local_root properties: canonical_url: type: string format: uri + object_store_local_root: + type: string InstallLlmValidationResponse: description: Successful response from install-time LLM credential validation. @@ -2655,6 +2658,8 @@ components: provider: type: string enum: [local, s3] + root: + type: string bucket: type: string region: @@ -2676,6 +2681,8 @@ components: provider: type: string enum: [local, s3] + root: + type: string bucket: type: string region: diff --git a/lib/crates/fabro-install/src/lib.rs b/lib/crates/fabro-install/src/lib.rs index 84bf86cce..e4ebf580c 100644 --- a/lib/crates/fabro-install/src/lib.rs +++ b/lib/crates/fabro-install/src/lib.rs @@ -41,7 +41,9 @@ pub enum InstallObjectStoreCredentialMode { #[derive(Debug, Clone, PartialEq, Eq)] pub enum InstallObjectStoreSelection { - Local, + Local { + root: String, + }, S3 { bucket: String, region: String, @@ -287,15 +289,44 @@ fn write_s3_store_settings( Ok(()) } +fn write_local_store_settings( + server: &mut toml::Table, + domain: &str, + prefix: &str, + root: &str, +) -> Result<()> { + let store = ensure_table(server, domain)?; + store.insert( + "provider".to_string(), + toml::Value::String("local".to_string()), + ); + store.insert( + "prefix".to_string(), + toml::Value::String(prefix.to_string()), + ); + let local = ensure_table(store, "local")?; + local.insert("root".to_string(), toml::Value::String(root.to_string())); + Ok(()) +} + pub fn write_object_store_settings( doc: &mut toml::Value, selection: &InstallObjectStoreSelection, ) -> Result { match selection { - InstallObjectStoreSelection::Local => Ok(InstallObjectStoreEnvPlan { - writes: Vec::new(), - removals: object_store_env_removals(), - }), + InstallObjectStoreSelection::Local { root } => { + let root = root.trim(); + if !root.is_empty() { + let root_table = root_table_mut(doc)?; + let server = ensure_table(root_table, "server")?; + write_local_store_settings(server, "artifacts", "artifacts", root)?; + write_local_store_settings(server, "slatedb", "slatedb", root)?; + } + Ok(InstallObjectStoreEnvPlan { + writes: Vec::new(), + removals: object_store_env_removals(), + }) + } InstallObjectStoreSelection::S3 { bucket, region, @@ -671,8 +702,10 @@ name = "custom" #[test] fn write_object_store_settings_keeps_local_defaults_and_removes_managed_keys() { let mut doc = toml::Value::Table(toml::Table::default()); - let plan = write_object_store_settings(&mut doc, &InstallObjectStoreSelection::Local) - .expect("local object store selection should succeed"); + let plan = write_object_store_settings(&mut doc, &InstallObjectStoreSelection::Local { + root: String::new(), + }) + .expect("local object store selection should succeed"); assert!( doc.get("server") @@ -684,6 +717,74 @@ name = "custom" assert_eq!(plan.removals.len(), 2); } + #[test] + fn write_object_store_settings_configures_local_root() { + let mut doc = toml::Value::Table(toml::Table::default()); + let plan = write_object_store_settings(&mut doc, &InstallObjectStoreSelection::Local { + root: "/srv/fabro/objects".to_string(), + }) + .expect("local object store selection should succeed"); + + let server = doc + .get("server") + .and_then(toml::Value::as_table) + .expect("server table should exist"); + assert_eq!( + server + .get("artifacts") + .and_then(toml::Value::as_table) + .and_then(|artifacts| artifacts.get("provider")) + .and_then(toml::Value::as_str), + Some("local") + ); + assert_eq!( + server + .get("artifacts") + .and_then(toml::Value::as_table) + .and_then(|artifacts| artifacts.get("prefix")) + .and_then(toml::Value::as_str), + Some("artifacts") + ); + assert_eq!( + server + .get("artifacts") + .and_then(toml::Value::as_table) + .and_then(|artifacts| artifacts.get("local")) + .and_then(toml::Value::as_table) + .and_then(|local| local.get("root")) + .and_then(toml::Value::as_str), + Some("/srv/fabro/objects") + ); + assert_eq!( + server + .get("slatedb") + .and_then(toml::Value::as_table) + .and_then(|slatedb| slatedb.get("provider")) + .and_then(toml::Value::as_str), + Some("local") + ); + assert_eq!( + server + .get("slatedb") + .and_then(toml::Value::as_table) + .and_then(|slatedb| slatedb.get("prefix")) + .and_then(toml::Value::as_str), + Some("slatedb") + ); + assert_eq!( + server + .get("slatedb") + .and_then(toml::Value::as_table) + .and_then(|slatedb| slatedb.get("local")) + .and_then(toml::Value::as_table) + .and_then(|local| local.get("root")) + .and_then(toml::Value::as_str), + Some("/srv/fabro/objects") + ); + assert!(plan.writes.is_empty()); + assert_eq!(plan.removals.len(), 2); + } + #[test] fn write_object_store_settings_configures_s3_runtime_credentials() { let mut doc = toml::Value::Table(toml::Table::default()); diff --git a/lib/crates/fabro-server/src/install.rs b/lib/crates/fabro-server/src/install.rs index 1dfb001eb..b7bea4926 100644 --- a/lib/crates/fabro-server/src/install.rs +++ b/lib/crates/fabro-server/src/install.rs @@ -230,6 +230,7 @@ enum InstallObjectStoreCredentialMode { #[derive(Clone, Debug, Deserialize)] struct InstallObjectStoreInput { provider: InstallObjectStoreProvider, + root: Option, bucket: Option, region: Option, credential_mode: Option, @@ -297,7 +298,9 @@ impl std::fmt::Debug for InstallAwsCredentialPair { #[derive(Clone, Debug)] enum InstallObjectStoreState { - Local, + Local { + root: String, + }, S3 { bucket: String, region: String, @@ -309,8 +312,9 @@ enum InstallObjectStoreState { impl InstallObjectStoreState { fn as_session_value(&self) -> serde_json::Value { match self { - Self::Local => serde_json::json!({ + Self::Local { root } => serde_json::json!({ "provider": "local", + "root": root, }), Self::S3 { bucket, @@ -332,7 +336,9 @@ impl InstallObjectStoreState { fn to_persistence_selection(&self) -> fabro_install::InstallObjectStoreSelection { match self { - Self::Local => fabro_install::InstallObjectStoreSelection::Local, + Self::Local { root } => { + fabro_install::InstallObjectStoreSelection::Local { root: root.clone() } + } Self::S3 { bucket, region, @@ -648,6 +654,7 @@ async fn get_install_session( "github": redacted_github(&pending_install), "prefill": { "canonical_url": detect_canonical_url(&headers), + "object_store_local_root": default_local_object_store_root(&state), } })) .into_response() @@ -766,7 +773,11 @@ async fn post_install_object_store_test( let selection = { let pending_install = lock_unpoisoned(&state.pending_install, "install session"); - match resolve_install_object_store_state(pending_install.object_store.as_ref(), input) { + match resolve_install_object_store_state( + pending_install.object_store.as_ref(), + input, + &default_local_object_store_root(&state), + ) { Ok(selection) => selection, Err(err) => return install_error_response(StatusCode::UNPROCESSABLE_ENTITY, err), } @@ -793,11 +804,14 @@ async fn put_install_object_store( observe_operator(&state, &headers); let mut pending_install = lock_unpoisoned(&state.pending_install, "install session"); - let selection = - match resolve_install_object_store_state(pending_install.object_store.as_ref(), input) { - Ok(selection) => selection, - Err(err) => return install_error_response(StatusCode::UNPROCESSABLE_ENTITY, err), - }; + let selection = match resolve_install_object_store_state( + pending_install.object_store.as_ref(), + input, + &default_local_object_store_root(&state), + ) { + Ok(selection) => selection, + Err(err) => return install_error_response(StatusCode::UNPROCESSABLE_ENTITY, err), + }; pending_install.object_store = Some(selection); info!(step = "object_store", "install step completed"); @@ -810,10 +824,21 @@ fn trim_install_field(value: Option) -> Option { .filter(|value| !value.is_empty()) } +fn default_local_object_store_root(state: &InstallAppState) -> String { + state + .storage_dir + .as_ref() + .join("objects") + .display() + .to_string() +} + fn resolve_install_object_store_state( current: Option<&InstallObjectStoreState>, input: InstallObjectStoreInput, + default_local_root: &str, ) -> Result { + let root = trim_install_field(input.root); let bucket = trim_install_field(input.bucket); let region = trim_install_field(input.region); let access_key_id = trim_install_field(input.access_key_id); @@ -832,7 +857,13 @@ fn resolve_install_object_store_state( .to_string(), ); } - Ok(InstallObjectStoreState::Local) + let root = root + .or_else(|| match current { + Some(InstallObjectStoreState::Local { root }) => Some(root.clone()), + _ => None, + }) + .unwrap_or_else(|| default_local_root.to_string()); + Ok(InstallObjectStoreState::Local { root }) } InstallObjectStoreProvider::S3 => { let bucket = bucket.ok_or_else(|| "Bucket is required.".to_string())?; @@ -900,7 +931,7 @@ fn object_store_validation_settings( selection: &InstallObjectStoreState, ) -> Option { match selection { - InstallObjectStoreState::Local => None, + InstallObjectStoreState::Local { .. } => None, InstallObjectStoreState::S3 { bucket, region, .. } => Some(ObjectStoreSettings::S3 { bucket: InterpString::parse(bucket), region: InterpString::parse(region), @@ -935,7 +966,7 @@ async fn validate_install_object_store_selection( }; let (bucket, region, manual_credentials) = match selection { - InstallObjectStoreState::Local => return Ok(()), + InstallObjectStoreState::Local { .. } => return Ok(()), InstallObjectStoreState::S3 { bucket, region, @@ -1962,10 +1993,10 @@ mod tests { use super::{ AWS_SESSION_TOKEN_ENV, DEFAULT_INSTALL_GITHUB_API_BASE_URL, InstallAppState, InstallAwsCredentialPair, InstallFinishGuard, InstallObjectStoreCredentialMode, - InstallObjectStoreInput, InstallObjectStoreProvider, PendingInstall, ServerSecrets, - classify_object_store_validation_error, detect_canonical_url, install_object_store_lookup, - lock_unpoisoned, resolve_install_object_store_state, token_is_valid, - write_artifact_store_metadata, + InstallObjectStoreInput, InstallObjectStoreProvider, InstallObjectStoreState, + PendingInstall, ServerSecrets, classify_object_store_validation_error, + detect_canonical_url, install_object_store_lookup, lock_unpoisoned, + resolve_install_object_store_state, token_is_valid, write_artifact_store_metadata, }; #[test] @@ -2080,14 +2111,19 @@ methods = ["dev-token"] #[test] fn resolve_install_object_store_state_rejects_local_with_s3_fields() { - let err = resolve_install_object_store_state(None, InstallObjectStoreInput { - provider: InstallObjectStoreProvider::Local, - bucket: Some("fabro-data".to_string()), - region: None, - credential_mode: None, - access_key_id: None, - secret_access_key: None, - }) + let err = resolve_install_object_store_state( + None, + InstallObjectStoreInput { + provider: InstallObjectStoreProvider::Local, + root: Some("/srv/fabro/objects".to_string()), + bucket: Some("fabro-data".to_string()), + region: None, + credential_mode: None, + access_key_id: None, + secret_access_key: None, + }, + "/srv/fabro/objects", + ) .expect_err("local mode should reject S3-only fields"); assert_eq!( @@ -2096,16 +2132,44 @@ methods = ["dev-token"] ); } + #[test] + fn resolve_install_object_store_state_uses_local_root() { + let selection = resolve_install_object_store_state( + None, + InstallObjectStoreInput { + provider: InstallObjectStoreProvider::Local, + root: Some(" /srv/fabro/objects ".to_string()), + bucket: None, + region: None, + credential_mode: None, + access_key_id: None, + secret_access_key: None, + }, + "/default/fabro/objects", + ) + .expect("local mode should accept a root"); + + assert!(matches!( + selection, + InstallObjectStoreState::Local { ref root } if root == "/srv/fabro/objects" + )); + } + #[test] fn resolve_install_object_store_state_rejects_runtime_with_submitted_access_keys() { - let err = resolve_install_object_store_state(None, InstallObjectStoreInput { - provider: InstallObjectStoreProvider::S3, - bucket: Some("fabro-data".to_string()), - region: Some("us-east-1".to_string()), - credential_mode: Some(InstallObjectStoreCredentialMode::Runtime), - access_key_id: Some("AKIA_FAKE_VALUE".to_string()), - secret_access_key: Some("fake-secret-value".to_string()), - }) + let err = resolve_install_object_store_state( + None, + InstallObjectStoreInput { + provider: InstallObjectStoreProvider::S3, + root: None, + bucket: Some("fabro-data".to_string()), + region: Some("us-east-1".to_string()), + credential_mode: Some(InstallObjectStoreCredentialMode::Runtime), + access_key_id: Some("AKIA_FAKE_VALUE".to_string()), + secret_access_key: Some("fake-secret-value".to_string()), + }, + "/srv/fabro/objects", + ) .expect_err("runtime mode should reject submitted access keys"); assert_eq!( diff --git a/lib/crates/fabro-spa/assets/assets/entry-rwnsw2a9.js b/lib/crates/fabro-spa/assets/assets/entry-mvfx1rhm.js similarity index 61% rename from lib/crates/fabro-spa/assets/assets/entry-rwnsw2a9.js rename to lib/crates/fabro-spa/assets/assets/entry-mvfx1rhm.js index fcd771c34..7e124339b 100644 --- a/lib/crates/fabro-spa/assets/assets/entry-rwnsw2a9.js +++ b/lib/crates/fabro-spa/assets/assets/entry-mvfx1rhm.js @@ -1,76 +1,76 @@ -import{X as h,Y as D3,Z as p5,_ as x}from"./chunk-q07bg6gn.js";var J0=D3((va,YU)=>{(function(){function Z(j,Y0){Object.defineProperty(z.prototype,j,{get:function(){console.warn("%s(...) is deprecated in plain JavaScript React classes. %s",Y0[0],Y0[1])}})}function Y(j){if(j===null||typeof j!=="object")return null;return j=B1&&j[B1]||j["@@iterator"],typeof j==="function"?j:null}function Q(j,Y0){j=(j=j.constructor)&&(j.displayName||j.name)||"ReactClass";var A0=j+"."+Y0;R0[A0]||(console.error("Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.",Y0,j),R0[A0]=!0)}function z(j,Y0,A0){this.props=j,this.context=Y0,this.refs=n5,this.updater=A0||C1}function q(){}function B(j,Y0,A0){this.props=j,this.context=Y0,this.refs=n5,this.updater=A0||C1}function W(){}function $(j){return""+j}function U(j){try{$(j);var Y0=!1}catch(k0){Y0=!0}if(Y0){Y0=console;var A0=Y0.error,T0=typeof Symbol==="function"&&Symbol.toStringTag&&j[Symbol.toStringTag]||j.constructor.name||"Object";return A0.call(Y0,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",T0),$(j)}}function M(j){if(j==null)return null;if(typeof j==="function")return j.$$typeof===t6?null:j.displayName||j.name||null;if(typeof j==="string")return j;switch(j){case K0:return"Fragment";case z0:return"Profiler";case f:return"StrictMode";case x0:return"Suspense";case H0:return"SuspenseList";case R1:return"Activity"}if(typeof j==="object")switch(typeof j.tag==="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),j.$$typeof){case Z0:return"Portal";case n:return j.displayName||"Context";case i:return(j._context.displayName||"Context")+".Consumer";case L0:var Y0=j.render;return j=j.displayName,j||(j=Y0.displayName||Y0.name||"",j=j!==""?"ForwardRef("+j+")":"ForwardRef"),j;case p0:return Y0=j.displayName||null,Y0!==null?Y0:M(j.type)||"Memo";case i0:Y0=j._payload,j=j._init;try{return M(j(Y0))}catch(A0){}}return null}function H(j){if(j===K0)return"<>";if(typeof j==="object"&&j!==null&&j.$$typeof===i0)return"<...>";try{var Y0=M(j);return Y0?"<"+Y0+">":"<...>"}catch(A0){return"<...>"}}function O(){var j=W1.A;return j===null?null:j.getOwner()}function _(){return Error("react-stack-top-frame")}function A(j){if(N4.call(j,"key")){var Y0=Object.getOwnPropertyDescriptor(j,"key").get;if(Y0&&Y0.isReactWarning)return!1}return j.key!==void 0}function P(j,Y0){function A0(){V6||(V6=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",Y0))}A0.isReactWarning=!0,Object.defineProperty(j,"key",{get:A0,configurable:!0})}function L(){var j=M(this.type);return d4[j]||(d4[j]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),j=this.props.ref,j!==void 0?j:null}function v(j,Y0,A0,T0,k0,Y1){var f0=A0.ref;return j={$$typeof:G0,type:j,key:Y0,props:A0,_owner:T0},(f0!==void 0?f0:null)!==null?Object.defineProperty(j,"ref",{enumerable:!1,get:L}):Object.defineProperty(j,"ref",{enumerable:!1,value:null}),j._store={},Object.defineProperty(j._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(j,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(j,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:k0}),Object.defineProperty(j,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:Y1}),Object.freeze&&(Object.freeze(j.props),Object.freeze(j)),j}function R(j,Y0){return Y0=v(j.type,Y0,j.props,j._owner,j._debugStack,j._debugTask),j._store&&(Y0._store.validated=j._store.validated),Y0}function T(j){C(j)?j._store&&(j._store.validated=1):typeof j==="object"&&j!==null&&j.$$typeof===i0&&(j._payload.status==="fulfilled"?C(j._payload.value)&&j._payload.value._store&&(j._payload.value._store.validated=1):j._store&&(j._store.validated=1))}function C(j){return typeof j==="object"&&j!==null&&j.$$typeof===G0}function y(j){var Y0={"=":"=0",":":"=2"};return"$"+j.replace(/[=:]/g,function(A0){return Y0[A0]})}function b(j,Y0){return typeof j==="object"&&j!==null&&j.key!=null?(U(j.key),y(""+j.key)):Y0.toString(36)}function S(j){switch(j.status){case"fulfilled":return j.value;case"rejected":throw j.reason;default:switch(typeof j.status==="string"?j.then(W,W):(j.status="pending",j.then(function(Y0){j.status==="pending"&&(j.status="fulfilled",j.value=Y0)},function(Y0){j.status==="pending"&&(j.status="rejected",j.reason=Y0)})),j.status){case"fulfilled":return j.value;case"rejected":throw j.reason}}throw j}function I(j,Y0,A0,T0,k0){var Y1=typeof j;if(Y1==="undefined"||Y1==="boolean")j=null;var f0=!1;if(j===null)f0=!0;else switch(Y1){case"bigint":case"string":case"number":f0=!0;break;case"object":switch(j.$$typeof){case G0:case Z0:f0=!0;break;case i0:return f0=j._init,I(f0(j._payload),Y0,A0,T0,k0)}}if(f0){f0=j,k0=k0(f0);var Q1=T0===""?"."+b(f0,0):T0;return H1(k0)?(A0="",Q1!=null&&(A0=Q1.replace(Y7,"$&/")+"/"),I(k0,Y0,A0,"",function(_5){return _5})):k0!=null&&(C(k0)&&(k0.key!=null&&(f0&&f0.key===k0.key||U(k0.key)),A0=R(k0,A0+(k0.key==null||f0&&f0.key===k0.key?"":(""+k0.key).replace(Y7,"$&/")+"/")+Q1),T0!==""&&f0!=null&&C(f0)&&f0.key==null&&f0._store&&!f0._store.validated&&(A0._store.validated=2),k0=A0),Y0.push(k0)),1}if(f0=0,Q1=T0===""?".":T0+":",H1(j))for(var y0=0;y0{(function(){function Z(j,Z0){Object.defineProperty(z.prototype,j,{get:function(){console.warn("%s(...) is deprecated in plain JavaScript React classes. %s",Z0[0],Z0[1])}})}function Y(j){if(j===null||typeof j!=="object")return null;return j=B1&&j[B1]||j["@@iterator"],typeof j==="function"?j:null}function Q(j,Z0){j=(j=j.constructor)&&(j.displayName||j.name)||"ReactClass";var F0=j+"."+Z0;R0[F0]||(console.error("Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.",Z0,j),R0[F0]=!0)}function z(j,Z0,F0){this.props=j,this.context=Z0,this.refs=n5,this.updater=F0||C1}function q(){}function B(j,Z0,F0){this.props=j,this.context=Z0,this.refs=n5,this.updater=F0||C1}function W(){}function $(j){return""+j}function U(j){try{$(j);var Z0=!1}catch(x0){Z0=!0}if(Z0){Z0=console;var F0=Z0.error,T0=typeof Symbol==="function"&&Symbol.toStringTag&&j[Symbol.toStringTag]||j.constructor.name||"Object";return F0.call(Z0,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",T0),$(j)}}function M(j){if(j==null)return null;if(typeof j==="function")return j.$$typeof===n6?null:j.displayName||j.name||null;if(typeof j==="string")return j;switch(j){case q0:return"Fragment";case z0:return"Profiler";case f:return"StrictMode";case y0:return"Suspense";case U0:return"SuspenseList";case _1:return"Activity"}if(typeof j==="object")switch(typeof j.tag==="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),j.$$typeof){case e:return"Portal";case s:return j.displayName||"Context";case N0:return(j._context.displayName||"Context")+".Consumer";case H0:var Z0=j.render;return j=j.displayName,j||(j=Z0.displayName||Z0.name||"",j=j!==""?"ForwardRef("+j+")":"ForwardRef"),j;case u0:return Z0=j.displayName||null,Z0!==null?Z0:M(j.type)||"Memo";case a0:Z0=j._payload,j=j._init;try{return M(j(Z0))}catch(F0){}}return null}function H(j){if(j===q0)return"<>";if(typeof j==="object"&&j!==null&&j.$$typeof===a0)return"<...>";try{var Z0=M(j);return Z0?"<"+Z0+">":"<...>"}catch(F0){return"<...>"}}function O(){var j=W1.A;return j===null?null:j.getOwner()}function _(){return Error("react-stack-top-frame")}function A(j){if(N4.call(j,"key")){var Z0=Object.getOwnPropertyDescriptor(j,"key").get;if(Z0&&Z0.isReactWarning)return!1}return j.key!==void 0}function P(j,Z0){function F0(){L6||(L6=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",Z0))}F0.isReactWarning=!0,Object.defineProperty(j,"key",{get:F0,configurable:!0})}function L(){var j=M(this.type);return d4[j]||(d4[j]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),j=this.props.ref,j!==void 0?j:null}function v(j,Z0,F0,T0,x0,Y1){var f0=F0.ref;return j={$$typeof:$0,type:j,key:Z0,props:F0,_owner:T0},(f0!==void 0?f0:null)!==null?Object.defineProperty(j,"ref",{enumerable:!1,get:L}):Object.defineProperty(j,"ref",{enumerable:!1,value:null}),j._store={},Object.defineProperty(j._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(j,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(j,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:x0}),Object.defineProperty(j,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:Y1}),Object.freeze&&(Object.freeze(j.props),Object.freeze(j)),j}function R(j,Z0){return Z0=v(j.type,Z0,j.props,j._owner,j._debugStack,j._debugTask),j._store&&(Z0._store.validated=j._store.validated),Z0}function T(j){C(j)?j._store&&(j._store.validated=1):typeof j==="object"&&j!==null&&j.$$typeof===a0&&(j._payload.status==="fulfilled"?C(j._payload.value)&&j._payload.value._store&&(j._payload.value._store.validated=1):j._store&&(j._store.validated=1))}function C(j){return typeof j==="object"&&j!==null&&j.$$typeof===$0}function y(j){var Z0={"=":"=0",":":"=2"};return"$"+j.replace(/[=:]/g,function(F0){return Z0[F0]})}function b(j,Z0){return typeof j==="object"&&j!==null&&j.key!=null?(U(j.key),y(""+j.key)):Z0.toString(36)}function S(j){switch(j.status){case"fulfilled":return j.value;case"rejected":throw j.reason;default:switch(typeof j.status==="string"?j.then(W,W):(j.status="pending",j.then(function(Z0){j.status==="pending"&&(j.status="fulfilled",j.value=Z0)},function(Z0){j.status==="pending"&&(j.status="rejected",j.reason=Z0)})),j.status){case"fulfilled":return j.value;case"rejected":throw j.reason}}throw j}function I(j,Z0,F0,T0,x0){var Y1=typeof j;if(Y1==="undefined"||Y1==="boolean")j=null;var f0=!1;if(j===null)f0=!0;else switch(Y1){case"bigint":case"string":case"number":f0=!0;break;case"object":switch(j.$$typeof){case $0:case e:f0=!0;break;case a0:return f0=j._init,I(f0(j._payload),Z0,F0,T0,x0)}}if(f0){f0=j,x0=x0(f0);var Q1=T0===""?"."+b(f0,0):T0;return H1(x0)?(F0="",Q1!=null&&(F0=Q1.replace(Y7,"$&/")+"/"),I(x0,Z0,F0,"",function(_5){return _5})):x0!=null&&(C(x0)&&(x0.key!=null&&(f0&&f0.key===x0.key||U(x0.key)),F0=R(x0,F0+(x0.key==null||f0&&f0.key===x0.key?"":(""+x0.key).replace(Y7,"$&/")+"/")+Q1),T0!==""&&f0!=null&&C(f0)&&f0.key==null&&f0._store&&!f0._store.validated&&(F0._store.validated=2),x0=F0),Z0.push(x0)),1}if(f0=0,Q1=T0===""?".":T0+":",H1(j))for(var j0=0;j0 import('./MyComponent')) -Did you accidentally put curly braces around the import?`,Y0),"default"in Y0||console.error(`lazy: Expected the result of a dynamic import() call. Instead received: %s +Did you accidentally put curly braces around the import?`,Z0),"default"in Z0||console.error(`lazy: Expected the result of a dynamic import() call. Instead received: %s Your code should look like: - const MyComponent = lazy(() => import('./MyComponent'))`,Y0),Y0.default;throw j._result}function k(){var j=W1.H;return j===null&&console.error(`Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: + const MyComponent = lazy(() => import('./MyComponent'))`,Z0),Z0.default;throw j._result}function k(){var j=W1.H;return j===null&&console.error(`Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: 1. You might have mismatching versions of React and the renderer (such as React DOM) 2. You might be breaking the Rules of Hooks 3. You might have more than one copy of React in the same app -See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.`),j}function o(){W1.asyncTransitions--}function q0(j){if(O4===null)try{var Y0=("require"+Math.random()).slice(0,7);O4=(YU&&YU[Y0]).call(YU,"timers").setImmediate}catch(A0){O4=function(T0){$2===!1&&($2=!0,typeof MessageChannel>"u"&&console.error("This browser does not have a MessageChannel implementation, so enqueuing tasks via await act(async () => ...) will fail. Please file an issue at https://github.com/facebook/react/issues if you encounter this warning."));var k0=new MessageChannel;k0.port1.onmessage=T0,k0.port2.postMessage(void 0)}}return O4(j)}function $0(j){return 1 ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);"))}),{then:function(y0,_5){k0=!0,f0.then(function(K5){if(w0(Y0,A0),A0===0){try{X0(T0),q0(function(){return e(K5,y0,_5)})}catch(e5){W1.thrownErrors.push(e5)}if(0 ...)"))}),W1.actQueue=null),0W1.recentlyCreatedOwnerStacks++;return v(j,k0,T0,O(),y0?Error("react-stack-top-frame"):x2,y0?S1(H(j)):L6)},va.createRef=function(){var j={current:null};return Object.seal(j),j},va.forwardRef=function(j){j!=null&&j.$$typeof===p0?console.error("forwardRef requires a render function but received a `memo` component. Instead of forwardRef(memo(...)), use memo(forwardRef(...))."):typeof j!=="function"?console.error("forwardRef requires a render function but was given %s.",j===null?"null":typeof j):j.length!==0&&j.length!==2&&console.error("forwardRef render functions accept exactly two parameters: props and ref. %s",j.length===1?"Did you forget to use the ref parameter?":"Any additional parameter will be undefined."),j!=null&&j.defaultProps!=null&&console.error("forwardRef render functions do not support defaultProps. Did you accidentally pass a React component?");var Y0={$$typeof:L0,render:j},A0;return Object.defineProperty(Y0,"displayName",{enumerable:!1,configurable:!0,get:function(){return A0},set:function(T0){A0=T0,j.name||j.displayName||(Object.defineProperty(j,"name",{value:T0}),j.displayName=T0)}}),Y0},va.isValidElement=C,va.lazy=function(j){j={_status:-1,_result:j};var Y0={$$typeof:i0,_payload:j,_init:l},A0={name:"lazy",start:-1,end:-1,value:null,owner:null,debugStack:Error("react-stack-top-frame"),debugTask:console.createTask?console.createTask("lazy()"):null};return j._ioInfo=A0,Y0._debugInfo=[{awaited:A0}],Y0},va.memo=function(j,Y0){j==null&&console.error("memo: The first argument must be a component. Instead received: %s",j===null?"null":typeof j),Y0={$$typeof:p0,type:j,compare:Y0===void 0?null:Y0};var A0;return Object.defineProperty(Y0,"displayName",{enumerable:!1,configurable:!0,get:function(){return A0},set:function(T0){A0=T0,j.name||j.displayName||(Object.defineProperty(j,"name",{value:T0}),j.displayName=T0)}}),Y0},va.startTransition=function(j){var Y0=W1.T,A0={};A0._updatedFibers=new Set,W1.T=A0;try{var T0=j(),k0=W1.S;k0!==null&&k0(A0,T0),typeof T0==="object"&&T0!==null&&typeof T0.then==="function"&&(W1.asyncTransitions++,T0.then(o,o),T0.then(W,C5))}catch(Y1){C5(Y1)}finally{Y0===null&&A0._updatedFibers&&(j=A0._updatedFibers.size,A0._updatedFibers.clear(),10{(function(){function Z(){if(y=!1,g){var e=Ca.unstable_now();o=e;var X0=!0;try{Z:{T=!1,C&&(C=!1,S(l),l=-1),R=!0;var G0=v;try{Y:{B(e);for(L=Q(_);L!==null&&!(L.expirationTime>e&&$());){var Z0=L.callback;if(typeof Z0==="function"){L.callback=null,v=L.priorityLevel;var K0=Z0(L.expirationTime<=e);if(e=Ca.unstable_now(),typeof K0==="function"){L.callback=K0,B(e),X0=!0;break Y}L===Q(_)&&z(_),B(e)}else z(_);L=Q(_)}if(L!==null)X0=!0;else{var f=Q(A);f!==null&&U(W,f.startTime-e),X0=!1}}break Z}finally{L=null,v=G0,R=!1}X0=void 0}}finally{X0?q0():g=!1}}}function Y(e,X0){var G0=e.length;e.push(X0);Z:for(;0>>1,K0=e[Z0];if(0>>1;Z0q(i,G0))nq(L0,i)?(e[Z0]=L0,e[n]=G0,Z0=n):(e[Z0]=i,e[z0]=G0,Z0=z0);else if(nq(L0,G0))e[Z0]=L0,e[n]=G0,Z0=n;else break Z}}return X0}function q(e,X0){var G0=e.sortIndex-X0.sortIndex;return G0!==0?G0:e.id-X0.id}function B(e){for(var X0=Q(A);X0!==null;){if(X0.callback===null)z(A);else if(X0.startTime<=e)z(A),X0.sortIndex=X0.expirationTime,Y(_,X0);else break;X0=Q(A)}}function W(e){if(C=!1,B(e),!T)if(Q(_)!==null)T=!0,g||(g=!0,q0());else{var X0=Q(A);X0!==null&&U(W,X0.startTime-e)}}function $(){return y?!0:Ca.unstable_now()-oe||125Z0?(e.sortIndex=G0,Y(A,e),Q(_)===null&&e===Q(A)&&(C?(S(l),l=-1):C=!0,U(W,G0-Z0))):(e.sortIndex=K0,Y(_,e),T||R||(T=!0,g||(g=!0,q0()))),e},Ca.unstable_shouldYield=$,Ca.unstable_wrapCallback=function(e){var X0=v;return function(){var G0=v;v=X0;try{return e.apply(this,arguments)}finally{v=G0}}},typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop==="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error())})()});var dI=D3((Da)=>{var dA=h(J0());(function(){function Z(){}function Y(H){return""+H}function Q(H,O,_){var A=3"u"&&console.error("This browser does not have a MessageChannel implementation, so enqueuing tasks via await act(async () => ...) will fail. Please file an issue at https://github.com/facebook/react/issues if you encounter this warning."));var x0=new MessageChannel;x0.port1.onmessage=T0,x0.port2.postMessage(void 0)}}return O4(j)}function W0(j){return 1 ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);"))}),{then:function(j0,_5){x0=!0,f0.then(function(K5){if(w0(Z0,F0),F0===0){try{Q0(T0),X0(function(){return n(K5,j0,_5)})}catch(e5){W1.thrownErrors.push(e5)}if(0 ...)"))}),W1.actQueue=null),0W1.recentlyCreatedOwnerStacks++;return v(j,x0,T0,O(),j0?Error("react-stack-top-frame"):f2,j0?S1(H(j)):R6)},va.createRef=function(){var j={current:null};return Object.seal(j),j},va.forwardRef=function(j){j!=null&&j.$$typeof===u0?console.error("forwardRef requires a render function but received a `memo` component. Instead of forwardRef(memo(...)), use memo(forwardRef(...))."):typeof j!=="function"?console.error("forwardRef requires a render function but was given %s.",j===null?"null":typeof j):j.length!==0&&j.length!==2&&console.error("forwardRef render functions accept exactly two parameters: props and ref. %s",j.length===1?"Did you forget to use the ref parameter?":"Any additional parameter will be undefined."),j!=null&&j.defaultProps!=null&&console.error("forwardRef render functions do not support defaultProps. Did you accidentally pass a React component?");var Z0={$$typeof:H0,render:j},F0;return Object.defineProperty(Z0,"displayName",{enumerable:!1,configurable:!0,get:function(){return F0},set:function(T0){F0=T0,j.name||j.displayName||(Object.defineProperty(j,"name",{value:T0}),j.displayName=T0)}}),Z0},va.isValidElement=C,va.lazy=function(j){j={_status:-1,_result:j};var Z0={$$typeof:a0,_payload:j,_init:l},F0={name:"lazy",start:-1,end:-1,value:null,owner:null,debugStack:Error("react-stack-top-frame"),debugTask:console.createTask?console.createTask("lazy()"):null};return j._ioInfo=F0,Z0._debugInfo=[{awaited:F0}],Z0},va.memo=function(j,Z0){j==null&&console.error("memo: The first argument must be a component. Instead received: %s",j===null?"null":typeof j),Z0={$$typeof:u0,type:j,compare:Z0===void 0?null:Z0};var F0;return Object.defineProperty(Z0,"displayName",{enumerable:!1,configurable:!0,get:function(){return F0},set:function(T0){F0=T0,j.name||j.displayName||(Object.defineProperty(j,"name",{value:T0}),j.displayName=T0)}}),Z0},va.startTransition=function(j){var Z0=W1.T,F0={};F0._updatedFibers=new Set,W1.T=F0;try{var T0=j(),x0=W1.S;x0!==null&&x0(F0,T0),typeof T0==="object"&&T0!==null&&typeof T0.then==="function"&&(W1.asyncTransitions++,T0.then(i,i),T0.then(W,C5))}catch(Y1){C5(Y1)}finally{Z0===null&&F0._updatedFibers&&(j=F0._updatedFibers.size,F0._updatedFibers.clear(),10{(function(){function Z(){if(y=!1,g){var n=Ca.unstable_now();i=n;var Q0=!0;try{Z:{T=!1,C&&(C=!1,S(l),l=-1),R=!0;var $0=v;try{Y:{B(n);for(L=Q(_);L!==null&&!(L.expirationTime>n&&$());){var e=L.callback;if(typeof e==="function"){L.callback=null,v=L.priorityLevel;var q0=e(L.expirationTime<=n);if(n=Ca.unstable_now(),typeof q0==="function"){L.callback=q0,B(n),Q0=!0;break Y}L===Q(_)&&z(_),B(n)}else z(_);L=Q(_)}if(L!==null)Q0=!0;else{var f=Q(A);f!==null&&U(W,f.startTime-n),Q0=!1}}break Z}finally{L=null,v=$0,R=!1}Q0=void 0}}finally{Q0?X0():g=!1}}}function Y(n,Q0){var $0=n.length;n.push(Q0);Z:for(;0<$0;){var e=$0-1>>>1,q0=n[e];if(0>>1;eq(N0,$0))sq(H0,N0)?(n[e]=H0,n[s]=$0,e=s):(n[e]=N0,n[z0]=$0,e=z0);else if(sq(H0,$0))n[e]=H0,n[s]=$0,e=s;else break Z}}return Q0}function q(n,Q0){var $0=n.sortIndex-Q0.sortIndex;return $0!==0?$0:n.id-Q0.id}function B(n){for(var Q0=Q(A);Q0!==null;){if(Q0.callback===null)z(A);else if(Q0.startTime<=n)z(A),Q0.sortIndex=Q0.expirationTime,Y(_,Q0);else break;Q0=Q(A)}}function W(n){if(C=!1,B(n),!T)if(Q(_)!==null)T=!0,g||(g=!0,X0());else{var Q0=Q(A);Q0!==null&&U(W,Q0.startTime-n)}}function $(){return y?!0:Ca.unstable_now()-in||125e?(n.sortIndex=$0,Y(A,n),Q(_)===null&&n===Q(A)&&(C?(S(l),l=-1):C=!0,U(W,$0-e))):(n.sortIndex=q0,Y(_,n),T||R||(T=!0,g||(g=!0,X0()))),n},Ca.unstable_shouldYield=$,Ca.unstable_wrapCallback=function(n){var Q0=v;return function(){var $0=v;v=Q0;try{return n.apply(this,arguments)}finally{v=$0}}},typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop==="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error())})()});var dI=b3((Da)=>{var cA=h(Y0());(function(){function Z(){}function Y(H){return""+H}function Q(H,O,_){var A=3` tag.%s',_),typeof H==="string"&&typeof O==="object"&&O!==null&&typeof O.as==="string"){_=O.as;var A=z(_,O.crossOrigin);$.d.L(H,_,{crossOrigin:A,integrity:typeof O.integrity==="string"?O.integrity:void 0,nonce:typeof O.nonce==="string"?O.nonce:void 0,type:typeof O.type==="string"?O.type:void 0,fetchPriority:typeof O.fetchPriority==="string"?O.fetchPriority:void 0,referrerPolicy:typeof O.referrerPolicy==="string"?O.referrerPolicy:void 0,imageSrcSet:typeof O.imageSrcSet==="string"?O.imageSrcSet:void 0,imageSizes:typeof O.imageSizes==="string"?O.imageSizes:void 0,media:typeof O.media==="string"?O.media:void 0})}},Da.preloadModule=function(H,O){var _="";typeof H==="string"&&H||(_+=" The `href` argument encountered was "+q(H)+"."),O!==void 0&&typeof O!=="object"?_+=" The `options` argument encountered was "+q(O)+".":O&&("as"in O)&&typeof O.as!=="string"&&(_+=" The `as` option encountered was "+q(O.as)+"."),_&&console.error('ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `` tag.%s',_),typeof H==="string"&&(O?(_=z(O.as,O.crossOrigin),$.d.m(H,{as:typeof O.as==="string"&&O.as!=="script"?O.as:void 0,crossOrigin:_,integrity:typeof O.integrity==="string"?O.integrity:void 0})):$.d.m(H))},Da.requestFormReset=function(H){$.d.r(H)},Da.unstable_batchedUpdates=function(H,O){return H(O)},Da.useFormState=function(H,O,_){return W().useFormState(H,O,_)},Da.useFormStatus=function(){return W().useHostTransitionStatus()},Da.version="19.2.4",typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop==="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error())})()});var b3=D3((hQ0,lI)=>{var ba=h(dI());lI.exports=ba});var rI=D3((Ea)=>{var a1=h(cI()),oQ=h(J0()),lA=h(b3());(function(){function Z(J,X){for(J=J.memoizedState;J!==null&&0=X.length)return G;var w=X[K],N=T2(J)?J.slice():E1({},J);return N[w]=Y(J[w],X,K+1,G),N}function Q(J,X,K){if(X.length!==K.length)console.warn("copyWithRename() expects paths of the same length");else{for(var G=0;GA8?console.error("Unexpected pop."):(X!==V_[A8]&&console.error("Unexpected Fiber popped."),J.current=P_[A8],P_[A8]=null,V_[A8]=null,A8--)}function $0(J,X,K){A8++,P_[A8]=J.current,V_[A8]=K,J.current=X}function w0(J){return J===null&&console.error("Expected host context to exist. This error is likely caused by a bug in React. Please file an issue."),J}function e(J,X){$0(y9,X,J),$0(sq,J,J),$0(I9,null,J);var K=X.nodeType;switch(K){case 9:case 11:K=K===9?"#document":"#fragment",X=(X=X.documentElement)?(X=X.namespaceURI)?vD(X):j8:j8;break;default:if(K=X.tagName,X=X.namespaceURI)X=vD(X),X=CD(X,K);else switch(K){case"svg":X=aQ;break;case"math":X=sG;break;default:X=j8}}K=K.toLowerCase(),K=FT(null,K),K={context:X,ancestorInfo:K},q0(I9,J),$0(I9,K,J)}function X0(J){q0(I9,J),q0(sq,J),q0(y9,J)}function G0(){return w0(I9.current)}function Z0(J){J.memoizedState!==null&&$0(t$,J,J);var X=w0(I9.current),K=J.type,G=CD(X.context,K);K=FT(X.ancestorInfo,K),G={context:G,ancestorInfo:K},X!==G&&($0(sq,J,J),$0(I9,G,J))}function K0(J){sq.current===J&&(q0(I9,J),q0(sq,J)),t$.current===J&&(q0(t$,J),gK._currentValue=bY)}function f(){}function z0(){if(oq===0){Qb=console.log,Xb=console.info,zb=console.warn,qb=console.error,Kb=console.group,Bb=console.groupCollapsed,Wb=console.groupEnd;var J={configurable:!0,enumerable:!0,value:f,writable:!0};Object.defineProperties(console,{info:J,log:J,warn:J,error:J,group:J,groupCollapsed:J,groupEnd:J})}oq++}function i(){if(oq--,oq===0){var J={configurable:!0,enumerable:!0,writable:!0};Object.defineProperties(console,{log:E1({},J,{value:Qb}),info:E1({},J,{value:Xb}),warn:E1({},J,{value:zb}),error:E1({},J,{value:qb}),group:E1({},J,{value:Kb}),groupCollapsed:E1({},J,{value:Bb}),groupEnd:E1({},J,{value:Wb})})}0>oq&&console.error("disabledDepth fell below zero. This is a bug in React. Please file an issue.")}function n(J){var X=Error.prepareStackTrace;if(Error.prepareStackTrace=void 0,J=J.stack,Error.prepareStackTrace=X,J.startsWith(`Error: react-stack-top-frame +See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.`),H}typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart==="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());var $={d:{f:Z,r:function(){throw Error("Invalid form element. requestFormReset must be passed a form that was rendered by React.")},D:Z,C:Z,L:Z,m:Z,X:Z,S:Z,M:Z},p:0,findDOMNode:null},U=Symbol.for("react.portal"),M=cA.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;typeof Map==="function"&&Map.prototype!=null&&typeof Map.prototype.forEach==="function"&&typeof Set==="function"&&Set.prototype!=null&&typeof Set.prototype.clear==="function"&&typeof Set.prototype.forEach==="function"||console.error("React depends on Map and Set built-in types. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"),Da.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=$,Da.createPortal=function(H,O){var _=2` tag.%s',_),typeof H==="string"&&typeof O==="object"&&O!==null&&typeof O.as==="string"){_=O.as;var A=z(_,O.crossOrigin);$.d.L(H,_,{crossOrigin:A,integrity:typeof O.integrity==="string"?O.integrity:void 0,nonce:typeof O.nonce==="string"?O.nonce:void 0,type:typeof O.type==="string"?O.type:void 0,fetchPriority:typeof O.fetchPriority==="string"?O.fetchPriority:void 0,referrerPolicy:typeof O.referrerPolicy==="string"?O.referrerPolicy:void 0,imageSrcSet:typeof O.imageSrcSet==="string"?O.imageSrcSet:void 0,imageSizes:typeof O.imageSizes==="string"?O.imageSizes:void 0,media:typeof O.media==="string"?O.media:void 0})}},Da.preloadModule=function(H,O){var _="";typeof H==="string"&&H||(_+=" The `href` argument encountered was "+q(H)+"."),O!==void 0&&typeof O!=="object"?_+=" The `options` argument encountered was "+q(O)+".":O&&("as"in O)&&typeof O.as!=="string"&&(_+=" The `as` option encountered was "+q(O.as)+"."),_&&console.error('ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `` tag.%s',_),typeof H==="string"&&(O?(_=z(O.as,O.crossOrigin),$.d.m(H,{as:typeof O.as==="string"&&O.as!=="script"?O.as:void 0,crossOrigin:_,integrity:typeof O.integrity==="string"?O.integrity:void 0})):$.d.m(H))},Da.requestFormReset=function(H){$.d.r(H)},Da.unstable_batchedUpdates=function(H,O){return H(O)},Da.useFormState=function(H,O,_){return W().useFormState(H,O,_)},Da.useFormStatus=function(){return W().useHostTransitionStatus()},Da.version="19.2.4",typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop==="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error())})()});var E3=b3((hQ0,lI)=>{var ba=h(dI());lI.exports=ba});var rI=b3((Ea)=>{var a1=h(cI()),oQ=h(Y0()),dA=h(E3());(function(){function Z(J,X){for(J=J.memoizedState;J!==null&&0=X.length)return G;var w=X[K],N=T2(J)?J.slice():E1({},J);return N[w]=Y(J[w],X,K+1,G),N}function Q(J,X,K){if(X.length!==K.length)console.warn("copyWithRename() expects paths of the same length");else{for(var G=0;GA8?console.error("Unexpected pop."):(X!==P_[A8]&&console.error("Unexpected Fiber popped."),J.current=F_[A8],F_[A8]=null,P_[A8]=null,A8--)}function W0(J,X,K){A8++,F_[A8]=J.current,P_[A8]=K,J.current=X}function w0(J){return J===null&&console.error("Expected host context to exist. This error is likely caused by a bug in React. Please file an issue."),J}function n(J,X){W0(j9,X,J),W0(sq,J,J),W0(y9,null,J);var K=X.nodeType;switch(K){case 9:case 11:K=K===9?"#document":"#fragment",X=(X=X.documentElement)?(X=X.namespaceURI)?vD(X):j8:j8;break;default:if(K=X.tagName,X=X.namespaceURI)X=vD(X),X=CD(X,K);else switch(K){case"svg":X=aQ;break;case"math":X=sG;break;default:X=j8}}K=K.toLowerCase(),K=FT(null,K),K={context:X,ancestorInfo:K},X0(y9,J),W0(y9,K,J)}function Q0(J){X0(y9,J),X0(sq,J),X0(j9,J)}function $0(){return w0(y9.current)}function e(J){J.memoizedState!==null&&W0(t$,J,J);var X=w0(y9.current),K=J.type,G=CD(X.context,K);K=FT(X.ancestorInfo,K),G={context:G,ancestorInfo:K},X!==G&&(W0(sq,J,J),W0(y9,G,J))}function q0(J){sq.current===J&&(X0(y9,J),X0(sq,J)),t$.current===J&&(X0(t$,J),gK._currentValue=IY)}function f(){}function z0(){if(oq===0){Qb=console.log,Xb=console.info,zb=console.warn,qb=console.error,Kb=console.group,Bb=console.groupCollapsed,Wb=console.groupEnd;var J={configurable:!0,enumerable:!0,value:f,writable:!0};Object.defineProperties(console,{info:J,log:J,warn:J,error:J,group:J,groupCollapsed:J,groupEnd:J})}oq++}function N0(){if(oq--,oq===0){var J={configurable:!0,enumerable:!0,writable:!0};Object.defineProperties(console,{log:E1({},J,{value:Qb}),info:E1({},J,{value:Xb}),warn:E1({},J,{value:zb}),error:E1({},J,{value:qb}),group:E1({},J,{value:Kb}),groupCollapsed:E1({},J,{value:Bb}),groupEnd:E1({},J,{value:Wb})})}0>oq&&console.error("disabledDepth fell below zero. This is a bug in React. Please file an issue.")}function s(J){var X=Error.prepareStackTrace;if(Error.prepareStackTrace=void 0,J=J.stack,Error.prepareStackTrace=X,J.startsWith(`Error: react-stack-top-frame `)&&(J=J.slice(29)),X=J.indexOf(` `),X!==-1&&(J=J.slice(X+1)),X=J.indexOf("react_stack_bottom_frame"),X!==-1&&(X=J.lastIndexOf(` -`,X)),X!==-1)J=J.slice(0,X);else return"";return J}function L0(J){if(L_===void 0)try{throw Error()}catch(K){var X=K.stack.trim().match(/\n( *(at )?)/);L_=X&&X[1]||"",$b=-1)":-1F||E[N]!==a[F]){var s=` -`+E[N].replace(" at new "," at ");return J.displayName&&s.includes("")&&(s=s.replace("",J.displayName)),typeof J==="function"&&T_.set(J,s),s}while(1<=N&&0<=F);break}}}finally{R_=!1,M0.H=G,i(),Error.prepareStackTrace=K}return E=(E=J?J.displayName||J.name:"")?L0(E):"",typeof J==="function"&&T_.set(J,E),E}function H0(J,X){switch(J.tag){case 26:case 27:case 5:return L0(J.type);case 16:return L0("Lazy");case 13:return J.child!==X&&X!==null?L0("Suspense Fallback"):L0("Suspense");case 19:return L0("SuspenseList");case 0:case 15:return x0(J.type,!1);case 11:return x0(J.type.render,!1);case 1:return x0(J.type,!0);case 31:return L0("Activity");default:return""}}function p0(J){try{var X="",K=null;do{X+=H0(J,K);var G=J._debugInfo;if(G)for(var w=G.length-1;0<=w;w--){var N=G[w];if(typeof N.name==="string"){var F=X;Z:{var{name:V,env:D,debugLocation:E}=N;if(E!=null){var a=n(E),s=a.lastIndexOf(` -`),c=s===-1?a:a.slice(s+1);if(c.indexOf(V)!==-1){var B0=` -`+c;break Z}}B0=L0(V+(D?" ["+D+"]":""))}X=F+B0}}K=J,J=J.return}while(J);return X}catch(v0){return` +`);for(F=N=0;NF||E[N]!==a[F]){var o=` +`+E[N].replace(" at new "," at ");return J.displayName&&o.includes("")&&(o=o.replace("",J.displayName)),typeof J==="function"&&R_.set(J,o),o}while(1<=N&&0<=F);break}}}finally{L_=!1,M0.H=G,N0(),Error.prepareStackTrace=K}return E=(E=J?J.displayName||J.name:"")?H0(E):"",typeof J==="function"&&R_.set(J,E),E}function U0(J,X){switch(J.tag){case 26:case 27:case 5:return H0(J.type);case 16:return H0("Lazy");case 13:return J.child!==X&&X!==null?H0("Suspense Fallback"):H0("Suspense");case 19:return H0("SuspenseList");case 0:case 15:return y0(J.type,!1);case 11:return y0(J.type.render,!1);case 1:return y0(J.type,!0);case 31:return H0("Activity");default:return""}}function u0(J){try{var X="",K=null;do{X+=U0(J,K);var G=J._debugInfo;if(G)for(var w=G.length-1;0<=w;w--){var N=G[w];if(typeof N.name==="string"){var F=X;Z:{var{name:V,env:D,debugLocation:E}=N;if(E!=null){var a=s(E),o=a.lastIndexOf(` +`),c=o===-1?a:a.slice(o+1);if(c.indexOf(V)!==-1){var K0=` +`+c;break Z}}K0=H0(V+(D?" ["+D+"]":""))}X=F+K0}}K=J,J=J.return}while(J);return X}catch(v0){return` Error generating stack: `+v0.message+` -`+v0.stack}}function i0(J){return(J=J?J.displayName||J.name:"")?L0(J):""}function R1(){if(v4===null)return null;var J=v4._debugOwner;return J!=null?l(J):null}function B1(){if(v4===null)return"";var J=v4;try{var X="";switch(J.tag===6&&(J=J.return),J.tag){case 26:case 27:case 5:X+=L0(J.type);break;case 13:X+=L0("Suspense");break;case 19:X+=L0("SuspenseList");break;case 31:X+=L0("Activity");break;case 30:case 0:case 15:case 1:J._debugOwner||X!==""||(X+=i0(J.type));break;case 11:J._debugOwner||X!==""||(X+=i0(J.type.render))}for(;J;)if(typeof J.tag==="number"){var K=J;J=K._debugOwner;var G=K._debugStack;if(J&&G){var w=n(G);w!==""&&(X+=` +`+v0.stack}}function a0(J){return(J=J?J.displayName||J.name:"")?H0(J):""}function _1(){if(v4===null)return null;var J=v4._debugOwner;return J!=null?l(J):null}function B1(){if(v4===null)return"";var J=v4;try{var X="";switch(J.tag===6&&(J=J.return),J.tag){case 26:case 27:case 5:X+=H0(J.type);break;case 13:X+=H0("Suspense");break;case 19:X+=H0("SuspenseList");break;case 31:X+=H0("Activity");break;case 30:case 0:case 15:case 1:J._debugOwner||X!==""||(X+=a0(J.type));break;case 11:J._debugOwner||X!==""||(X+=a0(J.type.render))}for(;J;)if(typeof J.tag==="number"){var K=J;J=K._debugOwner;var G=K._debugStack;if(J&&G){var w=s(G);w!==""&&(X+=` `+w)}}else if(J.debugStack!=null){var N=J.debugStack;(J=J.owner)&&N&&(X+=` -`+n(N))}else break;var F=X}catch(V){F=` +`+s(N))}else break;var F=X}catch(V){F=` Error generating stack: `+V.message+` -`+V.stack}return F}function R0(J,X,K,G,w,N,F){var V=v4;C1(J);try{return J!==null&&J._debugTask?J._debugTask.run(X.bind(null,K,G,w,N,F)):X(K,G,w,N,F)}finally{C1(V)}throw Error("runWithFiberInDEV should never be called in production. This is a bug in React.")}function C1(J){M0.getCurrentStack=J===null?null:B1,_3=!1,v4=J}function X5(J){return typeof Symbol==="function"&&Symbol.toStringTag&&J[Symbol.toStringTag]||J.constructor.name||"Object"}function n5(J){try{return O5(J),!1}catch(X){return!0}}function O5(J){return""+J}function H1(J,X){if(n5(J))return console.error("The provided `%s` attribute is an unsupported type %s. This value must be coerced to a string before using it here.",X,X5(J)),O5(J)}function t6(J,X){if(n5(J))return console.error("The provided `%s` CSS property is an unsupported type %s. This value must be coerced to a string before using it here.",X,X5(J)),O5(J)}function W1(J){if(n5(J))return console.error("Form field values (value, checked, defaultValue, or defaultChecked props) must be strings, not %s. This value must be coerced to a string before using it here.",X5(J)),O5(J)}function N4(J){if(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u")return!1;var X=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(X.isDisabled)return!0;if(!X.supportsFiber)return console.error("The installed version of React DevTools is too old and will not work with the current version of React. Please update React DevTools. https://react.dev/link/react-devtools"),!0;try{HQ=X.inject(J),F7=X}catch(K){console.error("React instrumentation encountered an error: %o.",K)}return X.checkDCE?!0:!1}function S1(J){if(typeof cl==="function"&&dl(J),F7&&typeof F7.setStrictMode==="function")try{F7.setStrictMode(HQ,J)}catch(X){A3||(A3=!0,console.error("React instrumentation encountered an error: %o",X))}}function V6(J){return J>>>=0,J===0?32:31-(ll(J)/rl|0)|0}function Z7(J){var X=J&42;if(X!==0)return X;switch(J&-J){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return J&261888;case 262144:case 524288:case 1048576:case 2097152:return J&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return J&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return console.error("Should have found matching lanes. This is a bug in React."),J}}function d4(J,X,K){var G=J.pendingLanes;if(G===0)return 0;var w=0,N=J.suspendedLanes,F=J.pingedLanes;J=J.warmLanes;var V=G&134217727;return V!==0?(G=V&~N,G!==0?w=Z7(G):(F&=V,F!==0?w=Z7(F):K||(K=V&~J,K!==0&&(w=Z7(K))))):(V=G&~N,V!==0?w=Z7(V):F!==0?w=Z7(F):K||(K=G&~J,K!==0&&(w=Z7(K)))),w===0?0:X!==0&&X!==w&&(X&N)===0&&(N=w&-w,K=X&-X,N>=K||N===32&&(K&4194048)!==0)?X:w}function x2(J,X){return(J.pendingLanes&~(J.suspendedLanes&~J.pingedLanes)&X)===0}function L6(J,X){switch(J){case 1:case 2:case 4:case 8:case 64:return X+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return X+5000;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return console.error("Should have found matching lanes. This is a bug in React."),-1}}function R6(){var J=ZG;return ZG<<=1,(ZG&62914560)===0&&(ZG=4194304),J}function Y7(J){for(var X=[],K=0;31>K;K++)X.push(J);return X}function C5(J,X){J.pendingLanes|=X,X!==268435456&&(J.suspendedLanes=0,J.pingedLanes=0,J.warmLanes=0)}function $2(J,X,K,G,w,N){var F=J.pendingLanes;J.pendingLanes=K,J.suspendedLanes=0,J.pingedLanes=0,J.warmLanes=0,J.expiredLanes&=K,J.entangledLanes&=K,J.errorRecoveryDisabledLanes&=K,J.shellSuspendCounter=0;var{entanglements:V,expirationTimes:D,hiddenUpdates:E}=J;for(K=F&~K;0"u")return null;try{return J.activeElement||J.body}catch(X){return J.body}}function S0(J){return J.replace(tl,function(X){return"\\"+X.charCodeAt(0).toString(16)+" "})}function l0(J,X){X.checked===void 0||X.defaultChecked===void 0||Nb||(console.error("%s contains an input of type %s with both checked and defaultChecked props. Input elements must be either controlled or uncontrolled (specify either the checked prop, or the defaultChecked prop, but not both). Decide between using a controlled or uncontrolled input element and remove one of these props. More info: https://react.dev/link/controlled-components",R1()||"A component",X.type),Nb=!0),X.value===void 0||X.defaultValue===void 0||Hb||(console.error("%s contains an input of type %s with both value and defaultValue props. Input elements must be either controlled or uncontrolled (specify either the value prop, or the defaultValue prop, but not both). Decide between using a controlled or uncontrolled input element and remove one of these props. More info: https://react.dev/link/controlled-components",R1()||"A component",X.type),Hb=!0)}function a0(J,X,K,G,w,N,F,V){if(J.name="",F!=null&&typeof F!=="function"&&typeof F!=="symbol"&&typeof F!=="boolean"?(H1(F,"type"),J.type=F):J.removeAttribute("type"),X!=null)if(F==="number"){if(X===0&&J.value===""||J.value!=X)J.value=""+t(X)}else J.value!==""+t(X)&&(J.value=""+t(X));else F!=="submit"&&F!=="reset"||J.removeAttribute("value");X!=null?r0(J,F,t(X)):K!=null?r0(J,F,t(K)):G!=null&&J.removeAttribute("value"),w==null&&N!=null&&(J.defaultChecked=!!N),w!=null&&(J.checked=w&&typeof w!=="function"&&typeof w!=="symbol"),V!=null&&typeof V!=="function"&&typeof V!=="symbol"&&typeof V!=="boolean"?(H1(V,"name"),J.name=""+t(V)):J.removeAttribute("name")}function J1(J,X,K,G,w,N,F,V){if(N!=null&&typeof N!=="function"&&typeof N!=="symbol"&&typeof N!=="boolean"&&(H1(N,"type"),J.type=N),X!=null||K!=null){if(!(N!=="submit"&&N!=="reset"||X!==void 0&&X!==null)){P0(J);return}K=K!=null?""+t(K):"",X=X!=null?""+t(X):K,V||X===J.value||(J.value=X),J.defaultValue=X}G=G!=null?G:w,G=typeof G!=="function"&&typeof G!=="symbol"&&!!G,J.checked=V?J.checked:!!G,J.defaultChecked=!!G,F!=null&&typeof F!=="function"&&typeof F!=="symbol"&&typeof F!=="boolean"&&(H1(F,"name"),J.name=F),P0(J)}function r0(J,X,K){X==="number"&&j0(J.ownerDocument)===J||J.defaultValue===""+K||(J.defaultValue=""+K)}function p1(J,X){X.value==null&&(typeof X.children==="object"&&X.children!==null?oQ.Children.forEach(X.children,function(K){K==null||typeof K==="string"||typeof K==="number"||typeof K==="bigint"||_b||(_b=!0,console.error("Cannot infer the option value of complex children. Pass a `value` prop or use a plain string as children to