From e5dfb96351d53a45e90e8d4690046a7fcd9b8ffb Mon Sep 17 00:00:00 2001 From: maziggy Date: Mon, 20 Apr 2026 11:49:45 +0200 Subject: [PATCH] fix(skip-objects): enlarged plate preview fails to load on auth-enabled instances (#1046) The mini thumbnail wrapped its src with withStreamToken() (appends the short-lived camera-stream token, needed because can't send an Authorization header), but the enlarged lightbox used a bare ${status.cover_url}?view=top. On auth-enabled instances the backend rejected the unauthenticated request and the browser showed the broken-image icon. Wrap the enlarged src with withStreamToken() too. --- CHANGELOG.md | 1 + frontend/src/components/SkipObjectsModal.tsx | 2 +- .../{index-CFcQzo54.js => index-BVXFAk6e.js} | 74 +++++++++---------- static/index.html | 2 +- 4 files changed, 40 insertions(+), 39 deletions(-) rename static/assets/{index-CFcQzo54.js => index-BVXFAk6e.js} (98%) diff --git a/CHANGELOG.md b/CHANGELOG.md index de707e4b9..e11bd8814 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to Bambuddy will be documented in this file. ## [0.2.4b1] - Unreleased ### Fixed +- **Skip Objects: Enlarged Preview Image Fails to Load on Auth-Enabled Instances** ([#1046](https://github.com/maziggy/bambuddy/issues/1046)) — Clicking the mini print-preview thumbnail inside the Skip Objects modal opened a lightbox that showed a broken-image icon instead of the full-size plate preview. The thumbnail `` wrapped its `src` with `withStreamToken()` (which appends the short-lived camera-stream token to `/api/v1/` URLs that `` tags can't attach an `Authorization` header to), but the enlarged lightbox `` used a bare `${status.cover_url}?view=top` so the browser's unauthenticated request was rejected by the backend. Both images now go through `withStreamToken()`. Thanks to @elit3ge for the report and screenshot. - **P1S Print Dispatches Stuck at IDLE Due to task_id Int32 Overflow** ([#1042](https://github.com/maziggy/bambuddy/issues/1042)) — Since the #1011 fix switched `project_id` / `subtask_id` / `task_id` from hardcoded `"0"` to `str(int(time.time() * 1000))`, each submission sent a 13-digit epoch-millisecond value (~1.7×10¹²). P1S firmware (observed on 01.10.00.00) clamps oversized task identity fields to signed int32 max (`2147483647`), so every dispatch looked identical from the printer's perspective — it treated a fresh print as a continuation of the prior FAILED job, returned `result: success` for `project_file` (command accepted), but then sat at `gcode_state: IDLE` with an empty `gcode_file` instead of transitioning to `PREPARE`/`RUNNING`. Thanks to @EdwardChamberlain for pinpointing the exact line and suggesting the mod fix. The three identity fields are now set to `str(int(time.time() * 1000) % 2_147_483_647 or 1)`: modulo keeps values inside the signed-int31 window with a ~24-day uniqueness cycle (more than enough for reprint deduplication), and `or 1` guards against the astronomically unlikely zero case (the printer rejects `task_id=0`). Regression test `test_submission_id_fits_signed_int32` asserts all three IDs are `< 2**31`. Two of @EdwardChamberlain's other suggestions — resolving `bed_type` from the sliced 3MF's per-plate JSON instead of hardcoding `"auto"`, and gating dispatch success on an actual state transition to `PREPARE`/`RUNNING` rather than on `project_file`'s `result: success` — are larger changes tracked separately. - **FTP Download Zombie-Thread Race on Slow WiFi** ([#1014](https://github.com/maziggy/bambuddy/issues/1014)) — Users on 2.4 GHz WiFi with heavy neighborhood interference saw "Successfully downloaded" log lines for queued prints that Bambuddy nonetheless reported as failed, and the slicer file landed in `/app/data/archives/temp/` with the File Manager unable to find it. Root cause: `download_file_async` wrapped the blocking FTP `RETR` in `asyncio.wait_for` with a 30–60 s timeout (user-configurable via `ftp_timeout`), but the wrapped thread couldn't be cancelled. On a slow link the download would overshoot the timeout by 15–30 s, at which point `_run()` waited a hard-coded 0.5 s for the zombie to finish, gave up, and returned failure — which triggered `with_ftp_retry` attempt 2, whose `_download` spawned a brand-new FTP session that contended with attempt 1's still-running transfer. Attempt 1's zombie eventually completed and wrote the file to disk, but by then attempt 2 (and 3, 4) had long since run out their own timeouts with their own fresh `completion` dicts and reported failure; the archive pipeline saw only the final `None` from `with_ftp_retry` and created a fallback archive row with no 3MF data, which is why Skip-Object couldn't find the plate's objects even though the 3MF was on disk. Two fixes: the 0.5 s post-timeout sleep is replaced with a `threading.Event` the worker sets in its `finally` block, and `_run()` waits for that event with a bounded grace of `max(min(ftp_timeout, 30), 0.5)` s — covering the slow-WiFi overshoot case without extending a genuinely stuck connection indefinitely. The log line now includes the grace window (`timed out after Xs (plus Ys grace)`). Regression test `test_download_file_async_timeout_waits_for_slow_zombie` simulates a 1.5 s zombie with a 1.0 s wait_for timeout; old 0.5 s sleep would give up, new 1.0 s grace salvages. The existing `test_download_file_async_timeout_no_salvage_when_incomplete` still passes — a thread that never completes within the grace window still returns failure. Thanks to @heffe2001 for the detailed reproduction and support logs. - **Obico: Cold-Start Capture Timeout Sticks in Status Banner** ([#172](https://github.com/maziggy/bambuddy/issues/172)) — On the very first detection poll after a restart, the initial RTSP snapshot capture occasionally exceeded the 20 s `SNAPSHOT_CAPTURE_TIMEOUT` (the first keyframe from the printer's camera can take a while on a cold RTSP connection). Subsequent polls every ~8 s recovered and captured in ~1.2 s, but the red `× Failed to capture snapshot for printer N` banner in Settings → Failure Detection → Status stayed up forever because `ObicoDetectionService._last_error` was written on failure and never cleared on the next successful poll. The successful branch in `_check_printer` now clears `_last_error` to `None` once a capture + ML call + classification complete, so the banner reflects only errors from recent cycles. Configuration-level errors (missing `external_url`, missing `ml_url`) still persist because they return before the clearing line — users still see them until they fix the setting. Regression test covers: seed `_last_error`, run one successful `_check_printer`, assert `_last_error is None`. Thanks to @fblix for the reproduction and screenshot. diff --git a/frontend/src/components/SkipObjectsModal.tsx b/frontend/src/components/SkipObjectsModal.tsx index 5482f8b9e..5821f8200 100644 --- a/frontend/src/components/SkipObjectsModal.tsx +++ b/frontend/src/components/SkipObjectsModal.tsx @@ -311,7 +311,7 @@ export function SkipObjectsModal({ printerId, isOpen, onClose }: SkipObjectsModa > {status?.cover_url ? ( {t('printers.printPreview')} diff --git a/static/assets/index-CFcQzo54.js b/static/assets/index-BVXFAk6e.js similarity index 98% rename from static/assets/index-CFcQzo54.js rename to static/assets/index-BVXFAk6e.js index 56eeb1522..bc2d3d835 100644 --- a/static/assets/index-CFcQzo54.js +++ b/static/assets/index-BVXFAk6e.js @@ -5,7 +5,7 @@ function Fde(t,e){for(var n=0;n$||nt[M]!==Nt[$]){var Lt=` `+nt[M].replace(" at new "," at ");return h.displayName&&Lt.includes("")&&(Lt=Lt.replace("",h.displayName)),Lt}while(1<=M&&0<=$);break}}}finally{G=!1,Error.prepareStackTrace=S}return(S=h?h.displayName||h.name:"")?I(S):""}function V(h,y){switch(h.tag){case 26:case 27:case 5:return I(h.type);case 16:return I("Lazy");case 13:return h.child!==y&&y!==null?I("Suspense Fallback"):I("Suspense");case 19:return I("SuspenseList");case 0:case 15:return X(h.type,!1);case 11:return X(h.type.render,!1);case 1:return X(h.type,!0);case 31:return I("Activity");default:return""}}function ee(h){try{var y="",S=null;do y+=V(h,S),S=h,h=h.return;while(h);return y}catch(M){return` Error generating stack: `+M.message+` -`+M.stack}}var ie=Object.prototype.hasOwnProperty,ge=t.unstable_scheduleCallback,pe=t.unstable_cancelCallback,ce=t.unstable_shouldYield,B=t.unstable_requestPaint,R=t.unstable_now,re=t.unstable_getCurrentPriorityLevel,ke=t.unstable_ImmediatePriority,Se=t.unstable_UserBlockingPriority,ye=t.unstable_NormalPriority,Te=t.unstable_LowPriority,ve=t.unstable_IdlePriority,Ae=t.log,Re=t.unstable_setDisableYieldValue,Me=null,Le=null;function Oe(h){if(typeof Ae=="function"&&Re(h),Le&&typeof Le.setStrictMode=="function")try{Le.setStrictMode(Me,h)}catch{}}var qe=Math.clz32?Math.clz32:he,Qe=Math.log,tt=Math.LN2;function he(h){return h>>>=0,h===0?32:31-(Qe(h)/tt|0)|0}var Fe=256,we=262144,Ve=4194304;function je(h){var y=h&42;if(y!==0)return y;switch(h&-h){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 h&261888;case 262144:case 524288:case 1048576:case 2097152:return h&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return h&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return h}}function de(h,y,S){var M=h.pendingLanes;if(M===0)return 0;var $=0,Z=h.suspendedLanes,Ne=h.pingedLanes;h=h.warmLanes;var He=M&134217727;return He!==0?(M=He&~Z,M!==0?$=je(M):(Ne&=He,Ne!==0?$=je(Ne):S||(S=He&~h,S!==0&&($=je(S))))):(He=M&~Z,He!==0?$=je(He):Ne!==0?$=je(Ne):S||(S=M&~h,S!==0&&($=je(S)))),$===0?0:y!==0&&y!==$&&(y&Z)===0&&(Z=$&-$,S=y&-y,Z>=S||Z===32&&(S&4194048)!==0)?y:$}function xe(h,y){return(h.pendingLanes&~(h.suspendedLanes&~h.pingedLanes)&y)===0}function Be(h,y){switch(h){case 1:case 2:case 4:case 8:case 64:return y+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 y+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Ze(){var h=Ve;return Ve<<=1,(Ve&62914560)===0&&(Ve=4194304),h}function pt(h){for(var y=[],S=0;31>S;S++)y.push(h);return y}function xt(h,y){h.pendingLanes|=y,y!==268435456&&(h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0)}function yt(h,y,S,M,$,Z){var Ne=h.pendingLanes;h.pendingLanes=S,h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0,h.expiredLanes&=S,h.entangledLanes&=S,h.errorRecoveryDisabledLanes&=S,h.shellSuspendCounter=0;var He=h.entanglements,nt=h.expirationTimes,Nt=h.hiddenUpdates;for(S=Ne&~S;0"u")return null;try{return h.activeElement||h.body}catch{return h.body}}var Dr=/[\n"\\]/g;function En(h){return h.replace(Dr,function(y){return"\\"+y.charCodeAt(0).toString(16)+" "})}function Ea(h,y,S,M,$,Z,Ne,He){h.name="",Ne!=null&&typeof Ne!="function"&&typeof Ne!="symbol"&&typeof Ne!="boolean"?h.type=Ne:h.removeAttribute("type"),y!=null?Ne==="number"?(y===0&&h.value===""||h.value!=y)&&(h.value=""+zn(y)):h.value!==""+zn(y)&&(h.value=""+zn(y)):Ne!=="submit"&&Ne!=="reset"||h.removeAttribute("value"),y!=null?na(h,Ne,zn(y)):S!=null?na(h,Ne,zn(S)):M!=null&&h.removeAttribute("value"),$==null&&Z!=null&&(h.defaultChecked=!!Z),$!=null&&(h.checked=$&&typeof $!="function"&&typeof $!="symbol"),He!=null&&typeof He!="function"&&typeof He!="symbol"&&typeof He!="boolean"?h.name=""+zn(He):h.removeAttribute("name")}function Pn(h,y,S,M,$,Z,Ne,He){if(Z!=null&&typeof Z!="function"&&typeof Z!="symbol"&&typeof Z!="boolean"&&(h.type=Z),y!=null||S!=null){if(!(Z!=="submit"&&Z!=="reset"||y!=null)){gn(h);return}S=S!=null?""+zn(S):"",y=y!=null?""+zn(y):S,He||y===h.value||(h.value=y),h.defaultValue=y}M=M??$,M=typeof M!="function"&&typeof M!="symbol"&&!!M,h.checked=He?h.checked:!!M,h.defaultChecked=!!M,Ne!=null&&typeof Ne!="function"&&typeof Ne!="symbol"&&typeof Ne!="boolean"&&(h.name=Ne),gn(h)}function na(h,y,S){y==="number"&&gr(h.ownerDocument)===h||h.defaultValue===""+S||(h.defaultValue=""+S)}function qn(h,y,S,M){if(h=h.options,y){y={};for(var $=0;$"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),kl=!1;if(Ns)try{var ns={};Object.defineProperty(ns,"passive",{get:function(){kl=!0}}),window.addEventListener("test",ns,ns),window.removeEventListener("test",ns,ns)}catch{kl=!1}var $o=null,Nl=null,wc=null;function vo(){if(wc)return wc;var h,y=Nl,S=y.length,M,$="value"in $o?$o.value:$o.textContent,Z=$.length;for(h=0;h=ct),ir=" ",aa=!1;function ka(h,y){switch(h){case"keyup":return Ht.indexOf(y.keyCode)!==-1;case"keydown":return y.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Jt(h){return h=h.detail,typeof h=="object"&&"data"in h?h.data:null}var vn=!1;function Da(h,y){switch(h){case"compositionend":return Jt(y);case"keypress":return y.which!==32?null:(aa=!0,ir);case"textInput":return h=y.data,h===ir&&aa?null:h;default:return null}}function di(h,y){if(vn)return h==="compositionend"||!Zt&&ka(h,y)?(h=vo(),wc=Nl=$o=null,vn=!1,h):null;switch(h){case"paste":return null;case"keypress":if(!(y.ctrlKey||y.altKey||y.metaKey)||y.ctrlKey&&y.altKey){if(y.char&&1=y)return{node:S,offset:y-h};h=M}e:{for(;S;){if(S.nextSibling){S=S.nextSibling;break e}S=S.parentNode}S=void 0}S=BS(S)}}function b5(h,y){return h&&y?h===y?!0:h&&h.nodeType===3?!1:y&&y.nodeType===3?b5(h,y.parentNode):"contains"in h?h.contains(y):h.compareDocumentPosition?!!(h.compareDocumentPosition(y)&16):!1:!1}function x5(h){h=h!=null&&h.ownerDocument!=null&&h.ownerDocument.defaultView!=null?h.ownerDocument.defaultView:window;for(var y=gr(h.document);y instanceof h.HTMLIFrameElement;){try{var S=typeof y.contentWindow.location.href=="string"}catch{S=!1}if(S)h=y.contentWindow;else break;y=gr(h.document)}return y}function wA(h){var y=h&&h.nodeName&&h.nodeName.toLowerCase();return y&&(y==="input"&&(h.type==="text"||h.type==="search"||h.type==="tel"||h.type==="url"||h.type==="password")||y==="textarea"||h.contentEditable==="true")}var hce=Ns&&"documentMode"in document&&11>=document.documentMode,Gg=null,SA=null,Vy=null,_A=!1;function y5(h,y,S){var M=S.window===S?S.document:S.nodeType===9?S:S.ownerDocument;_A||Gg==null||Gg!==gr(M)||(M=Gg,"selectionStart"in M&&wA(M)?M={start:M.selectionStart,end:M.selectionEnd}:(M=(M.ownerDocument&&M.ownerDocument.defaultView||window).getSelection(),M={anchorNode:M.anchorNode,anchorOffset:M.anchorOffset,focusNode:M.focusNode,focusOffset:M.focusOffset}),Vy&&Um(Vy,M)||(Vy=M,M=A_(SA,"onSelect"),0>=Ne,$-=Ne,md=1<<32-qe(y)+$|S<<$|M,hd=Z+h}else md=1<Zn?(yr=bn,bn=null):yr=bn.sibling;var Ar=Ct(bt,bn,kt[Zn],Ot);if(Ar===null){bn===null&&(bn=yr);break}h&&bn&&Ar.alternate===null&&y(bt,bn),ut=Z(Ar,ut,Zn),Tr===null?Cn=Ar:Tr.sibling=Ar,Tr=Ar,bn=yr}if(Zn===kt.length)return S(bt,bn),wr&&lu(bt,Zn),Cn;if(bn===null){for(;ZnZn?(yr=bn,bn=null):yr=bn.sibling;var lh=Ct(bt,bn,Ar.value,Ot);if(lh===null){bn===null&&(bn=yr);break}h&&bn&&lh.alternate===null&&y(bt,bn),ut=Z(lh,ut,Zn),Tr===null?Cn=lh:Tr.sibling=lh,Tr=lh,bn=yr}if(Ar.done)return S(bt,bn),wr&&lu(bt,Zn),Cn;if(bn===null){for(;!Ar.done;Zn++,Ar=kt.next())Ar=zt(bt,Ar.value,Ot),Ar!==null&&(ut=Z(Ar,ut,Zn),Tr===null?Cn=Ar:Tr.sibling=Ar,Tr=Ar);return wr&&lu(bt,Zn),Cn}for(bn=M(bn);!Ar.done;Zn++,Ar=kt.next())Ar=Et(bn,bt,Zn,Ar.value,Ot),Ar!==null&&(h&&Ar.alternate!==null&&bn.delete(Ar.key===null?Zn:Ar.key),ut=Z(Ar,ut,Zn),Tr===null?Cn=Ar:Tr.sibling=Ar,Tr=Ar);return h&&bn.forEach(function(Dde){return y(bt,Dde)}),wr&&lu(bt,Zn),Cn}function Wr(bt,ut,kt,Ot){if(typeof kt=="object"&&kt!==null&&kt.type===v&&kt.key===null&&(kt=kt.props.children),typeof kt=="object"&&kt!==null){switch(kt.$$typeof){case f:e:{for(var Cn=kt.key;ut!==null;){if(ut.key===Cn){if(Cn=kt.type,Cn===v){if(ut.tag===7){S(bt,ut.sibling),Ot=$(ut,kt.props.children),Ot.return=bt,bt=Ot;break e}}else if(ut.elementType===Cn||typeof Cn=="object"&&Cn!==null&&Cn.$$typeof===F&&Yp(Cn)===ut.type){S(bt,ut.sibling),Ot=$(ut,kt.props),Qy(Ot,kt),Ot.return=bt,bt=Ot;break e}S(bt,ut);break}else y(bt,ut);ut=ut.sibling}kt.type===v?(Ot=Vp(kt.props.children,bt.mode,Ot,kt.key),Ot.return=bt,bt=Ot):(Ot=GS(kt.type,kt.key,kt.props,null,bt.mode,Ot),Qy(Ot,kt),Ot.return=bt,bt=Ot)}return Ne(bt);case x:e:{for(Cn=kt.key;ut!==null;){if(ut.key===Cn)if(ut.tag===4&&ut.stateNode.containerInfo===kt.containerInfo&&ut.stateNode.implementation===kt.implementation){S(bt,ut.sibling),Ot=$(ut,kt.children||[]),Ot.return=bt,bt=Ot;break e}else{S(bt,ut);break}else y(bt,ut);ut=ut.sibling}Ot=jA(kt,bt.mode,Ot),Ot.return=bt,bt=Ot}return Ne(bt);case F:return kt=Yp(kt),Wr(bt,ut,kt,Ot)}if(te(kt))return mn(bt,ut,kt,Ot);if(z(kt)){if(Cn=z(kt),typeof Cn!="function")throw Error(r(150));return kt=Cn.call(kt),Fn(bt,ut,kt,Ot)}if(typeof kt.then=="function")return Wr(bt,ut,JS(kt),Ot);if(kt.$$typeof===C)return Wr(bt,ut,XS(bt,kt),Ot);e_(bt,kt)}return typeof kt=="string"&&kt!==""||typeof kt=="number"||typeof kt=="bigint"?(kt=""+kt,ut!==null&&ut.tag===6?(S(bt,ut.sibling),Ot=$(ut,kt),Ot.return=bt,bt=Ot):(S(bt,ut),Ot=AA(kt,bt.mode,Ot),Ot.return=bt,bt=Ot),Ne(bt)):S(bt,ut)}return function(bt,ut,kt,Ot){try{Yy=0;var Cn=Wr(bt,ut,kt,Ot);return rb=null,Cn}catch(bn){if(bn===nb||bn===QS)throw bn;var Tr=Yo(29,bn,null,bt.mode);return Tr.lanes=Ot,Tr.return=bt,Tr}}}var Zp=H5(!0),q5=H5(!1),Vm=!1;function HA(h){h.updateQueue={baseState:h.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function qA(h,y){h=h.updateQueue,y.updateQueue===h&&(y.updateQueue={baseState:h.baseState,firstBaseUpdate:h.firstBaseUpdate,lastBaseUpdate:h.lastBaseUpdate,shared:h.shared,callbacks:null})}function Gm(h){return{lane:h,tag:0,payload:null,callback:null,next:null}}function Wm(h,y,S){var M=h.updateQueue;if(M===null)return null;if(M=M.shared,(Fr&2)!==0){var $=M.pending;return $===null?y.next=y:(y.next=$.next,$.next=y),M.pending=y,y=VS(h),C5(h,null,S),y}return $S(h,M,y,S),VS(h)}function Zy(h,y,S){if(y=y.updateQueue,y!==null&&(y=y.shared,(S&4194048)!==0)){var M=y.lanes;M&=h.pendingLanes,S|=M,y.lanes=S,Kt(h,S)}}function $A(h,y){var S=h.updateQueue,M=h.alternate;if(M!==null&&(M=M.updateQueue,S===M)){var $=null,Z=null;if(S=S.firstBaseUpdate,S!==null){do{var Ne={lane:S.lane,tag:S.tag,payload:S.payload,callback:null,next:null};Z===null?$=Z=Ne:Z=Z.next=Ne,S=S.next}while(S!==null);Z===null?$=Z=y:Z=Z.next=y}else $=Z=y;S={baseState:M.baseState,firstBaseUpdate:$,lastBaseUpdate:Z,shared:M.shared,callbacks:M.callbacks},h.updateQueue=S;return}h=S.lastBaseUpdate,h===null?S.firstBaseUpdate=y:h.next=y,S.lastBaseUpdate=y}var VA=!1;function Jy(){if(VA){var h=tb;if(h!==null)throw h}}function ev(h,y,S,M){VA=!1;var $=h.updateQueue;Vm=!1;var Z=$.firstBaseUpdate,Ne=$.lastBaseUpdate,He=$.shared.pending;if(He!==null){$.shared.pending=null;var nt=He,Nt=nt.next;nt.next=null,Ne===null?Z=Nt:Ne.next=Nt,Ne=nt;var Lt=h.alternate;Lt!==null&&(Lt=Lt.updateQueue,He=Lt.lastBaseUpdate,He!==Ne&&(He===null?Lt.firstBaseUpdate=Nt:He.next=Nt,Lt.lastBaseUpdate=nt))}if(Z!==null){var zt=$.baseState;Ne=0,Lt=Nt=nt=null,He=Z;do{var Ct=He.lane&-536870913,Et=Ct!==He.lane;if(Et?(xr&Ct)===Ct:(M&Ct)===Ct){Ct!==0&&Ct===eb&&(VA=!0),Lt!==null&&(Lt=Lt.next={lane:0,tag:He.tag,payload:He.payload,callback:null,next:null});e:{var mn=h,Fn=He;Ct=y;var Wr=S;switch(Fn.tag){case 1:if(mn=Fn.payload,typeof mn=="function"){zt=mn.call(Wr,zt,Ct);break e}zt=mn;break e;case 3:mn.flags=mn.flags&-65537|128;case 0:if(mn=Fn.payload,Ct=typeof mn=="function"?mn.call(Wr,zt,Ct):mn,Ct==null)break e;zt=m({},zt,Ct);break e;case 2:Vm=!0}}Ct=He.callback,Ct!==null&&(h.flags|=64,Et&&(h.flags|=8192),Et=$.callbacks,Et===null?$.callbacks=[Ct]:Et.push(Ct))}else Et={lane:Ct,tag:He.tag,payload:He.payload,callback:He.callback,next:null},Lt===null?(Nt=Lt=Et,nt=zt):Lt=Lt.next=Et,Ne|=Ct;if(He=He.next,He===null){if(He=$.shared.pending,He===null)break;Et=He,He=Et.next,Et.next=null,$.lastBaseUpdate=Et,$.shared.pending=null}}while(!0);Lt===null&&(nt=zt),$.baseState=nt,$.firstBaseUpdate=Nt,$.lastBaseUpdate=Lt,Z===null&&($.shared.lanes=0),Zm|=Ne,h.lanes=Ne,h.memoizedState=zt}}function $5(h,y){if(typeof h!="function")throw Error(r(191,h));h.call(y)}function V5(h,y){var S=h.callbacks;if(S!==null)for(h.callbacks=null,h=0;hZ?Z:8;var Ne=ae.T,He={};ae.T=He,dj(h,!1,y,S);try{var nt=$(),Nt=ae.S;if(Nt!==null&&Nt(He,nt),nt!==null&&typeof nt=="object"&&typeof nt.then=="function"){var Lt=Sce(nt,M);rv(h,y,Lt,tl(h))}else rv(h,y,M,tl(h))}catch(zt){rv(h,y,{then:function(){},status:"rejected",reason:zt},tl())}finally{J.p=Z,Ne!==null&&He.types!==null&&(Ne.types=He.types),ae.T=Ne}}function Tce(){}function lj(h,y,S,M){if(h.tag!==5)throw Error(r(476));var $=_U(h).queue;SU(h,$,y,le,S===null?Tce:function(){return kU(h),S(M)})}function _U(h){var y=h.memoizedState;if(y!==null)return y;y={memoizedState:le,baseState:le,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:mu,lastRenderedState:le},next:null};var S={};return y.next={memoizedState:S,baseState:S,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:mu,lastRenderedState:S},next:null},h.memoizedState=y,h=h.alternate,h!==null&&(h.memoizedState=y),y}function kU(h){var y=_U(h);y.next===null&&(y=h.alternate.memoizedState),rv(h,y.next.queue,{},tl())}function cj(){return as(vv)}function NU(){return ri().memoizedState}function CU(){return ri().memoizedState}function Ace(h){for(var y=h.return;y!==null;){switch(y.tag){case 24:case 3:var S=tl();h=Gm(S);var M=Wm(y,h,S);M!==null&&(Co(M,y,S),Zy(M,y,S)),y={cache:IA()},h.payload=y;return}y=y.return}}function jce(h,y,S){var M=tl();S={lane:M,revertLane:0,gesture:null,action:S,hasEagerState:!1,eagerState:null,next:null},d_(h)?TU(y,S):(S=PA(h,y,S,M),S!==null&&(Co(S,h,M),AU(S,y,M)))}function PU(h,y,S){var M=tl();rv(h,y,S,M)}function rv(h,y,S,M){var $={lane:M,revertLane:0,gesture:null,action:S,hasEagerState:!1,eagerState:null,next:null};if(d_(h))TU(y,$);else{var Z=h.alternate;if(h.lanes===0&&(Z===null||Z.lanes===0)&&(Z=y.lastRenderedReducer,Z!==null))try{var Ne=y.lastRenderedState,He=Z(Ne,S);if($.hasEagerState=!0,$.eagerState=He,js(He,Ne))return $S(h,y,$,0),oa===null&&qS(),!1}catch{}if(S=PA(h,y,$,M),S!==null)return Co(S,h,M),AU(S,y,M),!0}return!1}function dj(h,y,S,M){if(M={lane:2,revertLane:Hj(),gesture:null,action:M,hasEagerState:!1,eagerState:null,next:null},d_(h)){if(y)throw Error(r(479))}else y=PA(h,S,M,2),y!==null&&Co(y,h,2)}function d_(h){var y=h.alternate;return h===Yn||y!==null&&y===Yn}function TU(h,y){ib=r_=!0;var S=h.pending;S===null?y.next=y:(y.next=S.next,S.next=y),h.pending=y}function AU(h,y,S){if((S&4194048)!==0){var M=y.lanes;M&=h.pendingLanes,S|=M,y.lanes=S,Kt(h,S)}}var av={readContext:as,use:s_,useCallback:Ba,useContext:Ba,useEffect:Ba,useImperativeHandle:Ba,useLayoutEffect:Ba,useInsertionEffect:Ba,useMemo:Ba,useReducer:Ba,useRef:Ba,useState:Ba,useDebugValue:Ba,useDeferredValue:Ba,useTransition:Ba,useSyncExternalStore:Ba,useId:Ba,useHostTransitionStatus:Ba,useFormState:Ba,useActionState:Ba,useOptimistic:Ba,useMemoCache:Ba,useCacheRefresh:Ba};av.useEffectEvent=Ba;var jU={readContext:as,use:s_,useCallback:function(h,y){return Qs().memoizedState=[h,y===void 0?null:y],h},useContext:as,useEffect:hU,useImperativeHandle:function(h,y,S){S=S!=null?S.concat([h]):null,l_(4194308,4,bU.bind(null,y,h),S)},useLayoutEffect:function(h,y){return l_(4194308,4,h,y)},useInsertionEffect:function(h,y){l_(4,2,h,y)},useMemo:function(h,y){var S=Qs();y=y===void 0?null:y;var M=h();if(Jp){Oe(!0);try{h()}finally{Oe(!1)}}return S.memoizedState=[M,y],M},useReducer:function(h,y,S){var M=Qs();if(S!==void 0){var $=S(y);if(Jp){Oe(!0);try{S(y)}finally{Oe(!1)}}}else $=y;return M.memoizedState=M.baseState=$,h={pending:null,lanes:0,dispatch:null,lastRenderedReducer:h,lastRenderedState:$},M.queue=h,h=h.dispatch=jce.bind(null,Yn,h),[M.memoizedState,h]},useRef:function(h){var y=Qs();return h={current:h},y.memoizedState=h},useState:function(h){h=rj(h);var y=h.queue,S=PU.bind(null,Yn,y);return y.dispatch=S,[h.memoizedState,S]},useDebugValue:sj,useDeferredValue:function(h,y){var S=Qs();return oj(S,h,y)},useTransition:function(){var h=rj(!1);return h=SU.bind(null,Yn,h.queue,!0,!1),Qs().memoizedState=h,[!1,h]},useSyncExternalStore:function(h,y,S){var M=Yn,$=Qs();if(wr){if(S===void 0)throw Error(r(407));S=S()}else{if(S=y(),oa===null)throw Error(r(349));(xr&127)!==0||Q5(M,y,S)}$.memoizedState=S;var Z={value:S,getSnapshot:y};return $.queue=Z,hU(J5.bind(null,M,Z,h),[h]),M.flags|=2048,ob(9,{destroy:void 0},Z5.bind(null,M,Z,S,y),null),S},useId:function(){var h=Qs(),y=oa.identifierPrefix;if(wr){var S=hd,M=md;S=(M&~(1<<32-qe(M)-1)).toString(32)+S,y="_"+y+"R_"+S,S=a_++,0<\/script>",Z=Z.removeChild(Z.firstChild);break;case"select":Z=typeof M.is=="string"?Ne.createElement("select",{is:M.is}):Ne.createElement("select"),M.multiple?Z.multiple=!0:M.size&&(Z.size=M.size);break;default:Z=typeof M.is=="string"?Ne.createElement($,{is:M.is}):Ne.createElement($)}}Z[at]=y,Z[dt]=M;e:for(Ne=y.child;Ne!==null;){if(Ne.tag===5||Ne.tag===6)Z.appendChild(Ne.stateNode);else if(Ne.tag!==4&&Ne.tag!==27&&Ne.child!==null){Ne.child.return=Ne,Ne=Ne.child;continue}if(Ne===y)break e;for(;Ne.sibling===null;){if(Ne.return===null||Ne.return===y)break e;Ne=Ne.return}Ne.sibling.return=Ne.return,Ne=Ne.sibling}y.stateNode=Z;e:switch(ss(Z,$,M),$){case"button":case"input":case"select":case"textarea":M=!!M.autoFocus;break e;case"img":M=!0;break e;default:M=!1}M&&pu(y)}}return va(y),kj(y,y.type,h===null?null:h.memoizedProps,y.pendingProps,S),null;case 6:if(h&&y.stateNode!=null)h.memoizedProps!==M&&pu(y);else{if(typeof M!="string"&&y.stateNode===null)throw Error(r(166));if(h=q.current,Zg(y)){if(h=y.stateNode,S=y.memoizedProps,M=null,$=rs,$!==null)switch($.tag){case 27:case 5:M=$.memoizedProps}h[at]=y,h=!!(h.nodeValue===S||M!==null&&M.suppressHydrationWarning===!0||XB(h.nodeValue,S)),h||qm(y,!0)}else h=j_(h).createTextNode(M),h[at]=y,y.stateNode=h}return va(y),null;case 31:if(S=y.memoizedState,h===null||h.memoizedState!==null){if(M=Zg(y),S!==null){if(h===null){if(!M)throw Error(r(318));if(h=y.memoizedState,h=h!==null?h.dehydrated:null,!h)throw Error(r(557));h[at]=y}else Gp(),(y.flags&128)===0&&(y.memoizedState=null),y.flags|=4;va(y),h=!1}else S=FA(),h!==null&&h.memoizedState!==null&&(h.memoizedState.hydrationErrors=S),h=!0;if(!h)return y.flags&256?(Zo(y),y):(Zo(y),null);if((y.flags&128)!==0)throw Error(r(558))}return va(y),null;case 13:if(M=y.memoizedState,h===null||h.memoizedState!==null&&h.memoizedState.dehydrated!==null){if($=Zg(y),M!==null&&M.dehydrated!==null){if(h===null){if(!$)throw Error(r(318));if($=y.memoizedState,$=$!==null?$.dehydrated:null,!$)throw Error(r(317));$[at]=y}else Gp(),(y.flags&128)===0&&(y.memoizedState=null),y.flags|=4;va(y),$=!1}else $=FA(),h!==null&&h.memoizedState!==null&&(h.memoizedState.hydrationErrors=$),$=!0;if(!$)return y.flags&256?(Zo(y),y):(Zo(y),null)}return Zo(y),(y.flags&128)!==0?(y.lanes=S,y):(S=M!==null,h=h!==null&&h.memoizedState!==null,S&&(M=y.child,$=null,M.alternate!==null&&M.alternate.memoizedState!==null&&M.alternate.memoizedState.cachePool!==null&&($=M.alternate.memoizedState.cachePool.pool),Z=null,M.memoizedState!==null&&M.memoizedState.cachePool!==null&&(Z=M.memoizedState.cachePool.pool),Z!==$&&(M.flags|=2048)),S!==h&&S&&(y.child.flags|=8192),f_(y,y.updateQueue),va(y),null);case 4:return j(),h===null&&Gj(y.stateNode.containerInfo),va(y),null;case 10:return du(y.type),va(y),null;case 19:if(ne(ni),M=y.memoizedState,M===null)return va(y),null;if($=(y.flags&128)!==0,Z=M.rendering,Z===null)if($)sv(M,!1);else{if(Ha!==0||h!==null&&(h.flags&128)!==0)for(h=y.child;h!==null;){if(Z=n_(h),Z!==null){for(y.flags|=128,sv(M,!1),h=Z.updateQueue,y.updateQueue=h,f_(y,h),y.subtreeFlags=0,h=S,S=y.child;S!==null;)P5(S,h),S=S.sibling;return fe(ni,ni.current&1|2),wr&&lu(y,M.treeForkCount),y.child}h=h.sibling}M.tail!==null&&R()>v_&&(y.flags|=128,$=!0,sv(M,!1),y.lanes=4194304)}else{if(!$)if(h=n_(Z),h!==null){if(y.flags|=128,$=!0,h=h.updateQueue,y.updateQueue=h,f_(y,h),sv(M,!0),M.tail===null&&M.tailMode==="hidden"&&!Z.alternate&&!wr)return va(y),null}else 2*R()-M.renderingStartTime>v_&&S!==536870912&&(y.flags|=128,$=!0,sv(M,!1),y.lanes=4194304);M.isBackwards?(Z.sibling=y.child,y.child=Z):(h=M.last,h!==null?h.sibling=Z:y.child=Z,M.last=Z)}return M.tail!==null?(h=M.tail,M.rendering=h,M.tail=h.sibling,M.renderingStartTime=R(),h.sibling=null,S=ni.current,fe(ni,$?S&1|2:S&1),wr&&lu(y,M.treeForkCount),h):(va(y),null);case 22:case 23:return Zo(y),WA(),M=y.memoizedState!==null,h!==null?h.memoizedState!==null!==M&&(y.flags|=8192):M&&(y.flags|=8192),M?(S&536870912)!==0&&(y.flags&128)===0&&(va(y),y.subtreeFlags&6&&(y.flags|=8192)):va(y),S=y.updateQueue,S!==null&&f_(y,S.retryQueue),S=null,h!==null&&h.memoizedState!==null&&h.memoizedState.cachePool!==null&&(S=h.memoizedState.cachePool.pool),M=null,y.memoizedState!==null&&y.memoizedState.cachePool!==null&&(M=y.memoizedState.cachePool.pool),M!==S&&(y.flags|=2048),h!==null&&ne(Xp),null;case 24:return S=null,h!==null&&(S=h.memoizedState.cache),y.memoizedState.cache!==S&&(y.flags|=2048),du(ui),va(y),null;case 25:return null;case 30:return null}throw Error(r(156,y.tag))}function Rce(h,y){switch(EA(y),y.tag){case 1:return h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 3:return du(ui),j(),h=y.flags,(h&65536)!==0&&(h&128)===0?(y.flags=h&-65537|128,y):null;case 26:case 27:case 5:return K(y),null;case 31:if(y.memoizedState!==null){if(Zo(y),y.alternate===null)throw Error(r(340));Gp()}return h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 13:if(Zo(y),h=y.memoizedState,h!==null&&h.dehydrated!==null){if(y.alternate===null)throw Error(r(340));Gp()}return h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 19:return ne(ni),null;case 4:return j(),null;case 10:return du(y.type),null;case 22:case 23:return Zo(y),WA(),h!==null&&ne(Xp),h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 24:return du(ui),null;case 25:return null;default:return null}}function eB(h,y){switch(EA(y),y.tag){case 3:du(ui),j();break;case 26:case 27:case 5:K(y);break;case 4:j();break;case 31:y.memoizedState!==null&&Zo(y);break;case 13:Zo(y);break;case 19:ne(ni);break;case 10:du(y.type);break;case 22:case 23:Zo(y),WA(),h!==null&&ne(Xp);break;case 24:du(ui)}}function ov(h,y){try{var S=y.updateQueue,M=S!==null?S.lastEffect:null;if(M!==null){var $=M.next;S=$;do{if((S.tag&h)===h){M=void 0;var Z=S.create,Ne=S.inst;M=Z(),Ne.destroy=M}S=S.next}while(S!==$)}}catch(He){Br(y,y.return,He)}}function Ym(h,y,S){try{var M=y.updateQueue,$=M!==null?M.lastEffect:null;if($!==null){var Z=$.next;M=Z;do{if((M.tag&h)===h){var Ne=M.inst,He=Ne.destroy;if(He!==void 0){Ne.destroy=void 0,$=y;var nt=S,Nt=He;try{Nt()}catch(Lt){Br($,nt,Lt)}}}M=M.next}while(M!==Z)}}catch(Lt){Br(y,y.return,Lt)}}function tB(h){var y=h.updateQueue;if(y!==null){var S=h.stateNode;try{V5(y,S)}catch(M){Br(h,h.return,M)}}}function nB(h,y,S){S.props=ef(h.type,h.memoizedProps),S.state=h.memoizedState;try{S.componentWillUnmount()}catch(M){Br(h,y,M)}}function lv(h,y){try{var S=h.ref;if(S!==null){switch(h.tag){case 26:case 27:case 5:var M=h.stateNode;break;case 30:M=h.stateNode;break;default:M=h.stateNode}typeof S=="function"?h.refCleanup=S(M):S.current=M}}catch($){Br(h,y,$)}}function pd(h,y){var S=h.ref,M=h.refCleanup;if(S!==null)if(typeof M=="function")try{M()}catch($){Br(h,y,$)}finally{h.refCleanup=null,h=h.alternate,h!=null&&(h.refCleanup=null)}else if(typeof S=="function")try{S(null)}catch($){Br(h,y,$)}else S.current=null}function rB(h){var y=h.type,S=h.memoizedProps,M=h.stateNode;try{e:switch(y){case"button":case"input":case"select":case"textarea":S.autoFocus&&M.focus();break e;case"img":S.src?M.src=S.src:S.srcSet&&(M.srcset=S.srcSet)}}catch($){Br(h,h.return,$)}}function Nj(h,y,S){try{var M=h.stateNode;rde(M,h.type,S,y),M[dt]=y}catch($){Br(h,h.return,$)}}function aB(h){return h.tag===5||h.tag===3||h.tag===26||h.tag===27&&rh(h.type)||h.tag===4}function Cj(h){e:for(;;){for(;h.sibling===null;){if(h.return===null||aB(h.return))return null;h=h.return}for(h.sibling.return=h.return,h=h.sibling;h.tag!==5&&h.tag!==6&&h.tag!==18;){if(h.tag===27&&rh(h.type)||h.flags&2||h.child===null||h.tag===4)continue e;h.child.return=h,h=h.child}if(!(h.flags&2))return h.stateNode}}function Pj(h,y,S){var M=h.tag;if(M===5||M===6)h=h.stateNode,y?(S.nodeType===9?S.body:S.nodeName==="HTML"?S.ownerDocument.body:S).insertBefore(h,y):(y=S.nodeType===9?S.body:S.nodeName==="HTML"?S.ownerDocument.body:S,y.appendChild(h),S=S._reactRootContainer,S!=null||y.onclick!==null||(y.onclick=qt));else if(M!==4&&(M===27&&rh(h.type)&&(S=h.stateNode,y=null),h=h.child,h!==null))for(Pj(h,y,S),h=h.sibling;h!==null;)Pj(h,y,S),h=h.sibling}function g_(h,y,S){var M=h.tag;if(M===5||M===6)h=h.stateNode,y?S.insertBefore(h,y):S.appendChild(h);else if(M!==4&&(M===27&&rh(h.type)&&(S=h.stateNode),h=h.child,h!==null))for(g_(h,y,S),h=h.sibling;h!==null;)g_(h,y,S),h=h.sibling}function iB(h){var y=h.stateNode,S=h.memoizedProps;try{for(var M=h.type,$=y.attributes;$.length;)y.removeAttributeNode($[0]);ss(y,M,S),y[at]=h,y[dt]=S}catch(Z){Br(h,h.return,Z)}}var fu=!1,pi=!1,Tj=!1,sB=typeof WeakSet=="function"?WeakSet:Set,Hi=null;function Lce(h,y){if(h=h.containerInfo,Xj=O_,h=x5(h),wA(h)){if("selectionStart"in h)var S={start:h.selectionStart,end:h.selectionEnd};else e:{S=(S=h.ownerDocument)&&S.defaultView||window;var M=S.getSelection&&S.getSelection();if(M&&M.rangeCount!==0){S=M.anchorNode;var $=M.anchorOffset,Z=M.focusNode;M=M.focusOffset;try{S.nodeType,Z.nodeType}catch{S=null;break e}var Ne=0,He=-1,nt=-1,Nt=0,Lt=0,zt=h,Ct=null;t:for(;;){for(var Et;zt!==S||$!==0&&zt.nodeType!==3||(He=Ne+$),zt!==Z||M!==0&&zt.nodeType!==3||(nt=Ne+M),zt.nodeType===3&&(Ne+=zt.nodeValue.length),(Et=zt.firstChild)!==null;)Ct=zt,zt=Et;for(;;){if(zt===h)break t;if(Ct===S&&++Nt===$&&(He=Ne),Ct===Z&&++Lt===M&&(nt=Ne),(Et=zt.nextSibling)!==null)break;zt=Ct,Ct=zt.parentNode}zt=Et}S=He===-1||nt===-1?null:{start:He,end:nt}}else S=null}S=S||{start:0,end:0}}else S=null;for(Yj={focusedElem:h,selectionRange:S},O_=!1,Hi=y;Hi!==null;)if(y=Hi,h=y.child,(y.subtreeFlags&1028)!==0&&h!==null)h.return=y,Hi=h;else for(;Hi!==null;){switch(y=Hi,Z=y.alternate,h=y.flags,y.tag){case 0:if((h&4)!==0&&(h=y.updateQueue,h=h!==null?h.events:null,h!==null))for(S=0;S title"))),ss(Z,M,S),Z[at]=h,Ke(Z),M=Z;break e;case"link":var Ne=m8("link","href",$).get(M+(S.href||""));if(Ne){for(var He=0;HeWr&&(Ne=Wr,Wr=Fn,Fn=Ne);var bt=g5(He,Fn),ut=g5(He,Wr);if(bt&&ut&&(Et.rangeCount!==1||Et.anchorNode!==bt.node||Et.anchorOffset!==bt.offset||Et.focusNode!==ut.node||Et.focusOffset!==ut.offset)){var kt=zt.createRange();kt.setStart(bt.node,bt.offset),Et.removeAllRanges(),Fn>Wr?(Et.addRange(kt),Et.extend(ut.node,ut.offset)):(kt.setEnd(ut.node,ut.offset),Et.addRange(kt))}}}}for(zt=[],Et=He;Et=Et.parentNode;)Et.nodeType===1&&zt.push({element:Et,left:Et.scrollLeft,top:Et.scrollTop});for(typeof He.focus=="function"&&He.focus(),He=0;HeS?32:S,ae.T=null,S=Rj,Rj=null;var Z=eh,Ne=vu;if(Ti=0,mb=eh=null,vu=0,(Fr&6)!==0)throw Error(r(331));var He=Fr;if(Fr|=4,bB(Z.current),pB(Z,Z.current,Ne,S),Fr=He,pv(0,!1),Le&&typeof Le.onPostCommitFiberRoot=="function")try{Le.onPostCommitFiberRoot(Me,Z)}catch{}return!0}finally{J.p=$,ae.T=M,RB(h,y)}}function OB(h,y,S){y=Al(S,y),y=pj(h.stateNode,y,2),h=Wm(h,y,2),h!==null&&(xt(h,2),fd(h))}function Br(h,y,S){if(h.tag===3)OB(h,h,S);else for(;y!==null;){if(y.tag===3){OB(y,h,S);break}else if(y.tag===1){var M=y.stateNode;if(typeof y.type.getDerivedStateFromError=="function"||typeof M.componentDidCatch=="function"&&(Jm===null||!Jm.has(M))){h=Al(S,h),S=IU(2),M=Wm(y,S,2),M!==null&&(zU(S,M,y,h),xt(M,2),fd(M));break}}y=y.return}}function zj(h,y,S){var M=h.pingCache;if(M===null){M=h.pingCache=new zce;var $=new Set;M.set(y,$)}else $=M.get(y),$===void 0&&($=new Set,M.set(y,$));$.has(S)||(Mj=!0,$.add(S),h=$ce.bind(null,h,y,S),y.then(h,h))}function $ce(h,y,S){var M=h.pingCache;M!==null&&M.delete(y),h.pingedLanes|=h.suspendedLanes&S,h.warmLanes&=~S,oa===h&&(xr&S)===S&&(Ha===4||Ha===3&&(xr&62914560)===xr&&300>R()-y_?(Fr&2)===0&&hb(h,0):Ej|=S,ub===xr&&(ub=0)),fd(h)}function IB(h,y){y===0&&(y=Ze()),h=$p(h,y),h!==null&&(xt(h,y),fd(h))}function Vce(h){var y=h.memoizedState,S=0;y!==null&&(S=y.retryLane),IB(h,S)}function Gce(h,y){var S=0;switch(h.tag){case 31:case 13:var M=h.stateNode,$=h.memoizedState;$!==null&&(S=$.retryLane);break;case 19:M=h.stateNode;break;case 22:M=h.stateNode._retryCache;break;default:throw Error(r(314))}M!==null&&M.delete(y),IB(h,S)}function Wce(h,y){return ge(h,y)}var C_=null,fb=null,Uj=!1,P_=!1,Bj=!1,nh=0;function fd(h){h!==fb&&h.next===null&&(fb===null?C_=fb=h:fb=fb.next=h),P_=!0,Uj||(Uj=!0,Xce())}function pv(h,y){if(!Bj&&P_){Bj=!0;do for(var S=!1,M=C_;M!==null;){if(h!==0){var $=M.pendingLanes;if($===0)var Z=0;else{var Ne=M.suspendedLanes,He=M.pingedLanes;Z=(1<<31-qe(42|h)+1)-1,Z&=$&~(Ne&~He),Z=Z&201326741?Z&201326741|1:Z?Z|2:0}Z!==0&&(S=!0,HB(M,Z))}else Z=xr,Z=de(M,M===oa?Z:0,M.cancelPendingCommit!==null||M.timeoutHandle!==-1),(Z&3)===0||xe(M,Z)||(S=!0,HB(M,Z));M=M.next}while(S);Bj=!1}}function Kce(){zB()}function zB(){P_=Uj=!1;var h=0;nh!==0&&ide()&&(h=nh);for(var y=R(),S=null,M=C_;M!==null;){var $=M.next,Z=UB(M,y);Z===0?(M.next=null,S===null?C_=$:S.next=$,$===null&&(fb=S)):(S=M,(h!==0||(Z&3)!==0)&&(P_=!0)),M=$}Ti!==0&&Ti!==5||pv(h),nh!==0&&(nh=0)}function UB(h,y){for(var S=h.suspendedLanes,M=h.pingedLanes,$=h.expirationTimes,Z=h.pendingLanes&-62914561;0>>=0,h===0?32:31-(Qe(h)/tt|0)|0}var Fe=256,we=262144,Ve=4194304;function je(h){var y=h&42;if(y!==0)return y;switch(h&-h){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 h&261888;case 262144:case 524288:case 1048576:case 2097152:return h&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return h&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return h}}function de(h,y,S){var M=h.pendingLanes;if(M===0)return 0;var $=0,Z=h.suspendedLanes,Ne=h.pingedLanes;h=h.warmLanes;var He=M&134217727;return He!==0?(M=He&~Z,M!==0?$=je(M):(Ne&=He,Ne!==0?$=je(Ne):S||(S=He&~h,S!==0&&($=je(S))))):(He=M&~Z,He!==0?$=je(He):Ne!==0?$=je(Ne):S||(S=M&~h,S!==0&&($=je(S)))),$===0?0:y!==0&&y!==$&&(y&Z)===0&&(Z=$&-$,S=y&-y,Z>=S||Z===32&&(S&4194048)!==0)?y:$}function xe(h,y){return(h.pendingLanes&~(h.suspendedLanes&~h.pingedLanes)&y)===0}function Be(h,y){switch(h){case 1:case 2:case 4:case 8:case 64:return y+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 y+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Ze(){var h=Ve;return Ve<<=1,(Ve&62914560)===0&&(Ve=4194304),h}function pt(h){for(var y=[],S=0;31>S;S++)y.push(h);return y}function xt(h,y){h.pendingLanes|=y,y!==268435456&&(h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0)}function yt(h,y,S,M,$,Z){var Ne=h.pendingLanes;h.pendingLanes=S,h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0,h.expiredLanes&=S,h.entangledLanes&=S,h.errorRecoveryDisabledLanes&=S,h.shellSuspendCounter=0;var He=h.entanglements,nt=h.expirationTimes,Nt=h.hiddenUpdates;for(S=Ne&~S;0"u")return null;try{return h.activeElement||h.body}catch{return h.body}}var Dr=/[\n"\\]/g;function En(h){return h.replace(Dr,function(y){return"\\"+y.charCodeAt(0).toString(16)+" "})}function Ea(h,y,S,M,$,Z,Ne,He){h.name="",Ne!=null&&typeof Ne!="function"&&typeof Ne!="symbol"&&typeof Ne!="boolean"?h.type=Ne:h.removeAttribute("type"),y!=null?Ne==="number"?(y===0&&h.value===""||h.value!=y)&&(h.value=""+zn(y)):h.value!==""+zn(y)&&(h.value=""+zn(y)):Ne!=="submit"&&Ne!=="reset"||h.removeAttribute("value"),y!=null?na(h,Ne,zn(y)):S!=null?na(h,Ne,zn(S)):M!=null&&h.removeAttribute("value"),$==null&&Z!=null&&(h.defaultChecked=!!Z),$!=null&&(h.checked=$&&typeof $!="function"&&typeof $!="symbol"),He!=null&&typeof He!="function"&&typeof He!="symbol"&&typeof He!="boolean"?h.name=""+zn(He):h.removeAttribute("name")}function Pn(h,y,S,M,$,Z,Ne,He){if(Z!=null&&typeof Z!="function"&&typeof Z!="symbol"&&typeof Z!="boolean"&&(h.type=Z),y!=null||S!=null){if(!(Z!=="submit"&&Z!=="reset"||y!=null)){gn(h);return}S=S!=null?""+zn(S):"",y=y!=null?""+zn(y):S,He||y===h.value||(h.value=y),h.defaultValue=y}M=M??$,M=typeof M!="function"&&typeof M!="symbol"&&!!M,h.checked=He?h.checked:!!M,h.defaultChecked=!!M,Ne!=null&&typeof Ne!="function"&&typeof Ne!="symbol"&&typeof Ne!="boolean"&&(h.name=Ne),gn(h)}function na(h,y,S){y==="number"&&gr(h.ownerDocument)===h||h.defaultValue===""+S||(h.defaultValue=""+S)}function qn(h,y,S,M){if(h=h.options,y){y={};for(var $=0;$"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),kl=!1;if(Ns)try{var ns={};Object.defineProperty(ns,"passive",{get:function(){kl=!0}}),window.addEventListener("test",ns,ns),window.removeEventListener("test",ns,ns)}catch{kl=!1}var $o=null,Nl=null,wc=null;function vo(){if(wc)return wc;var h,y=Nl,S=y.length,M,$="value"in $o?$o.value:$o.textContent,Z=$.length;for(h=0;h=ct),ir=" ",aa=!1;function ka(h,y){switch(h){case"keyup":return Ht.indexOf(y.keyCode)!==-1;case"keydown":return y.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Jt(h){return h=h.detail,typeof h=="object"&&"data"in h?h.data:null}var vn=!1;function Da(h,y){switch(h){case"compositionend":return Jt(y);case"keypress":return y.which!==32?null:(aa=!0,ir);case"textInput":return h=y.data,h===ir&&aa?null:h;default:return null}}function di(h,y){if(vn)return h==="compositionend"||!Zt&&ka(h,y)?(h=vo(),wc=Nl=$o=null,vn=!1,h):null;switch(h){case"paste":return null;case"keypress":if(!(y.ctrlKey||y.altKey||y.metaKey)||y.ctrlKey&&y.altKey){if(y.char&&1=y)return{node:S,offset:y-h};h=M}e:{for(;S;){if(S.nextSibling){S=S.nextSibling;break e}S=S.parentNode}S=void 0}S=BS(S)}}function b5(h,y){return h&&y?h===y?!0:h&&h.nodeType===3?!1:y&&y.nodeType===3?b5(h,y.parentNode):"contains"in h?h.contains(y):h.compareDocumentPosition?!!(h.compareDocumentPosition(y)&16):!1:!1}function x5(h){h=h!=null&&h.ownerDocument!=null&&h.ownerDocument.defaultView!=null?h.ownerDocument.defaultView:window;for(var y=gr(h.document);y instanceof h.HTMLIFrameElement;){try{var S=typeof y.contentWindow.location.href=="string"}catch{S=!1}if(S)h=y.contentWindow;else break;y=gr(h.document)}return y}function wA(h){var y=h&&h.nodeName&&h.nodeName.toLowerCase();return y&&(y==="input"&&(h.type==="text"||h.type==="search"||h.type==="tel"||h.type==="url"||h.type==="password")||y==="textarea"||h.contentEditable==="true")}var hce=Ns&&"documentMode"in document&&11>=document.documentMode,Gg=null,SA=null,Vy=null,_A=!1;function y5(h,y,S){var M=S.window===S?S.document:S.nodeType===9?S:S.ownerDocument;_A||Gg==null||Gg!==gr(M)||(M=Gg,"selectionStart"in M&&wA(M)?M={start:M.selectionStart,end:M.selectionEnd}:(M=(M.ownerDocument&&M.ownerDocument.defaultView||window).getSelection(),M={anchorNode:M.anchorNode,anchorOffset:M.anchorOffset,focusNode:M.focusNode,focusOffset:M.focusOffset}),Vy&&Um(Vy,M)||(Vy=M,M=A_(SA,"onSelect"),0>=Ne,$-=Ne,md=1<<32-qe(y)+$|S<<$|M,hd=Z+h}else md=1<Zn?(yr=bn,bn=null):yr=bn.sibling;var Ar=Ct(bt,bn,kt[Zn],Ot);if(Ar===null){bn===null&&(bn=yr);break}h&&bn&&Ar.alternate===null&&y(bt,bn),ut=Z(Ar,ut,Zn),Tr===null?Cn=Ar:Tr.sibling=Ar,Tr=Ar,bn=yr}if(Zn===kt.length)return S(bt,bn),wr&&lu(bt,Zn),Cn;if(bn===null){for(;ZnZn?(yr=bn,bn=null):yr=bn.sibling;var lh=Ct(bt,bn,Ar.value,Ot);if(lh===null){bn===null&&(bn=yr);break}h&&bn&&lh.alternate===null&&y(bt,bn),ut=Z(lh,ut,Zn),Tr===null?Cn=lh:Tr.sibling=lh,Tr=lh,bn=yr}if(Ar.done)return S(bt,bn),wr&&lu(bt,Zn),Cn;if(bn===null){for(;!Ar.done;Zn++,Ar=kt.next())Ar=zt(bt,Ar.value,Ot),Ar!==null&&(ut=Z(Ar,ut,Zn),Tr===null?Cn=Ar:Tr.sibling=Ar,Tr=Ar);return wr&&lu(bt,Zn),Cn}for(bn=M(bn);!Ar.done;Zn++,Ar=kt.next())Ar=Et(bn,bt,Zn,Ar.value,Ot),Ar!==null&&(h&&Ar.alternate!==null&&bn.delete(Ar.key===null?Zn:Ar.key),ut=Z(Ar,ut,Zn),Tr===null?Cn=Ar:Tr.sibling=Ar,Tr=Ar);return h&&bn.forEach(function(Dde){return y(bt,Dde)}),wr&&lu(bt,Zn),Cn}function Wr(bt,ut,kt,Ot){if(typeof kt=="object"&&kt!==null&&kt.type===v&&kt.key===null&&(kt=kt.props.children),typeof kt=="object"&&kt!==null){switch(kt.$$typeof){case f:e:{for(var Cn=kt.key;ut!==null;){if(ut.key===Cn){if(Cn=kt.type,Cn===v){if(ut.tag===7){S(bt,ut.sibling),Ot=$(ut,kt.props.children),Ot.return=bt,bt=Ot;break e}}else if(ut.elementType===Cn||typeof Cn=="object"&&Cn!==null&&Cn.$$typeof===F&&Yp(Cn)===ut.type){S(bt,ut.sibling),Ot=$(ut,kt.props),Qy(Ot,kt),Ot.return=bt,bt=Ot;break e}S(bt,ut);break}else y(bt,ut);ut=ut.sibling}kt.type===v?(Ot=Vp(kt.props.children,bt.mode,Ot,kt.key),Ot.return=bt,bt=Ot):(Ot=GS(kt.type,kt.key,kt.props,null,bt.mode,Ot),Qy(Ot,kt),Ot.return=bt,bt=Ot)}return Ne(bt);case x:e:{for(Cn=kt.key;ut!==null;){if(ut.key===Cn)if(ut.tag===4&&ut.stateNode.containerInfo===kt.containerInfo&&ut.stateNode.implementation===kt.implementation){S(bt,ut.sibling),Ot=$(ut,kt.children||[]),Ot.return=bt,bt=Ot;break e}else{S(bt,ut);break}else y(bt,ut);ut=ut.sibling}Ot=jA(kt,bt.mode,Ot),Ot.return=bt,bt=Ot}return Ne(bt);case F:return kt=Yp(kt),Wr(bt,ut,kt,Ot)}if(te(kt))return mn(bt,ut,kt,Ot);if(z(kt)){if(Cn=z(kt),typeof Cn!="function")throw Error(r(150));return kt=Cn.call(kt),Fn(bt,ut,kt,Ot)}if(typeof kt.then=="function")return Wr(bt,ut,JS(kt),Ot);if(kt.$$typeof===C)return Wr(bt,ut,XS(bt,kt),Ot);e_(bt,kt)}return typeof kt=="string"&&kt!==""||typeof kt=="number"||typeof kt=="bigint"?(kt=""+kt,ut!==null&&ut.tag===6?(S(bt,ut.sibling),Ot=$(ut,kt),Ot.return=bt,bt=Ot):(S(bt,ut),Ot=AA(kt,bt.mode,Ot),Ot.return=bt,bt=Ot),Ne(bt)):S(bt,ut)}return function(bt,ut,kt,Ot){try{Yy=0;var Cn=Wr(bt,ut,kt,Ot);return rb=null,Cn}catch(bn){if(bn===nb||bn===QS)throw bn;var Tr=Yo(29,bn,null,bt.mode);return Tr.lanes=Ot,Tr.return=bt,Tr}}}var Zp=H5(!0),q5=H5(!1),Vm=!1;function HA(h){h.updateQueue={baseState:h.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function qA(h,y){h=h.updateQueue,y.updateQueue===h&&(y.updateQueue={baseState:h.baseState,firstBaseUpdate:h.firstBaseUpdate,lastBaseUpdate:h.lastBaseUpdate,shared:h.shared,callbacks:null})}function Gm(h){return{lane:h,tag:0,payload:null,callback:null,next:null}}function Wm(h,y,S){var M=h.updateQueue;if(M===null)return null;if(M=M.shared,(Fr&2)!==0){var $=M.pending;return $===null?y.next=y:(y.next=$.next,$.next=y),M.pending=y,y=VS(h),C5(h,null,S),y}return $S(h,M,y,S),VS(h)}function Zy(h,y,S){if(y=y.updateQueue,y!==null&&(y=y.shared,(S&4194048)!==0)){var M=y.lanes;M&=h.pendingLanes,S|=M,y.lanes=S,Kt(h,S)}}function $A(h,y){var S=h.updateQueue,M=h.alternate;if(M!==null&&(M=M.updateQueue,S===M)){var $=null,Z=null;if(S=S.firstBaseUpdate,S!==null){do{var Ne={lane:S.lane,tag:S.tag,payload:S.payload,callback:null,next:null};Z===null?$=Z=Ne:Z=Z.next=Ne,S=S.next}while(S!==null);Z===null?$=Z=y:Z=Z.next=y}else $=Z=y;S={baseState:M.baseState,firstBaseUpdate:$,lastBaseUpdate:Z,shared:M.shared,callbacks:M.callbacks},h.updateQueue=S;return}h=S.lastBaseUpdate,h===null?S.firstBaseUpdate=y:h.next=y,S.lastBaseUpdate=y}var VA=!1;function Jy(){if(VA){var h=tb;if(h!==null)throw h}}function ev(h,y,S,M){VA=!1;var $=h.updateQueue;Vm=!1;var Z=$.firstBaseUpdate,Ne=$.lastBaseUpdate,He=$.shared.pending;if(He!==null){$.shared.pending=null;var nt=He,Nt=nt.next;nt.next=null,Ne===null?Z=Nt:Ne.next=Nt,Ne=nt;var Lt=h.alternate;Lt!==null&&(Lt=Lt.updateQueue,He=Lt.lastBaseUpdate,He!==Ne&&(He===null?Lt.firstBaseUpdate=Nt:He.next=Nt,Lt.lastBaseUpdate=nt))}if(Z!==null){var zt=$.baseState;Ne=0,Lt=Nt=nt=null,He=Z;do{var Ct=He.lane&-536870913,Et=Ct!==He.lane;if(Et?(xr&Ct)===Ct:(M&Ct)===Ct){Ct!==0&&Ct===eb&&(VA=!0),Lt!==null&&(Lt=Lt.next={lane:0,tag:He.tag,payload:He.payload,callback:null,next:null});e:{var mn=h,Fn=He;Ct=y;var Wr=S;switch(Fn.tag){case 1:if(mn=Fn.payload,typeof mn=="function"){zt=mn.call(Wr,zt,Ct);break e}zt=mn;break e;case 3:mn.flags=mn.flags&-65537|128;case 0:if(mn=Fn.payload,Ct=typeof mn=="function"?mn.call(Wr,zt,Ct):mn,Ct==null)break e;zt=m({},zt,Ct);break e;case 2:Vm=!0}}Ct=He.callback,Ct!==null&&(h.flags|=64,Et&&(h.flags|=8192),Et=$.callbacks,Et===null?$.callbacks=[Ct]:Et.push(Ct))}else Et={lane:Ct,tag:He.tag,payload:He.payload,callback:He.callback,next:null},Lt===null?(Nt=Lt=Et,nt=zt):Lt=Lt.next=Et,Ne|=Ct;if(He=He.next,He===null){if(He=$.shared.pending,He===null)break;Et=He,He=Et.next,Et.next=null,$.lastBaseUpdate=Et,$.shared.pending=null}}while(!0);Lt===null&&(nt=zt),$.baseState=nt,$.firstBaseUpdate=Nt,$.lastBaseUpdate=Lt,Z===null&&($.shared.lanes=0),Zm|=Ne,h.lanes=Ne,h.memoizedState=zt}}function $5(h,y){if(typeof h!="function")throw Error(r(191,h));h.call(y)}function V5(h,y){var S=h.callbacks;if(S!==null)for(h.callbacks=null,h=0;hZ?Z:8;var Ne=ae.T,He={};ae.T=He,dj(h,!1,y,S);try{var nt=$(),Nt=ae.S;if(Nt!==null&&Nt(He,nt),nt!==null&&typeof nt=="object"&&typeof nt.then=="function"){var Lt=Sce(nt,M);rv(h,y,Lt,tl(h))}else rv(h,y,M,tl(h))}catch(zt){rv(h,y,{then:function(){},status:"rejected",reason:zt},tl())}finally{J.p=Z,Ne!==null&&He.types!==null&&(Ne.types=He.types),ae.T=Ne}}function Tce(){}function lj(h,y,S,M){if(h.tag!==5)throw Error(r(476));var $=_U(h).queue;SU(h,$,y,le,S===null?Tce:function(){return kU(h),S(M)})}function _U(h){var y=h.memoizedState;if(y!==null)return y;y={memoizedState:le,baseState:le,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:mu,lastRenderedState:le},next:null};var S={};return y.next={memoizedState:S,baseState:S,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:mu,lastRenderedState:S},next:null},h.memoizedState=y,h=h.alternate,h!==null&&(h.memoizedState=y),y}function kU(h){var y=_U(h);y.next===null&&(y=h.alternate.memoizedState),rv(h,y.next.queue,{},tl())}function cj(){return as(vv)}function NU(){return ai().memoizedState}function CU(){return ai().memoizedState}function Ace(h){for(var y=h.return;y!==null;){switch(y.tag){case 24:case 3:var S=tl();h=Gm(S);var M=Wm(y,h,S);M!==null&&(Co(M,y,S),Zy(M,y,S)),y={cache:IA()},h.payload=y;return}y=y.return}}function jce(h,y,S){var M=tl();S={lane:M,revertLane:0,gesture:null,action:S,hasEagerState:!1,eagerState:null,next:null},d_(h)?TU(y,S):(S=PA(h,y,S,M),S!==null&&(Co(S,h,M),AU(S,y,M)))}function PU(h,y,S){var M=tl();rv(h,y,S,M)}function rv(h,y,S,M){var $={lane:M,revertLane:0,gesture:null,action:S,hasEagerState:!1,eagerState:null,next:null};if(d_(h))TU(y,$);else{var Z=h.alternate;if(h.lanes===0&&(Z===null||Z.lanes===0)&&(Z=y.lastRenderedReducer,Z!==null))try{var Ne=y.lastRenderedState,He=Z(Ne,S);if($.hasEagerState=!0,$.eagerState=He,js(He,Ne))return $S(h,y,$,0),oa===null&&qS(),!1}catch{}if(S=PA(h,y,$,M),S!==null)return Co(S,h,M),AU(S,y,M),!0}return!1}function dj(h,y,S,M){if(M={lane:2,revertLane:Hj(),gesture:null,action:M,hasEagerState:!1,eagerState:null,next:null},d_(h)){if(y)throw Error(r(479))}else y=PA(h,S,M,2),y!==null&&Co(y,h,2)}function d_(h){var y=h.alternate;return h===Yn||y!==null&&y===Yn}function TU(h,y){ib=r_=!0;var S=h.pending;S===null?y.next=y:(y.next=S.next,S.next=y),h.pending=y}function AU(h,y,S){if((S&4194048)!==0){var M=y.lanes;M&=h.pendingLanes,S|=M,y.lanes=S,Kt(h,S)}}var av={readContext:as,use:s_,useCallback:Ba,useContext:Ba,useEffect:Ba,useImperativeHandle:Ba,useLayoutEffect:Ba,useInsertionEffect:Ba,useMemo:Ba,useReducer:Ba,useRef:Ba,useState:Ba,useDebugValue:Ba,useDeferredValue:Ba,useTransition:Ba,useSyncExternalStore:Ba,useId:Ba,useHostTransitionStatus:Ba,useFormState:Ba,useActionState:Ba,useOptimistic:Ba,useMemoCache:Ba,useCacheRefresh:Ba};av.useEffectEvent=Ba;var jU={readContext:as,use:s_,useCallback:function(h,y){return Qs().memoizedState=[h,y===void 0?null:y],h},useContext:as,useEffect:hU,useImperativeHandle:function(h,y,S){S=S!=null?S.concat([h]):null,l_(4194308,4,bU.bind(null,y,h),S)},useLayoutEffect:function(h,y){return l_(4194308,4,h,y)},useInsertionEffect:function(h,y){l_(4,2,h,y)},useMemo:function(h,y){var S=Qs();y=y===void 0?null:y;var M=h();if(Jp){Oe(!0);try{h()}finally{Oe(!1)}}return S.memoizedState=[M,y],M},useReducer:function(h,y,S){var M=Qs();if(S!==void 0){var $=S(y);if(Jp){Oe(!0);try{S(y)}finally{Oe(!1)}}}else $=y;return M.memoizedState=M.baseState=$,h={pending:null,lanes:0,dispatch:null,lastRenderedReducer:h,lastRenderedState:$},M.queue=h,h=h.dispatch=jce.bind(null,Yn,h),[M.memoizedState,h]},useRef:function(h){var y=Qs();return h={current:h},y.memoizedState=h},useState:function(h){h=rj(h);var y=h.queue,S=PU.bind(null,Yn,y);return y.dispatch=S,[h.memoizedState,S]},useDebugValue:sj,useDeferredValue:function(h,y){var S=Qs();return oj(S,h,y)},useTransition:function(){var h=rj(!1);return h=SU.bind(null,Yn,h.queue,!0,!1),Qs().memoizedState=h,[!1,h]},useSyncExternalStore:function(h,y,S){var M=Yn,$=Qs();if(wr){if(S===void 0)throw Error(r(407));S=S()}else{if(S=y(),oa===null)throw Error(r(349));(xr&127)!==0||Q5(M,y,S)}$.memoizedState=S;var Z={value:S,getSnapshot:y};return $.queue=Z,hU(J5.bind(null,M,Z,h),[h]),M.flags|=2048,ob(9,{destroy:void 0},Z5.bind(null,M,Z,S,y),null),S},useId:function(){var h=Qs(),y=oa.identifierPrefix;if(wr){var S=hd,M=md;S=(M&~(1<<32-qe(M)-1)).toString(32)+S,y="_"+y+"R_"+S,S=a_++,0<\/script>",Z=Z.removeChild(Z.firstChild);break;case"select":Z=typeof M.is=="string"?Ne.createElement("select",{is:M.is}):Ne.createElement("select"),M.multiple?Z.multiple=!0:M.size&&(Z.size=M.size);break;default:Z=typeof M.is=="string"?Ne.createElement($,{is:M.is}):Ne.createElement($)}}Z[at]=y,Z[dt]=M;e:for(Ne=y.child;Ne!==null;){if(Ne.tag===5||Ne.tag===6)Z.appendChild(Ne.stateNode);else if(Ne.tag!==4&&Ne.tag!==27&&Ne.child!==null){Ne.child.return=Ne,Ne=Ne.child;continue}if(Ne===y)break e;for(;Ne.sibling===null;){if(Ne.return===null||Ne.return===y)break e;Ne=Ne.return}Ne.sibling.return=Ne.return,Ne=Ne.sibling}y.stateNode=Z;e:switch(ss(Z,$,M),$){case"button":case"input":case"select":case"textarea":M=!!M.autoFocus;break e;case"img":M=!0;break e;default:M=!1}M&&pu(y)}}return va(y),kj(y,y.type,h===null?null:h.memoizedProps,y.pendingProps,S),null;case 6:if(h&&y.stateNode!=null)h.memoizedProps!==M&&pu(y);else{if(typeof M!="string"&&y.stateNode===null)throw Error(r(166));if(h=q.current,Zg(y)){if(h=y.stateNode,S=y.memoizedProps,M=null,$=rs,$!==null)switch($.tag){case 27:case 5:M=$.memoizedProps}h[at]=y,h=!!(h.nodeValue===S||M!==null&&M.suppressHydrationWarning===!0||XB(h.nodeValue,S)),h||qm(y,!0)}else h=j_(h).createTextNode(M),h[at]=y,y.stateNode=h}return va(y),null;case 31:if(S=y.memoizedState,h===null||h.memoizedState!==null){if(M=Zg(y),S!==null){if(h===null){if(!M)throw Error(r(318));if(h=y.memoizedState,h=h!==null?h.dehydrated:null,!h)throw Error(r(557));h[at]=y}else Gp(),(y.flags&128)===0&&(y.memoizedState=null),y.flags|=4;va(y),h=!1}else S=FA(),h!==null&&h.memoizedState!==null&&(h.memoizedState.hydrationErrors=S),h=!0;if(!h)return y.flags&256?(Zo(y),y):(Zo(y),null);if((y.flags&128)!==0)throw Error(r(558))}return va(y),null;case 13:if(M=y.memoizedState,h===null||h.memoizedState!==null&&h.memoizedState.dehydrated!==null){if($=Zg(y),M!==null&&M.dehydrated!==null){if(h===null){if(!$)throw Error(r(318));if($=y.memoizedState,$=$!==null?$.dehydrated:null,!$)throw Error(r(317));$[at]=y}else Gp(),(y.flags&128)===0&&(y.memoizedState=null),y.flags|=4;va(y),$=!1}else $=FA(),h!==null&&h.memoizedState!==null&&(h.memoizedState.hydrationErrors=$),$=!0;if(!$)return y.flags&256?(Zo(y),y):(Zo(y),null)}return Zo(y),(y.flags&128)!==0?(y.lanes=S,y):(S=M!==null,h=h!==null&&h.memoizedState!==null,S&&(M=y.child,$=null,M.alternate!==null&&M.alternate.memoizedState!==null&&M.alternate.memoizedState.cachePool!==null&&($=M.alternate.memoizedState.cachePool.pool),Z=null,M.memoizedState!==null&&M.memoizedState.cachePool!==null&&(Z=M.memoizedState.cachePool.pool),Z!==$&&(M.flags|=2048)),S!==h&&S&&(y.child.flags|=8192),f_(y,y.updateQueue),va(y),null);case 4:return j(),h===null&&Gj(y.stateNode.containerInfo),va(y),null;case 10:return du(y.type),va(y),null;case 19:if(ne(ri),M=y.memoizedState,M===null)return va(y),null;if($=(y.flags&128)!==0,Z=M.rendering,Z===null)if($)sv(M,!1);else{if(Ha!==0||h!==null&&(h.flags&128)!==0)for(h=y.child;h!==null;){if(Z=n_(h),Z!==null){for(y.flags|=128,sv(M,!1),h=Z.updateQueue,y.updateQueue=h,f_(y,h),y.subtreeFlags=0,h=S,S=y.child;S!==null;)P5(S,h),S=S.sibling;return fe(ri,ri.current&1|2),wr&&lu(y,M.treeForkCount),y.child}h=h.sibling}M.tail!==null&&R()>v_&&(y.flags|=128,$=!0,sv(M,!1),y.lanes=4194304)}else{if(!$)if(h=n_(Z),h!==null){if(y.flags|=128,$=!0,h=h.updateQueue,y.updateQueue=h,f_(y,h),sv(M,!0),M.tail===null&&M.tailMode==="hidden"&&!Z.alternate&&!wr)return va(y),null}else 2*R()-M.renderingStartTime>v_&&S!==536870912&&(y.flags|=128,$=!0,sv(M,!1),y.lanes=4194304);M.isBackwards?(Z.sibling=y.child,y.child=Z):(h=M.last,h!==null?h.sibling=Z:y.child=Z,M.last=Z)}return M.tail!==null?(h=M.tail,M.rendering=h,M.tail=h.sibling,M.renderingStartTime=R(),h.sibling=null,S=ri.current,fe(ri,$?S&1|2:S&1),wr&&lu(y,M.treeForkCount),h):(va(y),null);case 22:case 23:return Zo(y),WA(),M=y.memoizedState!==null,h!==null?h.memoizedState!==null!==M&&(y.flags|=8192):M&&(y.flags|=8192),M?(S&536870912)!==0&&(y.flags&128)===0&&(va(y),y.subtreeFlags&6&&(y.flags|=8192)):va(y),S=y.updateQueue,S!==null&&f_(y,S.retryQueue),S=null,h!==null&&h.memoizedState!==null&&h.memoizedState.cachePool!==null&&(S=h.memoizedState.cachePool.pool),M=null,y.memoizedState!==null&&y.memoizedState.cachePool!==null&&(M=y.memoizedState.cachePool.pool),M!==S&&(y.flags|=2048),h!==null&&ne(Xp),null;case 24:return S=null,h!==null&&(S=h.memoizedState.cache),y.memoizedState.cache!==S&&(y.flags|=2048),du(ui),va(y),null;case 25:return null;case 30:return null}throw Error(r(156,y.tag))}function Rce(h,y){switch(EA(y),y.tag){case 1:return h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 3:return du(ui),j(),h=y.flags,(h&65536)!==0&&(h&128)===0?(y.flags=h&-65537|128,y):null;case 26:case 27:case 5:return K(y),null;case 31:if(y.memoizedState!==null){if(Zo(y),y.alternate===null)throw Error(r(340));Gp()}return h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 13:if(Zo(y),h=y.memoizedState,h!==null&&h.dehydrated!==null){if(y.alternate===null)throw Error(r(340));Gp()}return h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 19:return ne(ri),null;case 4:return j(),null;case 10:return du(y.type),null;case 22:case 23:return Zo(y),WA(),h!==null&&ne(Xp),h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 24:return du(ui),null;case 25:return null;default:return null}}function eB(h,y){switch(EA(y),y.tag){case 3:du(ui),j();break;case 26:case 27:case 5:K(y);break;case 4:j();break;case 31:y.memoizedState!==null&&Zo(y);break;case 13:Zo(y);break;case 19:ne(ri);break;case 10:du(y.type);break;case 22:case 23:Zo(y),WA(),h!==null&&ne(Xp);break;case 24:du(ui)}}function ov(h,y){try{var S=y.updateQueue,M=S!==null?S.lastEffect:null;if(M!==null){var $=M.next;S=$;do{if((S.tag&h)===h){M=void 0;var Z=S.create,Ne=S.inst;M=Z(),Ne.destroy=M}S=S.next}while(S!==$)}}catch(He){Br(y,y.return,He)}}function Ym(h,y,S){try{var M=y.updateQueue,$=M!==null?M.lastEffect:null;if($!==null){var Z=$.next;M=Z;do{if((M.tag&h)===h){var Ne=M.inst,He=Ne.destroy;if(He!==void 0){Ne.destroy=void 0,$=y;var nt=S,Nt=He;try{Nt()}catch(Lt){Br($,nt,Lt)}}}M=M.next}while(M!==Z)}}catch(Lt){Br(y,y.return,Lt)}}function tB(h){var y=h.updateQueue;if(y!==null){var S=h.stateNode;try{V5(y,S)}catch(M){Br(h,h.return,M)}}}function nB(h,y,S){S.props=ef(h.type,h.memoizedProps),S.state=h.memoizedState;try{S.componentWillUnmount()}catch(M){Br(h,y,M)}}function lv(h,y){try{var S=h.ref;if(S!==null){switch(h.tag){case 26:case 27:case 5:var M=h.stateNode;break;case 30:M=h.stateNode;break;default:M=h.stateNode}typeof S=="function"?h.refCleanup=S(M):S.current=M}}catch($){Br(h,y,$)}}function pd(h,y){var S=h.ref,M=h.refCleanup;if(S!==null)if(typeof M=="function")try{M()}catch($){Br(h,y,$)}finally{h.refCleanup=null,h=h.alternate,h!=null&&(h.refCleanup=null)}else if(typeof S=="function")try{S(null)}catch($){Br(h,y,$)}else S.current=null}function rB(h){var y=h.type,S=h.memoizedProps,M=h.stateNode;try{e:switch(y){case"button":case"input":case"select":case"textarea":S.autoFocus&&M.focus();break e;case"img":S.src?M.src=S.src:S.srcSet&&(M.srcset=S.srcSet)}}catch($){Br(h,h.return,$)}}function Nj(h,y,S){try{var M=h.stateNode;rde(M,h.type,S,y),M[dt]=y}catch($){Br(h,h.return,$)}}function aB(h){return h.tag===5||h.tag===3||h.tag===26||h.tag===27&&rh(h.type)||h.tag===4}function Cj(h){e:for(;;){for(;h.sibling===null;){if(h.return===null||aB(h.return))return null;h=h.return}for(h.sibling.return=h.return,h=h.sibling;h.tag!==5&&h.tag!==6&&h.tag!==18;){if(h.tag===27&&rh(h.type)||h.flags&2||h.child===null||h.tag===4)continue e;h.child.return=h,h=h.child}if(!(h.flags&2))return h.stateNode}}function Pj(h,y,S){var M=h.tag;if(M===5||M===6)h=h.stateNode,y?(S.nodeType===9?S.body:S.nodeName==="HTML"?S.ownerDocument.body:S).insertBefore(h,y):(y=S.nodeType===9?S.body:S.nodeName==="HTML"?S.ownerDocument.body:S,y.appendChild(h),S=S._reactRootContainer,S!=null||y.onclick!==null||(y.onclick=qt));else if(M!==4&&(M===27&&rh(h.type)&&(S=h.stateNode,y=null),h=h.child,h!==null))for(Pj(h,y,S),h=h.sibling;h!==null;)Pj(h,y,S),h=h.sibling}function g_(h,y,S){var M=h.tag;if(M===5||M===6)h=h.stateNode,y?S.insertBefore(h,y):S.appendChild(h);else if(M!==4&&(M===27&&rh(h.type)&&(S=h.stateNode),h=h.child,h!==null))for(g_(h,y,S),h=h.sibling;h!==null;)g_(h,y,S),h=h.sibling}function iB(h){var y=h.stateNode,S=h.memoizedProps;try{for(var M=h.type,$=y.attributes;$.length;)y.removeAttributeNode($[0]);ss(y,M,S),y[at]=h,y[dt]=S}catch(Z){Br(h,h.return,Z)}}var fu=!1,pi=!1,Tj=!1,sB=typeof WeakSet=="function"?WeakSet:Set,Hi=null;function Lce(h,y){if(h=h.containerInfo,Xj=O_,h=x5(h),wA(h)){if("selectionStart"in h)var S={start:h.selectionStart,end:h.selectionEnd};else e:{S=(S=h.ownerDocument)&&S.defaultView||window;var M=S.getSelection&&S.getSelection();if(M&&M.rangeCount!==0){S=M.anchorNode;var $=M.anchorOffset,Z=M.focusNode;M=M.focusOffset;try{S.nodeType,Z.nodeType}catch{S=null;break e}var Ne=0,He=-1,nt=-1,Nt=0,Lt=0,zt=h,Ct=null;t:for(;;){for(var Et;zt!==S||$!==0&&zt.nodeType!==3||(He=Ne+$),zt!==Z||M!==0&&zt.nodeType!==3||(nt=Ne+M),zt.nodeType===3&&(Ne+=zt.nodeValue.length),(Et=zt.firstChild)!==null;)Ct=zt,zt=Et;for(;;){if(zt===h)break t;if(Ct===S&&++Nt===$&&(He=Ne),Ct===Z&&++Lt===M&&(nt=Ne),(Et=zt.nextSibling)!==null)break;zt=Ct,Ct=zt.parentNode}zt=Et}S=He===-1||nt===-1?null:{start:He,end:nt}}else S=null}S=S||{start:0,end:0}}else S=null;for(Yj={focusedElem:h,selectionRange:S},O_=!1,Hi=y;Hi!==null;)if(y=Hi,h=y.child,(y.subtreeFlags&1028)!==0&&h!==null)h.return=y,Hi=h;else for(;Hi!==null;){switch(y=Hi,Z=y.alternate,h=y.flags,y.tag){case 0:if((h&4)!==0&&(h=y.updateQueue,h=h!==null?h.events:null,h!==null))for(S=0;S title"))),ss(Z,M,S),Z[at]=h,Ke(Z),M=Z;break e;case"link":var Ne=m8("link","href",$).get(M+(S.href||""));if(Ne){for(var He=0;HeWr&&(Ne=Wr,Wr=Fn,Fn=Ne);var bt=g5(He,Fn),ut=g5(He,Wr);if(bt&&ut&&(Et.rangeCount!==1||Et.anchorNode!==bt.node||Et.anchorOffset!==bt.offset||Et.focusNode!==ut.node||Et.focusOffset!==ut.offset)){var kt=zt.createRange();kt.setStart(bt.node,bt.offset),Et.removeAllRanges(),Fn>Wr?(Et.addRange(kt),Et.extend(ut.node,ut.offset)):(kt.setEnd(ut.node,ut.offset),Et.addRange(kt))}}}}for(zt=[],Et=He;Et=Et.parentNode;)Et.nodeType===1&&zt.push({element:Et,left:Et.scrollLeft,top:Et.scrollTop});for(typeof He.focus=="function"&&He.focus(),He=0;HeS?32:S,ae.T=null,S=Rj,Rj=null;var Z=eh,Ne=vu;if(Ti=0,mb=eh=null,vu=0,(Fr&6)!==0)throw Error(r(331));var He=Fr;if(Fr|=4,bB(Z.current),pB(Z,Z.current,Ne,S),Fr=He,pv(0,!1),Le&&typeof Le.onPostCommitFiberRoot=="function")try{Le.onPostCommitFiberRoot(Me,Z)}catch{}return!0}finally{J.p=$,ae.T=M,RB(h,y)}}function OB(h,y,S){y=Al(S,y),y=pj(h.stateNode,y,2),h=Wm(h,y,2),h!==null&&(xt(h,2),fd(h))}function Br(h,y,S){if(h.tag===3)OB(h,h,S);else for(;y!==null;){if(y.tag===3){OB(y,h,S);break}else if(y.tag===1){var M=y.stateNode;if(typeof y.type.getDerivedStateFromError=="function"||typeof M.componentDidCatch=="function"&&(Jm===null||!Jm.has(M))){h=Al(S,h),S=IU(2),M=Wm(y,S,2),M!==null&&(zU(S,M,y,h),xt(M,2),fd(M));break}}y=y.return}}function zj(h,y,S){var M=h.pingCache;if(M===null){M=h.pingCache=new zce;var $=new Set;M.set(y,$)}else $=M.get(y),$===void 0&&($=new Set,M.set(y,$));$.has(S)||(Mj=!0,$.add(S),h=$ce.bind(null,h,y,S),y.then(h,h))}function $ce(h,y,S){var M=h.pingCache;M!==null&&M.delete(y),h.pingedLanes|=h.suspendedLanes&S,h.warmLanes&=~S,oa===h&&(xr&S)===S&&(Ha===4||Ha===3&&(xr&62914560)===xr&&300>R()-y_?(Fr&2)===0&&hb(h,0):Ej|=S,ub===xr&&(ub=0)),fd(h)}function IB(h,y){y===0&&(y=Ze()),h=$p(h,y),h!==null&&(xt(h,y),fd(h))}function Vce(h){var y=h.memoizedState,S=0;y!==null&&(S=y.retryLane),IB(h,S)}function Gce(h,y){var S=0;switch(h.tag){case 31:case 13:var M=h.stateNode,$=h.memoizedState;$!==null&&(S=$.retryLane);break;case 19:M=h.stateNode;break;case 22:M=h.stateNode._retryCache;break;default:throw Error(r(314))}M!==null&&M.delete(y),IB(h,S)}function Wce(h,y){return ge(h,y)}var C_=null,fb=null,Uj=!1,P_=!1,Bj=!1,nh=0;function fd(h){h!==fb&&h.next===null&&(fb===null?C_=fb=h:fb=fb.next=h),P_=!0,Uj||(Uj=!0,Xce())}function pv(h,y){if(!Bj&&P_){Bj=!0;do for(var S=!1,M=C_;M!==null;){if(h!==0){var $=M.pendingLanes;if($===0)var Z=0;else{var Ne=M.suspendedLanes,He=M.pingedLanes;Z=(1<<31-qe(42|h)+1)-1,Z&=$&~(Ne&~He),Z=Z&201326741?Z&201326741|1:Z?Z|2:0}Z!==0&&(S=!0,HB(M,Z))}else Z=xr,Z=de(M,M===oa?Z:0,M.cancelPendingCommit!==null||M.timeoutHandle!==-1),(Z&3)===0||xe(M,Z)||(S=!0,HB(M,Z));M=M.next}while(S);Bj=!1}}function Kce(){zB()}function zB(){P_=Uj=!1;var h=0;nh!==0&&ide()&&(h=nh);for(var y=R(),S=null,M=C_;M!==null;){var $=M.next,Z=UB(M,y);Z===0?(M.next=null,S===null?C_=$:S.next=$,$===null&&(fb=S)):(S=M,(h!==0||(Z&3)!==0)&&(P_=!0)),M=$}Ti!==0&&Ti!==5||pv(h),nh!==0&&(nh=0)}function UB(h,y){for(var S=h.suspendedLanes,M=h.pingedLanes,$=h.expirationTimes,Z=h.pendingLanes&-62914561;0He)break;var Lt=nt.transferSize,zt=nt.initiatorType;Lt&&YB(zt)&&(nt=nt.responseEnd,Ne+=Lt*(nt"u"?null:document;function l8(h,y,S){var M=gb;if(M&&typeof y=="string"&&y){var $=En(y);$='link[rel="'+h+'"][href="'+$+'"]',typeof S=="string"&&($+='[crossorigin="'+S+'"]'),o8.has($)||(o8.add($),h={rel:h,crossOrigin:S,href:y},M.querySelector($)===null&&(y=M.createElement("link"),ss(y,"link",h),Ke(y),M.head.appendChild(y)))}}function pde(h){wu.D(h),l8("dns-prefetch",h,null)}function fde(h,y){wu.C(h,y),l8("preconnect",h,y)}function gde(h,y,S){wu.L(h,y,S);var M=gb;if(M&&h&&y){var $='link[rel="preload"][as="'+En(y)+'"]';y==="image"&&S&&S.imageSrcSet?($+='[imagesrcset="'+En(S.imageSrcSet)+'"]',typeof S.imageSizes=="string"&&($+='[imagesizes="'+En(S.imageSizes)+'"]')):$+='[href="'+En(h)+'"]';var Z=$;switch(y){case"style":Z=bb(h);break;case"script":Z=xb(h)}Rl.has(Z)||(h=m({rel:"preload",href:y==="image"&&S&&S.imageSrcSet?void 0:h,as:y},S),Rl.set(Z,h),M.querySelector($)!==null||y==="style"&&M.querySelector(xv(Z))||y==="script"&&M.querySelector(yv(Z))||(y=M.createElement("link"),ss(y,"link",h),Ke(y),M.head.appendChild(y)))}}function bde(h,y){wu.m(h,y);var S=gb;if(S&&h){var M=y&&typeof y.as=="string"?y.as:"script",$='link[rel="modulepreload"][as="'+En(M)+'"][href="'+En(h)+'"]',Z=$;switch(M){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":Z=xb(h)}if(!Rl.has(Z)&&(h=m({rel:"modulepreload",href:h},y),Rl.set(Z,h),S.querySelector($)===null)){switch(M){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(S.querySelector(yv(Z)))return}M=S.createElement("link"),ss(M,"link",h),Ke(M),S.head.appendChild(M)}}}function xde(h,y,S){wu.S(h,y,S);var M=gb;if(M&&h){var $=et(M).hoistableStyles,Z=bb(h);y=y||"default";var Ne=$.get(Z);if(!Ne){var He={loading:0,preload:null};if(Ne=M.querySelector(xv(Z)))He.loading=5;else{h=m({rel:"stylesheet",href:h,"data-precedence":y},S),(S=Rl.get(Z))&&rM(h,S);var nt=Ne=M.createElement("link");Ke(nt),ss(nt,"link",h),nt._p=new Promise(function(Nt,Lt){nt.onload=Nt,nt.onerror=Lt}),nt.addEventListener("load",function(){He.loading|=1}),nt.addEventListener("error",function(){He.loading|=2}),He.loading|=4,E_(Ne,y,M)}Ne={type:"stylesheet",instance:Ne,count:1,state:He},$.set(Z,Ne)}}}function yde(h,y){wu.X(h,y);var S=gb;if(S&&h){var M=et(S).hoistableScripts,$=xb(h),Z=M.get($);Z||(Z=S.querySelector(yv($)),Z||(h=m({src:h,async:!0},y),(y=Rl.get($))&&aM(h,y),Z=S.createElement("script"),Ke(Z),ss(Z,"link",h),S.head.appendChild(Z)),Z={type:"script",instance:Z,count:1,state:null},M.set($,Z))}}function vde(h,y){wu.M(h,y);var S=gb;if(S&&h){var M=et(S).hoistableScripts,$=xb(h),Z=M.get($);Z||(Z=S.querySelector(yv($)),Z||(h=m({src:h,async:!0,type:"module"},y),(y=Rl.get($))&&aM(h,y),Z=S.createElement("script"),Ke(Z),ss(Z,"link",h),S.head.appendChild(Z)),Z={type:"script",instance:Z,count:1,state:null},M.set($,Z))}}function c8(h,y,S,M){var $=($=q.current)?M_($):null;if(!$)throw Error(r(446));switch(h){case"meta":case"title":return null;case"style":return typeof S.precedence=="string"&&typeof S.href=="string"?(y=bb(S.href),S=et($).hoistableStyles,M=S.get(y),M||(M={type:"style",instance:null,count:0,state:null},S.set(y,M)),M):{type:"void",instance:null,count:0,state:null};case"link":if(S.rel==="stylesheet"&&typeof S.href=="string"&&typeof S.precedence=="string"){h=bb(S.href);var Z=et($).hoistableStyles,Ne=Z.get(h);if(Ne||($=$.ownerDocument||$,Ne={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},Z.set(h,Ne),(Z=$.querySelector(xv(h)))&&!Z._p&&(Ne.instance=Z,Ne.state.loading=5),Rl.has(h)||(S={rel:"preload",as:"style",href:S.href,crossOrigin:S.crossOrigin,integrity:S.integrity,media:S.media,hrefLang:S.hrefLang,referrerPolicy:S.referrerPolicy},Rl.set(h,S),Z||wde($,h,S,Ne.state))),y&&M===null)throw Error(r(528,""));return Ne}if(y&&M!==null)throw Error(r(529,""));return null;case"script":return y=S.async,S=S.src,typeof S=="string"&&y&&typeof y!="function"&&typeof y!="symbol"?(y=xb(S),S=et($).hoistableScripts,M=S.get(y),M||(M={type:"script",instance:null,count:0,state:null},S.set(y,M)),M):{type:"void",instance:null,count:0,state:null};default:throw Error(r(444,h))}}function bb(h){return'href="'+En(h)+'"'}function xv(h){return'link[rel="stylesheet"]['+h+"]"}function d8(h){return m({},h,{"data-precedence":h.precedence,precedence:null})}function wde(h,y,S,M){h.querySelector('link[rel="preload"][as="style"]['+y+"]")?M.loading=1:(y=h.createElement("link"),M.preload=y,y.addEventListener("load",function(){return M.loading|=1}),y.addEventListener("error",function(){return M.loading|=2}),ss(y,"link",S),Ke(y),h.head.appendChild(y))}function xb(h){return'[src="'+En(h)+'"]'}function yv(h){return"script[async]"+h}function u8(h,y,S){if(y.count++,y.instance===null)switch(y.type){case"style":var M=h.querySelector('style[data-href~="'+En(S.href)+'"]');if(M)return y.instance=M,Ke(M),M;var $=m({},S,{"data-href":S.href,"data-precedence":S.precedence,href:null,precedence:null});return M=(h.ownerDocument||h).createElement("style"),Ke(M),ss(M,"style",$),E_(M,S.precedence,h),y.instance=M;case"stylesheet":$=bb(S.href);var Z=h.querySelector(xv($));if(Z)return y.state.loading|=4,y.instance=Z,Ke(Z),Z;M=d8(S),($=Rl.get($))&&rM(M,$),Z=(h.ownerDocument||h).createElement("link"),Ke(Z);var Ne=Z;return Ne._p=new Promise(function(He,nt){Ne.onload=He,Ne.onerror=nt}),ss(Z,"link",M),y.state.loading|=4,E_(Z,S.precedence,h),y.instance=Z;case"script":return Z=xb(S.src),($=h.querySelector(yv(Z)))?(y.instance=$,Ke($),$):(M=S,($=Rl.get(Z))&&(M=m({},S),aM(M,$)),h=h.ownerDocument||h,$=h.createElement("script"),Ke($),ss($,"link",M),h.head.appendChild($),y.instance=$);case"void":return null;default:throw Error(r(443,y.type))}else y.type==="stylesheet"&&(y.state.loading&4)===0&&(M=y.instance,y.state.loading|=4,E_(M,S.precedence,h));return y.instance}function E_(h,y,S){for(var M=S.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),$=M.length?M[M.length-1]:null,Z=$,Ne=0;Ne title"):null)}function Sde(h,y,S){if(S===1||y.itemProp!=null)return!1;switch(h){case"meta":case"title":return!0;case"style":if(typeof y.precedence!="string"||typeof y.href!="string"||y.href==="")break;return!0;case"link":if(typeof y.rel!="string"||typeof y.href!="string"||y.href===""||y.onLoad||y.onError)break;return y.rel==="stylesheet"?(h=y.disabled,typeof y.precedence=="string"&&h==null):!0;case"script":if(y.async&&typeof y.async!="function"&&typeof y.async!="symbol"&&!y.onLoad&&!y.onError&&y.src&&typeof y.src=="string")return!0}return!1}function p8(h){return!(h.type==="stylesheet"&&(h.state.loading&3)===0)}function _de(h,y,S,M){if(S.type==="stylesheet"&&(typeof M.media!="string"||matchMedia(M.media).matches!==!1)&&(S.state.loading&4)===0){if(S.instance===null){var $=bb(M.href),Z=y.querySelector(xv($));if(Z){y=Z._p,y!==null&&typeof y=="object"&&typeof y.then=="function"&&(h.count++,h=F_.bind(h),y.then(h,h)),S.state.loading|=4,S.instance=Z,Ke(Z);return}Z=y.ownerDocument||y,M=d8(M),($=Rl.get($))&&rM(M,$),Z=Z.createElement("link"),Ke(Z);var Ne=Z;Ne._p=new Promise(function(He,nt){Ne.onload=He,Ne.onerror=nt}),ss(Z,"link",M),S.instance=Z}h.stylesheets===null&&(h.stylesheets=new Map),h.stylesheets.set(S,y),(y=S.state.preload)&&(S.state.loading&3)===0&&(h.count++,S=F_.bind(h),y.addEventListener("load",S),y.addEventListener("error",S))}}var iM=0;function kde(h,y){return h.stylesheets&&h.count===0&&L_(h,h.stylesheets),0iM?50:800)+y);return h.unsuspend=S,function(){h.unsuspend=null,clearTimeout(M),clearTimeout($)}}:null}function F_(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)L_(this,this.stylesheets);else if(this.unsuspend){var h=this.unsuspend;this.unsuspend=null,h()}}}var R_=null;function L_(h,y){h.stylesheets=null,h.unsuspend!==null&&(h.count++,R_=new Map,y.forEach(Nde,h),R_=null,F_.call(h))}function Nde(h,y){if(!(y.state.loading&4)){var S=R_.get(h);if(S)var M=S.get(null);else{S=new Map,R_.set(h,S);for(var $=h.querySelectorAll("link[data-precedence],style[data-precedence]"),Z=0;Z<$.length;Z++){var Ne=$[Z];(Ne.nodeName==="LINK"||Ne.getAttribute("media")!=="not all")&&(S.set(Ne.dataset.precedence,Ne),M=Ne)}M&&S.set(null,M)}$=y.instance,Ne=$.getAttribute("data-precedence"),Z=S.get(Ne)||M,Z===M&&S.set(null,$),S.set(Ne,$),this.count++,M=F_.bind(this),$.addEventListener("load",M),$.addEventListener("error",M),Z?Z.parentNode.insertBefore($,Z.nextSibling):(h=h.nodeType===9?h.head:h,h.insertBefore($,h.firstChild)),y.state.loading|=4}}var vv={$$typeof:C,Provider:null,Consumer:null,_currentValue:le,_currentValue2:le,_threadCount:0};function Cde(h,y,S,M,$,Z,Ne,He,nt){this.tag=1,this.containerInfo=h,this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.next=this.pendingContext=this.context=this.cancelPendingCommit=null,this.callbackPriority=0,this.expirationTimes=pt(-1),this.entangledLanes=this.shellSuspendCounter=this.errorRecoveryDisabledLanes=this.expiredLanes=this.warmLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=pt(0),this.hiddenUpdates=pt(null),this.identifierPrefix=M,this.onUncaughtError=$,this.onCaughtError=Z,this.onRecoverableError=Ne,this.pooledCache=null,this.pooledCacheLanes=0,this.formState=nt,this.incompleteTransitions=new Map}function f8(h,y,S,M,$,Z,Ne,He,nt,Nt,Lt,zt){return h=new Cde(h,y,S,Ne,nt,Nt,Lt,zt,He),y=1,Z===!0&&(y|=24),Z=Yo(3,null,null,y),h.current=Z,Z.stateNode=h,y=IA(),y.refCount++,h.pooledCache=y,y.refCount++,Z.memoizedState={element:M,isDehydrated:S,cache:y},HA(Z),h}function g8(h){return h?(h=Xg,h):Xg}function b8(h,y,S,M,$,Z){$=g8($),M.context===null?M.context=$:M.pendingContext=$,M=Gm(y),M.payload={element:S},Z=Z===void 0?null:Z,Z!==null&&(M.callback=Z),S=Wm(h,M,y),S!==null&&(Co(S,h,y),Zy(S,h,y))}function x8(h,y){if(h=h.memoizedState,h!==null&&h.dehydrated!==null){var S=h.retryLane;h.retryLane=S!==0&&S"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(e){console.error(e)}}return t(),pM.exports=Hde(),pM.exports}var $de=qde();const $n=t=>typeof t=="string",Cv=()=>{let t,e;const n=new Promise((r,i)=>{t=r,e=i});return n.resolve=t,n.reject=e,n},I8=t=>t==null?"":""+t,Vde=(t,e,n)=>{t.forEach(r=>{e[r]&&(n[r]=e[r])})},Gde=/###/g,z8=t=>t&&t.indexOf("###")>-1?t.replace(Gde,"."):t,U8=t=>!t||$n(t),_0=(t,e,n)=>{const r=$n(e)?e.split("."):e;let i=0;for(;i{const{obj:r,k:i}=_0(t,e,Object);if(r!==void 0||e.length===1){r[i]=n;return}let s=e[e.length-1],o=e.slice(0,e.length-1),l=_0(t,o,Object);for(;l.obj===void 0&&o.length;)s=`${o[o.length-1]}.${s}`,o=o.slice(0,o.length-1),l=_0(t,o,Object),l?.obj&&typeof l.obj[`${l.k}.${s}`]<"u"&&(l.obj=void 0);l.obj[`${l.k}.${s}`]=n},Wde=(t,e,n,r)=>{const{obj:i,k:s}=_0(t,e,Object);i[s]=i[s]||[],i[s].push(n)},dN=(t,e)=>{const{obj:n,k:r}=_0(t,e);if(n&&Object.prototype.hasOwnProperty.call(n,r))return n[r]},Kde=(t,e,n)=>{const r=dN(t,n);return r!==void 0?r:dN(e,n)},BY=(t,e,n)=>{for(const r in e)r!=="__proto__"&&r!=="constructor"&&(r in t?$n(t[r])||t[r]instanceof String||$n(e[r])||e[r]instanceof String?n&&(t[r]=e[r]):BY(t[r],e[r],n):t[r]=e[r]);return t},vb=t=>t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&");var Xde={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};const Yde=t=>$n(t)?t.replace(/[&<>"'\/]/g,e=>Xde[e]):t;class Qde{constructor(e){this.capacity=e,this.regExpMap=new Map,this.regExpQueue=[]}getRegExp(e){const n=this.regExpMap.get(e);if(n!==void 0)return n;const r=new RegExp(e);return this.regExpQueue.length===this.capacity&&this.regExpMap.delete(this.regExpQueue.shift()),this.regExpMap.set(e,r),this.regExpQueue.push(e),r}}const Zde=[" ",",","?","!",";"],Jde=new Qde(20),eue=(t,e,n)=>{e=e||"",n=n||"";const r=Zde.filter(o=>e.indexOf(o)<0&&n.indexOf(o)<0);if(r.length===0)return!0;const i=Jde.getRegExp(`(${r.map(o=>o==="?"?"\\?":o).join("|")})`);let s=!i.test(t);if(!s){const o=t.indexOf(n);o>0&&!i.test(t.substring(0,o))&&(s=!0)}return s},I3=(t,e,n=".")=>{if(!t)return;if(t[e])return Object.prototype.hasOwnProperty.call(t,e)?t[e]:void 0;const r=e.split(n);let i=t;for(let s=0;s-1&&ct?.replace("_","-"),tue={type:"logger",log(t){this.output("log",t)},warn(t){this.output("warn",t)},error(t){this.output("error",t)},output(t,e){console?.[t]?.apply?.(console,e)}};class uN{constructor(e,n={}){this.init(e,n)}init(e,n={}){this.prefix=n.prefix||"i18next:",this.logger=e||tue,this.options=n,this.debug=n.debug}log(...e){return this.forward(e,"log","",!0)}warn(...e){return this.forward(e,"warn","",!0)}error(...e){return this.forward(e,"error","")}deprecate(...e){return this.forward(e,"warn","WARNING DEPRECATED: ",!0)}forward(e,n,r,i){return i&&!this.debug?null:($n(e[0])&&(e[0]=`${r}${this.prefix} ${e[0]}`),this.logger[n](e))}create(e){return new uN(this.logger,{prefix:`${this.prefix}:${e}:`,...this.options})}clone(e){return e=e||this.options,e.prefix=e.prefix||this.prefix,new uN(this.logger,e)}}var Ed=new uN;let LP=class{constructor(){this.observers={}}on(e,n){return e.split(" ").forEach(r=>{this.observers[r]||(this.observers[r]=new Map);const i=this.observers[r].get(n)||0;this.observers[r].set(n,i+1)}),this}off(e,n){if(this.observers[e]){if(!n){delete this.observers[e];return}this.observers[e].delete(n)}}emit(e,...n){this.observers[e]&&Array.from(this.observers[e].entries()).forEach(([i,s])=>{for(let o=0;o{for(let o=0;o-1&&this.options.ns.splice(n,1)}getResource(e,n,r,i={}){const s=i.keySeparator!==void 0?i.keySeparator:this.options.keySeparator,o=i.ignoreJSONStructure!==void 0?i.ignoreJSONStructure:this.options.ignoreJSONStructure;let l;e.indexOf(".")>-1?l=e.split("."):(l=[e,n],r&&(Array.isArray(r)?l.push(...r):$n(r)&&s?l.push(...r.split(s)):l.push(r)));const c=dN(this.data,l);return!c&&!n&&!r&&e.indexOf(".")>-1&&(e=l[0],n=l[1],r=l.slice(2).join(".")),c||!o||!$n(r)?c:I3(this.data?.[e]?.[n],r,s)}addResource(e,n,r,i,s={silent:!1}){const o=s.keySeparator!==void 0?s.keySeparator:this.options.keySeparator;let l=[e,n];r&&(l=l.concat(o?r.split(o):r)),e.indexOf(".")>-1&&(l=e.split("."),i=n,n=l[1]),this.addNamespaces(n),B8(this.data,l,i),s.silent||this.emit("added",e,n,r,i)}addResources(e,n,r,i={silent:!1}){for(const s in r)($n(r[s])||Array.isArray(r[s]))&&this.addResource(e,n,s,r[s],{silent:!0});i.silent||this.emit("added",e,n,r)}addResourceBundle(e,n,r,i,s,o={silent:!1,skipCopy:!1}){let l=[e,n];e.indexOf(".")>-1&&(l=e.split("."),i=r,r=n,n=l[1]),this.addNamespaces(n);let c=dN(this.data,l)||{};o.skipCopy||(r=JSON.parse(JSON.stringify(r))),i?BY(c,r,s):c={...c,...r},B8(this.data,l,c),o.silent||this.emit("added",e,n,r)}removeResourceBundle(e,n){this.hasResourceBundle(e,n)&&delete this.data[e][n],this.removeNamespaces(n),this.emit("removed",e,n)}hasResourceBundle(e,n){return this.getResource(e,n)!==void 0}getResourceBundle(e,n){return n||(n=this.options.defaultNS),this.getResource(e,n)}getDataByLanguage(e){return this.data[e]}hasLanguageSomeTranslations(e){const n=this.getDataByLanguage(e);return!!(n&&Object.keys(n)||[]).find(i=>n[i]&&Object.keys(n[i]).length>0)}toJSON(){return this.data}}var HY={processors:{},addPostProcessor(t){this.processors[t.name]=t},handle(t,e,n,r,i){return t.forEach(s=>{e=this.processors[s]?.process(e,n,r,i)??e}),e}};const qY=Symbol("i18next/PATH_KEY");function nue(){const t=[],e=Object.create(null);let n;return e.get=(r,i)=>(n?.revoke?.(),i===qY?t:(t.push(i),n=Proxy.revocable(r,e),n.proxy)),Proxy.revocable(Object.create(null),e).proxy}function z3(t,e){const{[qY]:n}=t(nue());return n.join(e?.keySeparator??".")}const q8={},xM=t=>!$n(t)&&typeof t!="boolean"&&typeof t!="number";class mN extends LP{constructor(e,n={}){super(),Vde(["resourceStore","languageUtils","pluralResolver","interpolator","backendConnector","i18nFormat","utils"],e,this),this.options=n,this.options.keySeparator===void 0&&(this.options.keySeparator="."),this.logger=Ed.create("translator")}changeLanguage(e){e&&(this.language=e)}exists(e,n={interpolation:{}}){const r={...n};if(e==null)return!1;const i=this.resolve(e,r);if(i?.res===void 0)return!1;const s=xM(i.res);return!(r.returnObjects===!1&&s)}extractFromKey(e,n){let r=n.nsSeparator!==void 0?n.nsSeparator:this.options.nsSeparator;r===void 0&&(r=":");const i=n.keySeparator!==void 0?n.keySeparator:this.options.keySeparator;let s=n.ns||this.options.defaultNS||[];const o=r&&e.indexOf(r)>-1,l=!this.options.userDefinedKeySeparator&&!n.keySeparator&&!this.options.userDefinedNsSeparator&&!n.nsSeparator&&!eue(e,r,i);if(o&&!l){const c=e.match(this.interpolator.nestingRegexp);if(c&&c.length>0)return{key:e,namespaces:$n(s)?[s]:s};const d=e.split(r);(r!==i||r===i&&this.options.ns.indexOf(d[0])>-1)&&(s=d.shift()),e=d.join(i)}return{key:e,namespaces:$n(s)?[s]:s}}translate(e,n,r){let i=typeof n=="object"?{...n}:n;if(typeof i!="object"&&this.options.overloadTranslationOptionHandler&&(i=this.options.overloadTranslationOptionHandler(arguments)),typeof i=="object"&&(i={...i}),i||(i={}),e==null)return"";typeof e=="function"&&(e=z3(e,{...this.options,...i})),Array.isArray(e)||(e=[String(e)]);const s=i.returnDetails!==void 0?i.returnDetails:this.options.returnDetails,o=i.keySeparator!==void 0?i.keySeparator:this.options.keySeparator,{key:l,namespaces:c}=this.extractFromKey(e[e.length-1],i),d=c[c.length-1];let u=i.nsSeparator!==void 0?i.nsSeparator:this.options.nsSeparator;u===void 0&&(u=":");const m=i.lng||this.language,p=i.appendNamespaceToCIMode||this.options.appendNamespaceToCIMode;if(m?.toLowerCase()==="cimode")return p?s?{res:`${d}${u}${l}`,usedKey:l,exactUsedKey:l,usedLng:m,usedNS:d,usedParams:this.getUsedParamsDetails(i)}:`${d}${u}${l}`:s?{res:l,usedKey:l,exactUsedKey:l,usedLng:m,usedNS:d,usedParams:this.getUsedParamsDetails(i)}:l;const f=this.resolve(e,i);let x=f?.res;const v=f?.usedKey||l,b=f?.exactUsedKey||l,g=["[object Number]","[object Function]","[object RegExp]"],_=i.joinArrays!==void 0?i.joinArrays:this.options.joinArrays,C=!this.i18nFormat||this.i18nFormat.handleAsObject,P=i.count!==void 0&&!$n(i.count),N=mN.hasDefaultValue(i),A=P?this.pluralResolver.getSuffix(m,i.count,i):"",T=i.ordinal&&P?this.pluralResolver.getSuffix(m,i.count,{ordinal:!1}):"",F=P&&!i.ordinal&&i.count===0,k=F&&i[`defaultValue${this.options.pluralSeparator}zero`]||i[`defaultValue${A}`]||i[`defaultValue${T}`]||i.defaultValue;let D=x;C&&!x&&N&&(D=k);const H=xM(D),z=Object.prototype.toString.apply(D);if(C&&D&&H&&g.indexOf(z)<0&&!($n(_)&&Array.isArray(D))){if(!i.returnObjects&&!this.options.returnObjects){this.options.returnedObjectHandler||this.logger.warn("accessing an object - but returnObjects options is not enabled!");const Y=this.options.returnedObjectHandler?this.options.returnedObjectHandler(v,D,{...i,ns:c}):`key '${l} (${this.language})' returned an object instead of string.`;return s?(f.res=Y,f.usedParams=this.getUsedParamsDetails(i),f):Y}if(o){const Y=Array.isArray(D),L=Y?[]:{},te=Y?b:v;for(const ae in D)if(Object.prototype.hasOwnProperty.call(D,ae)){const J=`${te}${o}${ae}`;N&&!x?L[ae]=this.translate(J,{...i,defaultValue:xM(k)?k[ae]:void 0,joinArrays:!1,ns:c}):L[ae]=this.translate(J,{...i,joinArrays:!1,ns:c}),L[ae]===J&&(L[ae]=D[ae])}x=L}}else if(C&&$n(_)&&Array.isArray(x))x=x.join(_),x&&(x=this.extendTranslation(x,e,i,r));else{let Y=!1,L=!1;!this.isValidLookup(x)&&N&&(Y=!0,x=k),this.isValidLookup(x)||(L=!0,x=l);const ae=(i.missingKeyNoValueFallbackToKey||this.options.missingKeyNoValueFallbackToKey)&&L?void 0:x,J=N&&k!==x&&this.options.updateMissing;if(L||Y||J){if(this.logger.log(J?"updateKey":"missingKey",m,d,l,J?k:x),o){const W=this.resolve(l,{...i,keySeparator:!1});W&&W.res&&this.logger.warn("Seems the loaded translations were in flat JSON format instead of nested. Either set keySeparator: false on init or make sure your translations are published in nested format.")}let le=[];const se=this.languageUtils.getFallbackCodes(this.options.fallbackLng,i.lng||this.language);if(this.options.saveMissingTo==="fallback"&&se&&se[0])for(let W=0;W{const be=N&&fe!==x?fe:ae;this.options.missingKeyHandler?this.options.missingKeyHandler(W,d,ne,be,J,i):this.backendConnector?.saveMissing&&this.backendConnector.saveMissing(W,d,ne,be,J,i),this.emit("missingKey",W,d,ne,x)};this.options.saveMissing&&(this.options.saveMissingPlurals&&P?le.forEach(W=>{const ne=this.pluralResolver.getSuffixes(W,i);F&&i[`defaultValue${this.options.pluralSeparator}zero`]&&ne.indexOf(`${this.options.pluralSeparator}zero`)<0&&ne.push(`${this.options.pluralSeparator}zero`),ne.forEach(fe=>{oe([W],l+fe,i[`defaultValue${fe}`]||k)})}):oe(le,l,k))}x=this.extendTranslation(x,e,i,f,r),L&&x===l&&this.options.appendNamespaceToMissingKey&&(x=`${d}${u}${l}`),(L||Y)&&this.options.parseMissingKeyHandler&&(x=this.options.parseMissingKeyHandler(this.options.appendNamespaceToMissingKey?`${d}${u}${l}`:l,Y?x:void 0,i))}return s?(f.res=x,f.usedParams=this.getUsedParamsDetails(i),f):x}extendTranslation(e,n,r,i,s){if(this.i18nFormat?.parse)e=this.i18nFormat.parse(e,{...this.options.interpolation.defaultVariables,...r},r.lng||this.language||i.usedLng,i.usedNS,i.usedKey,{resolved:i});else if(!r.skipInterpolation){r.interpolation&&this.interpolator.init({...r,interpolation:{...this.options.interpolation,...r.interpolation}});const c=$n(e)&&(r?.interpolation?.skipOnVariables!==void 0?r.interpolation.skipOnVariables:this.options.interpolation.skipOnVariables);let d;if(c){const m=e.match(this.interpolator.nestingRegexp);d=m&&m.length}let u=r.replace&&!$n(r.replace)?r.replace:r;if(this.options.interpolation.defaultVariables&&(u={...this.options.interpolation.defaultVariables,...u}),e=this.interpolator.interpolate(e,u,r.lng||this.language||i.usedLng,r),c){const m=e.match(this.interpolator.nestingRegexp),p=m&&m.length;ds?.[0]===m[0]&&!r.context?(this.logger.warn(`It seems you are nesting recursively key: ${m[0]} in key: ${n[0]}`),null):this.translate(...m,n),r)),r.interpolation&&this.interpolator.reset()}const o=r.postProcess||this.options.postProcess,l=$n(o)?[o]:o;return e!=null&&l?.length&&r.applyPostProcessor!==!1&&(e=HY.handle(l,e,n,this.options&&this.options.postProcessPassResolved?{i18nResolved:{...i,usedParams:this.getUsedParamsDetails(r)},...r}:r,this)),e}resolve(e,n={}){let r,i,s,o,l;return $n(e)&&(e=[e]),e.forEach(c=>{if(this.isValidLookup(r))return;const d=this.extractFromKey(c,n),u=d.key;i=u;let m=d.namespaces;this.options.fallbackNS&&(m=m.concat(this.options.fallbackNS));const p=n.count!==void 0&&!$n(n.count),f=p&&!n.ordinal&&n.count===0,x=n.context!==void 0&&($n(n.context)||typeof n.context=="number")&&n.context!=="",v=n.lngs?n.lngs:this.languageUtils.toResolveHierarchy(n.lng||this.language,n.fallbackLng);m.forEach(b=>{this.isValidLookup(r)||(l=b,!q8[`${v[0]}-${b}`]&&this.utils?.hasLoadedNamespace&&!this.utils?.hasLoadedNamespace(l)&&(q8[`${v[0]}-${b}`]=!0,this.logger.warn(`key "${i}" for languages "${v.join(", ")}" won't get resolved as namespace "${l}" was not yet loaded`,"This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!")),v.forEach(g=>{if(this.isValidLookup(r))return;o=g;const _=[u];if(this.i18nFormat?.addLookupKeys)this.i18nFormat.addLookupKeys(_,u,g,b,n);else{let P;p&&(P=this.pluralResolver.getSuffix(g,n.count,n));const N=`${this.options.pluralSeparator}zero`,A=`${this.options.pluralSeparator}ordinal${this.options.pluralSeparator}`;if(p&&(n.ordinal&&P.indexOf(A)===0&&_.push(u+P.replace(A,this.options.pluralSeparator)),_.push(u+P),f&&_.push(u+N)),x){const T=`${u}${this.options.contextSeparator||"_"}${n.context}`;_.push(T),p&&(n.ordinal&&P.indexOf(A)===0&&_.push(T+P.replace(A,this.options.pluralSeparator)),_.push(T+P),f&&_.push(T+N))}}let C;for(;C=_.pop();)this.isValidLookup(r)||(s=C,r=this.getResource(g,b,C,n))}))})}),{res:r,usedKey:i,exactUsedKey:s,usedLng:o,usedNS:l}}isValidLookup(e){return e!==void 0&&!(!this.options.returnNull&&e===null)&&!(!this.options.returnEmptyString&&e==="")}getResource(e,n,r,i={}){return this.i18nFormat?.getResource?this.i18nFormat.getResource(e,n,r,i):this.resourceStore.getResource(e,n,r,i)}getUsedParamsDetails(e={}){const n=["defaultValue","ordinal","context","replace","lng","lngs","fallbackLng","ns","keySeparator","nsSeparator","returnObjects","returnDetails","joinArrays","postProcess","interpolation"],r=e.replace&&!$n(e.replace);let i=r?e.replace:e;if(r&&typeof e.count<"u"&&(i.count=e.count),this.options.interpolation.defaultVariables&&(i={...this.options.interpolation.defaultVariables,...i}),!r){i={...i};for(const s of n)delete i[s]}return i}static hasDefaultValue(e){const n="defaultValue";for(const r in e)if(Object.prototype.hasOwnProperty.call(e,r)&&n===r.substring(0,n.length)&&e[r]!==void 0)return!0;return!1}}class $8{constructor(e){this.options=e,this.supportedLngs=this.options.supportedLngs||!1,this.logger=Ed.create("languageUtils")}getScriptPartFromCode(e){if(e=Y0(e),!e||e.indexOf("-")<0)return null;const n=e.split("-");return n.length===2||(n.pop(),n[n.length-1].toLowerCase()==="x")?null:this.formatLanguageCode(n.join("-"))}getLanguagePartFromCode(e){if(e=Y0(e),!e||e.indexOf("-")<0)return e;const n=e.split("-");return this.formatLanguageCode(n[0])}formatLanguageCode(e){if($n(e)&&e.indexOf("-")>-1){let n;try{n=Intl.getCanonicalLocales(e)[0]}catch{}return n&&this.options.lowerCaseLng&&(n=n.toLowerCase()),n||(this.options.lowerCaseLng?e.toLowerCase():e)}return this.options.cleanCode||this.options.lowerCaseLng?e.toLowerCase():e}isSupportedCode(e){return(this.options.load==="languageOnly"||this.options.nonExplicitSupportedLngs)&&(e=this.getLanguagePartFromCode(e)),!this.supportedLngs||!this.supportedLngs.length||this.supportedLngs.indexOf(e)>-1}getBestMatchFromCodes(e){if(!e)return null;let n;return e.forEach(r=>{if(n)return;const i=this.formatLanguageCode(r);(!this.options.supportedLngs||this.isSupportedCode(i))&&(n=i)}),!n&&this.options.supportedLngs&&e.forEach(r=>{if(n)return;const i=this.getScriptPartFromCode(r);if(this.isSupportedCode(i))return n=i;const s=this.getLanguagePartFromCode(r);if(this.isSupportedCode(s))return n=s;n=this.options.supportedLngs.find(o=>{if(o===s)return o;if(!(o.indexOf("-")<0&&s.indexOf("-")<0)&&(o.indexOf("-")>0&&s.indexOf("-")<0&&o.substring(0,o.indexOf("-"))===s||o.indexOf(s)===0&&s.length>1))return o})}),n||(n=this.getFallbackCodes(this.options.fallbackLng)[0]),n}getFallbackCodes(e,n){if(!e)return[];if(typeof e=="function"&&(e=e(n)),$n(e)&&(e=[e]),Array.isArray(e))return e;if(!n)return e.default||[];let r=e[n];return r||(r=e[this.getScriptPartFromCode(n)]),r||(r=e[this.formatLanguageCode(n)]),r||(r=e[this.getLanguagePartFromCode(n)]),r||(r=e.default),r||[]}toResolveHierarchy(e,n){const r=this.getFallbackCodes((n===!1?[]:n)||this.options.fallbackLng||[],e),i=[],s=o=>{o&&(this.isSupportedCode(o)?i.push(o):this.logger.warn(`rejecting language code not found in supportedLngs: ${o}`))};return $n(e)&&(e.indexOf("-")>-1||e.indexOf("_")>-1)?(this.options.load!=="languageOnly"&&s(this.formatLanguageCode(e)),this.options.load!=="languageOnly"&&this.options.load!=="currentOnly"&&s(this.getScriptPartFromCode(e)),this.options.load!=="currentOnly"&&s(this.getLanguagePartFromCode(e))):$n(e)&&s(this.formatLanguageCode(e)),r.forEach(o=>{i.indexOf(o)<0&&s(this.formatLanguageCode(o))}),i}}const V8={zero:0,one:1,two:2,few:3,many:4,other:5},G8={select:t=>t===1?"one":"other",resolvedOptions:()=>({pluralCategories:["one","other"]})};class rue{constructor(e,n={}){this.languageUtils=e,this.options=n,this.logger=Ed.create("pluralResolver"),this.pluralRulesCache={}}addRule(e,n){this.rules[e]=n}clearCache(){this.pluralRulesCache={}}getRule(e,n={}){const r=Y0(e==="dev"?"en":e),i=n.ordinal?"ordinal":"cardinal",s=JSON.stringify({cleanedCode:r,type:i});if(s in this.pluralRulesCache)return this.pluralRulesCache[s];let o;try{o=new Intl.PluralRules(r,{type:i})}catch{if(!Intl)return this.logger.error("No Intl support, please use an Intl polyfill!"),G8;if(!e.match(/-|_/))return G8;const c=this.languageUtils.getLanguagePartFromCode(e);o=this.getRule(c,n)}return this.pluralRulesCache[s]=o,o}needsPlural(e,n={}){let r=this.getRule(e,n);return r||(r=this.getRule("dev",n)),r?.resolvedOptions().pluralCategories.length>1}getPluralFormsOfKey(e,n,r={}){return this.getSuffixes(e,r).map(i=>`${n}${i}`)}getSuffixes(e,n={}){let r=this.getRule(e,n);return r||(r=this.getRule("dev",n)),r?r.resolvedOptions().pluralCategories.sort((i,s)=>V8[i]-V8[s]).map(i=>`${this.options.prepend}${n.ordinal?`ordinal${this.options.prepend}`:""}${i}`):[]}getSuffix(e,n,r={}){const i=this.getRule(e,r);return i?`${this.options.prepend}${r.ordinal?`ordinal${this.options.prepend}`:""}${i.select(n)}`:(this.logger.warn(`no plural rule found for: ${e}`),this.getSuffix("dev",n,r))}}const W8=(t,e,n,r=".",i=!0)=>{let s=Kde(t,e,n);return!s&&i&&$n(n)&&(s=I3(t,n,r),s===void 0&&(s=I3(e,n,r))),s},yM=t=>t.replace(/\$/g,"$$$$");class aue{constructor(e={}){this.logger=Ed.create("interpolator"),this.options=e,this.format=e?.interpolation?.format||(n=>n),this.init(e)}init(e={}){e.interpolation||(e.interpolation={escapeValue:!0});const{escape:n,escapeValue:r,useRawValueToEscape:i,prefix:s,prefixEscaped:o,suffix:l,suffixEscaped:c,formatSeparator:d,unescapeSuffix:u,unescapePrefix:m,nestingPrefix:p,nestingPrefixEscaped:f,nestingSuffix:x,nestingSuffixEscaped:v,nestingOptionsSeparator:b,maxReplaces:g,alwaysFormat:_}=e.interpolation;this.escape=n!==void 0?n:Yde,this.escapeValue=r!==void 0?r:!0,this.useRawValueToEscape=i!==void 0?i:!1,this.prefix=s?vb(s):o||"{{",this.suffix=l?vb(l):c||"}}",this.formatSeparator=d||",",this.unescapePrefix=u?"":m||"-",this.unescapeSuffix=this.unescapePrefix?"":u||"",this.nestingPrefix=p?vb(p):f||vb("$t("),this.nestingSuffix=x?vb(x):v||vb(")"),this.nestingOptionsSeparator=b||",",this.maxReplaces=g||1e3,this.alwaysFormat=_!==void 0?_:!1,this.resetRegExp()}reset(){this.options&&this.init(this.options)}resetRegExp(){const e=(n,r)=>n?.source===r?(n.lastIndex=0,n):new RegExp(r,"g");this.regexp=e(this.regexp,`${this.prefix}(.+?)${this.suffix}`),this.regexpUnescape=e(this.regexpUnescape,`${this.prefix}${this.unescapePrefix}(.+?)${this.unescapeSuffix}${this.suffix}`),this.nestingRegexp=e(this.nestingRegexp,`${this.nestingPrefix}((?:[^()"']+|"[^"]*"|'[^']*'|\\((?:[^()]|"[^"]*"|'[^']*')*\\))*?)${this.nestingSuffix}`)}interpolate(e,n,r,i){let s,o,l;const c=this.options&&this.options.interpolation&&this.options.interpolation.defaultVariables||{},d=f=>{if(f.indexOf(this.formatSeparator)<0){const g=W8(n,c,f,this.options.keySeparator,this.options.ignoreJSONStructure);return this.alwaysFormat?this.format(g,void 0,r,{...i,...n,interpolationkey:f}):g}const x=f.split(this.formatSeparator),v=x.shift().trim(),b=x.join(this.formatSeparator).trim();return this.format(W8(n,c,v,this.options.keySeparator,this.options.ignoreJSONStructure),b,r,{...i,...n,interpolationkey:v})};this.resetRegExp();const u=i?.missingInterpolationHandler||this.options.missingInterpolationHandler,m=i?.interpolation?.skipOnVariables!==void 0?i.interpolation.skipOnVariables:this.options.interpolation.skipOnVariables;return[{regex:this.regexpUnescape,safeValue:f=>yM(f)},{regex:this.regexp,safeValue:f=>this.escapeValue?yM(this.escape(f)):yM(f)}].forEach(f=>{for(l=0;s=f.regex.exec(e);){const x=s[1].trim();if(o=d(x),o===void 0)if(typeof u=="function"){const b=u(e,s,i);o=$n(b)?b:""}else if(i&&Object.prototype.hasOwnProperty.call(i,x))o="";else if(m){o=s[0];continue}else this.logger.warn(`missed to pass in variable ${x} for interpolating ${e}`),o="";else!$n(o)&&!this.useRawValueToEscape&&(o=I8(o));const v=f.safeValue(o);if(e=e.replace(s[0],v),m?(f.regex.lastIndex+=o.length,f.regex.lastIndex-=s[0].length):f.regex.lastIndex=0,l++,l>=this.maxReplaces)break}}),e}nest(e,n,r={}){let i,s,o;const l=(c,d)=>{const u=this.nestingOptionsSeparator;if(c.indexOf(u)<0)return c;const m=c.split(new RegExp(`${u}[ ]*{`));let p=`{${m[1]}`;c=m[0],p=this.interpolate(p,o);const f=p.match(/'/g),x=p.match(/"/g);((f?.length??0)%2===0&&!x||x.length%2!==0)&&(p=p.replace(/'/g,'"'));try{o=JSON.parse(p),d&&(o={...d,...o})}catch(v){return this.logger.warn(`failed parsing options string in nesting for key ${c}`,v),`${c}${u}${p}`}return o.defaultValue&&o.defaultValue.indexOf(this.prefix)>-1&&delete o.defaultValue,c};for(;i=this.nestingRegexp.exec(e);){let c=[];o={...r},o=o.replace&&!$n(o.replace)?o.replace:o,o.applyPostProcessor=!1,delete o.defaultValue;const d=/{.*}/.test(i[1])?i[1].lastIndexOf("}")+1:i[1].indexOf(this.formatSeparator);if(d!==-1&&(c=i[1].slice(d).split(this.formatSeparator).map(u=>u.trim()).filter(Boolean),i[1]=i[1].slice(0,d)),s=n(l.call(this,i[1].trim(),o),o),s&&i[0]===e&&!$n(s))return s;$n(s)||(s=I8(s)),s||(this.logger.warn(`missed to resolve ${i[1]} for nesting ${e}`),s=""),c.length&&(s=c.reduce((u,m)=>this.format(u,m,r.lng,{...r,interpolationkey:i[1].trim()}),s.trim())),e=e.replace(i[0],s),this.regexp.lastIndex=0}return e}}const iue=t=>{let e=t.toLowerCase().trim();const n={};if(t.indexOf("(")>-1){const r=t.split("(");e=r[0].toLowerCase().trim();const i=r[1].substring(0,r[1].length-1);e==="currency"&&i.indexOf(":")<0?n.currency||(n.currency=i.trim()):e==="relativetime"&&i.indexOf(":")<0?n.range||(n.range=i.trim()):i.split(";").forEach(o=>{if(o){const[l,...c]=o.split(":"),d=c.join(":").trim().replace(/^'+|'+$/g,""),u=l.trim();n[u]||(n[u]=d),d==="false"&&(n[u]=!1),d==="true"&&(n[u]=!0),isNaN(d)||(n[u]=parseInt(d,10))}})}return{formatName:e,formatOptions:n}},K8=t=>{const e={};return(n,r,i)=>{let s=i;i&&i.interpolationkey&&i.formatParams&&i.formatParams[i.interpolationkey]&&i[i.interpolationkey]&&(s={...s,[i.interpolationkey]:void 0});const o=r+JSON.stringify(s);let l=e[o];return l||(l=t(Y0(r),i),e[o]=l),l(n)}},sue=t=>(e,n,r)=>t(Y0(n),r)(e);class oue{constructor(e={}){this.logger=Ed.create("formatter"),this.options=e,this.init(e)}init(e,n={interpolation:{}}){this.formatSeparator=n.interpolation.formatSeparator||",";const r=n.cacheInBuiltFormats?K8:sue;this.formats={number:r((i,s)=>{const o=new Intl.NumberFormat(i,{...s});return l=>o.format(l)}),currency:r((i,s)=>{const o=new Intl.NumberFormat(i,{...s,style:"currency"});return l=>o.format(l)}),datetime:r((i,s)=>{const o=new Intl.DateTimeFormat(i,{...s});return l=>o.format(l)}),relativetime:r((i,s)=>{const o=new Intl.RelativeTimeFormat(i,{...s});return l=>o.format(l,s.range||"day")}),list:r((i,s)=>{const o=new Intl.ListFormat(i,{...s});return l=>o.format(l)})}}add(e,n){this.formats[e.toLowerCase().trim()]=n}addCached(e,n){this.formats[e.toLowerCase().trim()]=K8(n)}format(e,n,r,i={}){const s=n.split(this.formatSeparator);if(s.length>1&&s[0].indexOf("(")>1&&s[0].indexOf(")")<0&&s.find(l=>l.indexOf(")")>-1)){const l=s.findIndex(c=>c.indexOf(")")>-1);s[0]=[s[0],...s.splice(1,l)].join(this.formatSeparator)}return s.reduce((l,c)=>{const{formatName:d,formatOptions:u}=iue(c);if(this.formats[d]){let m=l;try{const p=i?.formatParams?.[i.interpolationkey]||{},f=p.locale||p.lng||i.locale||i.lng||r;m=this.formats[d](l,f,{...u,...i,...p})}catch(p){this.logger.warn(p)}return m}else this.logger.warn(`there was no format function for ${d}`);return l},e)}}const lue=(t,e)=>{t.pending[e]!==void 0&&(delete t.pending[e],t.pendingCount--)};class cue extends LP{constructor(e,n,r,i={}){super(),this.backend=e,this.store=n,this.services=r,this.languageUtils=r.languageUtils,this.options=i,this.logger=Ed.create("backendConnector"),this.waitingReads=[],this.maxParallelReads=i.maxParallelReads||10,this.readingCalls=0,this.maxRetries=i.maxRetries>=0?i.maxRetries:5,this.retryTimeout=i.retryTimeout>=1?i.retryTimeout:350,this.state={},this.queue=[],this.backend?.init?.(r,i.backend,i)}queueLoad(e,n,r,i){const s={},o={},l={},c={};return e.forEach(d=>{let u=!0;n.forEach(m=>{const p=`${d}|${m}`;!r.reload&&this.store.hasResourceBundle(d,m)?this.state[p]=2:this.state[p]<0||(this.state[p]===1?o[p]===void 0&&(o[p]=!0):(this.state[p]=1,u=!1,o[p]===void 0&&(o[p]=!0),s[p]===void 0&&(s[p]=!0),c[m]===void 0&&(c[m]=!0)))}),u||(l[d]=!0)}),(Object.keys(s).length||Object.keys(o).length)&&this.queue.push({pending:o,pendingCount:Object.keys(o).length,loaded:{},errors:[],callback:i}),{toLoad:Object.keys(s),pending:Object.keys(o),toLoadLanguages:Object.keys(l),toLoadNamespaces:Object.keys(c)}}loaded(e,n,r){const i=e.split("|"),s=i[0],o=i[1];n&&this.emit("failedLoading",s,o,n),!n&&r&&this.store.addResourceBundle(s,o,r,void 0,void 0,{skipCopy:!0}),this.state[e]=n?-1:2,n&&r&&(this.state[e]=0);const l={};this.queue.forEach(c=>{Wde(c.loaded,[s],o),lue(c,e),n&&c.errors.push(n),c.pendingCount===0&&!c.done&&(Object.keys(c.loaded).forEach(d=>{l[d]||(l[d]={});const u=c.loaded[d];u.length&&u.forEach(m=>{l[d][m]===void 0&&(l[d][m]=!0)})}),c.done=!0,c.errors.length?c.callback(c.errors):c.callback())}),this.emit("loaded",l),this.queue=this.queue.filter(c=>!c.done)}read(e,n,r,i=0,s=this.retryTimeout,o){if(!e.length)return o(null,{});if(this.readingCalls>=this.maxParallelReads){this.waitingReads.push({lng:e,ns:n,fcName:r,tried:i,wait:s,callback:o});return}this.readingCalls++;const l=(d,u)=>{if(this.readingCalls--,this.waitingReads.length>0){const m=this.waitingReads.shift();this.read(m.lng,m.ns,m.fcName,m.tried,m.wait,m.callback)}if(d&&u&&i{this.read.call(this,e,n,r,i+1,s*2,o)},s);return}o(d,u)},c=this.backend[r].bind(this.backend);if(c.length===2){try{const d=c(e,n);d&&typeof d.then=="function"?d.then(u=>l(null,u)).catch(l):l(null,d)}catch(d){l(d)}return}return c(e,n,l)}prepareLoading(e,n,r={},i){if(!this.backend)return this.logger.warn("No backend was added via i18next.use. Will not load resources."),i&&i();$n(e)&&(e=this.languageUtils.toResolveHierarchy(e)),$n(n)&&(n=[n]);const s=this.queueLoad(e,n,r,i);if(!s.toLoad.length)return s.pending.length||i(),null;s.toLoad.forEach(o=>{this.loadOne(o)})}load(e,n,r){this.prepareLoading(e,n,{},r)}reload(e,n,r){this.prepareLoading(e,n,{reload:!0},r)}loadOne(e,n=""){const r=e.split("|"),i=r[0],s=r[1];this.read(i,s,"read",void 0,void 0,(o,l)=>{o&&this.logger.warn(`${n}loading namespace ${s} for language ${i} failed`,o),!o&&l&&this.logger.log(`${n}loaded namespace ${s} for language ${i}`,l),this.loaded(e,o,l)})}saveMissing(e,n,r,i,s,o={},l=()=>{}){if(this.services?.utils?.hasLoadedNamespace&&!this.services?.utils?.hasLoadedNamespace(n)){this.logger.warn(`did not save key "${r}" as the namespace "${n}" was not yet loaded`,"This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!");return}if(!(r==null||r==="")){if(this.backend?.create){const c={...o,isUpdate:s},d=this.backend.create.bind(this.backend);if(d.length<6)try{let u;d.length===5?u=d(e,n,r,i,c):u=d(e,n,r,i),u&&typeof u.then=="function"?u.then(m=>l(null,m)).catch(l):l(null,u)}catch(u){l(u)}else d(e,n,r,i,l,c)}!e||!e[0]||this.store.addResource(e[0],n,r,i)}}}const X8=()=>({debug:!1,initAsync:!0,ns:["translation"],defaultNS:["translation"],fallbackLng:["dev"],fallbackNS:!1,supportedLngs:!1,nonExplicitSupportedLngs:!1,load:"all",preload:!1,simplifyPluralSuffix:!0,keySeparator:".",nsSeparator:":",pluralSeparator:"_",contextSeparator:"_",partialBundledLanguages:!1,saveMissing:!1,updateMissing:!1,saveMissingTo:"fallback",saveMissingPlurals:!0,missingKeyHandler:!1,missingInterpolationHandler:!1,postProcess:!1,postProcessPassResolved:!1,returnNull:!1,returnEmptyString:!0,returnObjects:!1,joinArrays:!1,returnedObjectHandler:!1,parseMissingKeyHandler:!1,appendNamespaceToMissingKey:!1,appendNamespaceToCIMode:!1,overloadTranslationOptionHandler:t=>{let e={};if(typeof t[1]=="object"&&(e=t[1]),$n(t[1])&&(e.defaultValue=t[1]),$n(t[2])&&(e.tDescription=t[2]),typeof t[2]=="object"||typeof t[3]=="object"){const n=t[3]||t[2];Object.keys(n).forEach(r=>{e[r]=n[r]})}return e},interpolation:{escapeValue:!0,format:t=>t,prefix:"{{",suffix:"}}",formatSeparator:",",unescapePrefix:"-",nestingPrefix:"$t(",nestingSuffix:")",nestingOptionsSeparator:",",maxReplaces:1e3,skipOnVariables:!0},cacheInBuiltFormats:!0}),Y8=t=>($n(t.ns)&&(t.ns=[t.ns]),$n(t.fallbackLng)&&(t.fallbackLng=[t.fallbackLng]),$n(t.fallbackNS)&&(t.fallbackNS=[t.fallbackNS]),t.supportedLngs?.indexOf?.("cimode")<0&&(t.supportedLngs=t.supportedLngs.concat(["cimode"])),typeof t.initImmediate=="boolean"&&(t.initAsync=t.initImmediate),t),V_=()=>{},due=t=>{Object.getOwnPropertyNames(Object.getPrototypeOf(t)).forEach(n=>{typeof t[n]=="function"&&(t[n]=t[n].bind(t))})};class k0 extends LP{constructor(e={},n){if(super(),this.options=Y8(e),this.services={},this.logger=Ed,this.modules={external:[]},due(this),n&&!this.isInitialized&&!e.isClone){if(!this.options.initAsync)return this.init(e,n),this;setTimeout(()=>{this.init(e,n)},0)}}init(e={},n){this.isInitializing=!0,typeof e=="function"&&(n=e,e={}),e.defaultNS==null&&e.ns&&($n(e.ns)?e.defaultNS=e.ns:e.ns.indexOf("translation")<0&&(e.defaultNS=e.ns[0]));const r=X8();this.options={...r,...this.options,...Y8(e)},this.options.interpolation={...r.interpolation,...this.options.interpolation},e.keySeparator!==void 0&&(this.options.userDefinedKeySeparator=e.keySeparator),e.nsSeparator!==void 0&&(this.options.userDefinedNsSeparator=e.nsSeparator);const i=d=>d?typeof d=="function"?new d:d:null;if(!this.options.isClone){this.modules.logger?Ed.init(i(this.modules.logger),this.options):Ed.init(null,this.options);let d;this.modules.formatter?d=this.modules.formatter:d=oue;const u=new $8(this.options);this.store=new H8(this.options.resources,this.options);const m=this.services;m.logger=Ed,m.resourceStore=this.store,m.languageUtils=u,m.pluralResolver=new rue(u,{prepend:this.options.pluralSeparator,simplifyPluralSuffix:this.options.simplifyPluralSuffix}),this.options.interpolation.format&&this.options.interpolation.format!==r.interpolation.format&&this.logger.deprecate("init: you are still using the legacy format function, please use the new approach: https://www.i18next.com/translation-function/formatting"),d&&(!this.options.interpolation.format||this.options.interpolation.format===r.interpolation.format)&&(m.formatter=i(d),m.formatter.init&&m.formatter.init(m,this.options),this.options.interpolation.format=m.formatter.format.bind(m.formatter)),m.interpolator=new aue(this.options),m.utils={hasLoadedNamespace:this.hasLoadedNamespace.bind(this)},m.backendConnector=new cue(i(this.modules.backend),m.resourceStore,m,this.options),m.backendConnector.on("*",(f,...x)=>{this.emit(f,...x)}),this.modules.languageDetector&&(m.languageDetector=i(this.modules.languageDetector),m.languageDetector.init&&m.languageDetector.init(m,this.options.detection,this.options)),this.modules.i18nFormat&&(m.i18nFormat=i(this.modules.i18nFormat),m.i18nFormat.init&&m.i18nFormat.init(this)),this.translator=new mN(this.services,this.options),this.translator.on("*",(f,...x)=>{this.emit(f,...x)}),this.modules.external.forEach(f=>{f.init&&f.init(this)})}if(this.format=this.options.interpolation.format,n||(n=V_),this.options.fallbackLng&&!this.services.languageDetector&&!this.options.lng){const d=this.services.languageUtils.getFallbackCodes(this.options.fallbackLng);d.length>0&&d[0]!=="dev"&&(this.options.lng=d[0])}!this.services.languageDetector&&!this.options.lng&&this.logger.warn("init: no languageDetector is used and no lng is defined"),["getResource","hasResourceBundle","getResourceBundle","getDataByLanguage"].forEach(d=>{this[d]=(...u)=>this.store[d](...u)}),["addResource","addResources","addResourceBundle","removeResourceBundle"].forEach(d=>{this[d]=(...u)=>(this.store[d](...u),this)});const l=Cv(),c=()=>{const d=(u,m)=>{this.isInitializing=!1,this.isInitialized&&!this.initializedStoreOnce&&this.logger.warn("init: i18next is already initialized. You should call init just once!"),this.isInitialized=!0,this.options.isClone||this.logger.log("initialized",this.options),this.emit("initialized",this.options),l.resolve(m),n(u,m)};if(this.languages&&!this.isInitialized)return d(null,this.t.bind(this));this.changeLanguage(this.options.lng,d)};return this.options.resources||!this.options.initAsync?c():setTimeout(c,0),l}loadResources(e,n=V_){let r=n;const i=$n(e)?e:this.language;if(typeof e=="function"&&(r=e),!this.options.resources||this.options.partialBundledLanguages){if(i?.toLowerCase()==="cimode"&&(!this.options.preload||this.options.preload.length===0))return r();const s=[],o=l=>{if(!l||l==="cimode")return;this.services.languageUtils.toResolveHierarchy(l).forEach(d=>{d!=="cimode"&&s.indexOf(d)<0&&s.push(d)})};i?o(i):this.services.languageUtils.getFallbackCodes(this.options.fallbackLng).forEach(c=>o(c)),this.options.preload?.forEach?.(l=>o(l)),this.services.backendConnector.load(s,this.options.ns,l=>{!l&&!this.resolvedLanguage&&this.language&&this.setResolvedLanguage(this.language),r(l)})}else r(null)}reloadResources(e,n,r){const i=Cv();return typeof e=="function"&&(r=e,e=void 0),typeof n=="function"&&(r=n,n=void 0),e||(e=this.languages),n||(n=this.options.ns),r||(r=V_),this.services.backendConnector.reload(e,n,s=>{i.resolve(),r(s)}),i}use(e){if(!e)throw new Error("You are passing an undefined module! Please check the object you are passing to i18next.use()");if(!e.type)throw new Error("You are passing a wrong module! Please check the object you are passing to i18next.use()");return e.type==="backend"&&(this.modules.backend=e),(e.type==="logger"||e.log&&e.warn&&e.error)&&(this.modules.logger=e),e.type==="languageDetector"&&(this.modules.languageDetector=e),e.type==="i18nFormat"&&(this.modules.i18nFormat=e),e.type==="postProcessor"&&HY.addPostProcessor(e),e.type==="formatter"&&(this.modules.formatter=e),e.type==="3rdParty"&&this.modules.external.push(e),this}setResolvedLanguage(e){if(!(!e||!this.languages)&&!(["cimode","dev"].indexOf(e)>-1)){for(let n=0;n-1)&&this.store.hasLanguageSomeTranslations(r)){this.resolvedLanguage=r;break}}!this.resolvedLanguage&&this.languages.indexOf(e)<0&&this.store.hasLanguageSomeTranslations(e)&&(this.resolvedLanguage=e,this.languages.unshift(e))}}changeLanguage(e,n){this.isLanguageChangingTo=e;const r=Cv();this.emit("languageChanging",e);const i=l=>{this.language=l,this.languages=this.services.languageUtils.toResolveHierarchy(l),this.resolvedLanguage=void 0,this.setResolvedLanguage(l)},s=(l,c)=>{c?this.isLanguageChangingTo===e&&(i(c),this.translator.changeLanguage(c),this.isLanguageChangingTo=void 0,this.emit("languageChanged",c),this.logger.log("languageChanged",c)):this.isLanguageChangingTo=void 0,r.resolve((...d)=>this.t(...d)),n&&n(l,(...d)=>this.t(...d))},o=l=>{!e&&!l&&this.services.languageDetector&&(l=[]);const c=$n(l)?l:l&&l[0],d=this.store.hasLanguageSomeTranslations(c)?c:this.services.languageUtils.getBestMatchFromCodes($n(l)?[l]:l);d&&(this.language||i(d),this.translator.language||this.translator.changeLanguage(d),this.services.languageDetector?.cacheUserLanguage?.(d)),this.loadResources(d,u=>{s(u,d)})};return!e&&this.services.languageDetector&&!this.services.languageDetector.async?o(this.services.languageDetector.detect()):!e&&this.services.languageDetector&&this.services.languageDetector.async?this.services.languageDetector.detect.length===0?this.services.languageDetector.detect().then(o):this.services.languageDetector.detect(o):o(e),r}getFixedT(e,n,r){const i=(s,o,...l)=>{let c;typeof o!="object"?c=this.options.overloadTranslationOptionHandler([s,o].concat(l)):c={...o},c.lng=c.lng||i.lng,c.lngs=c.lngs||i.lngs,c.ns=c.ns||i.ns,c.keyPrefix!==""&&(c.keyPrefix=c.keyPrefix||r||i.keyPrefix);const d=this.options.keySeparator||".";let u;return c.keyPrefix&&Array.isArray(s)?u=s.map(m=>(typeof m=="function"&&(m=z3(m,{...this.options,...o})),`${c.keyPrefix}${d}${m}`)):(typeof s=="function"&&(s=z3(s,{...this.options,...o})),u=c.keyPrefix?`${c.keyPrefix}${d}${s}`:s),this.t(u,c)};return $n(e)?i.lng=e:i.lngs=e,i.ns=n,i.keyPrefix=r,i}t(...e){return this.translator?.translate(...e)}exists(...e){return this.translator?.exists(...e)}setDefaultNamespace(e){this.options.defaultNS=e}hasLoadedNamespace(e,n={}){if(!this.isInitialized)return this.logger.warn("hasLoadedNamespace: i18next was not initialized",this.languages),!1;if(!this.languages||!this.languages.length)return this.logger.warn("hasLoadedNamespace: i18n.languages were undefined or empty",this.languages),!1;const r=n.lng||this.resolvedLanguage||this.languages[0],i=this.options?this.options.fallbackLng:!1,s=this.languages[this.languages.length-1];if(r.toLowerCase()==="cimode")return!0;const o=(l,c)=>{const d=this.services.backendConnector.state[`${l}|${c}`];return d===-1||d===0||d===2};if(n.precheck){const l=n.precheck(this,o);if(l!==void 0)return l}return!!(this.hasResourceBundle(r,e)||!this.services.backendConnector.backend||this.options.resources&&!this.options.partialBundledLanguages||o(r,e)&&(!i||o(s,e)))}loadNamespaces(e,n){const r=Cv();return this.options.ns?($n(e)&&(e=[e]),e.forEach(i=>{this.options.ns.indexOf(i)<0&&this.options.ns.push(i)}),this.loadResources(i=>{r.resolve(),n&&n(i)}),r):(n&&n(),Promise.resolve())}loadLanguages(e,n){const r=Cv();$n(e)&&(e=[e]);const i=this.options.preload||[],s=e.filter(o=>i.indexOf(o)<0&&this.services.languageUtils.isSupportedCode(o));return s.length?(this.options.preload=i.concat(s),this.loadResources(o=>{r.resolve(),n&&n(o)}),r):(n&&n(),Promise.resolve())}dir(e){if(e||(e=this.resolvedLanguage||(this.languages?.length>0?this.languages[0]:this.language)),!e)return"rtl";try{const i=new Intl.Locale(e);if(i&&i.getTextInfo){const s=i.getTextInfo();if(s&&s.direction)return s.direction}}catch{}const n=["ar","shu","sqr","ssh","xaa","yhd","yud","aao","abh","abv","acm","acq","acw","acx","acy","adf","ads","aeb","aec","afb","ajp","apc","apd","arb","arq","ars","ary","arz","auz","avl","ayh","ayl","ayn","ayp","bbz","pga","he","iw","ps","pbt","pbu","pst","prp","prd","ug","ur","ydd","yds","yih","ji","yi","hbo","men","xmn","fa","jpr","peo","pes","prs","dv","sam","ckb"],r=this.services?.languageUtils||new $8(X8());return e.toLowerCase().indexOf("-latn")>1?"ltr":n.indexOf(r.getLanguagePartFromCode(e))>-1||e.toLowerCase().indexOf("-arab")>1?"rtl":"ltr"}static createInstance(e={},n){const r=new k0(e,n);return r.createInstance=k0.createInstance,r}cloneInstance(e={},n=V_){const r=e.forkResourceStore;r&&delete e.forkResourceStore;const i={...this.options,...e,isClone:!0},s=new k0(i);if((e.debug!==void 0||e.prefix!==void 0)&&(s.logger=s.logger.clone(e)),["store","services","language"].forEach(l=>{s[l]=this[l]}),s.services={...this.services},s.services.utils={hasLoadedNamespace:s.hasLoadedNamespace.bind(s)},r){const l=Object.keys(this.store.data).reduce((c,d)=>(c[d]={...this.store.data[d]},c[d]=Object.keys(c[d]).reduce((u,m)=>(u[m]={...c[d][m]},u),c[d]),c),{});s.store=new H8(l,i),s.services.resourceStore=s.store}return s.translator=new mN(s.services,i),s.translator.on("*",(l,...c)=>{s.emit(l,...c)}),s.init(i,n),s.translator.options=i,s.translator.backendConnector.services.utils={hasLoadedNamespace:s.hasLoadedNamespace.bind(s)},s}toJSON(){return{options:this.options,store:this.store,language:this.language,languages:this.languages,resolvedLanguage:this.resolvedLanguage}}}const xo=k0.createInstance();xo.createInstance;xo.dir;xo.init;xo.loadResources;xo.reloadResources;xo.use;xo.changeLanguage;xo.getFixedT;xo.t;xo.exists;xo.setDefaultNamespace;xo.hasLoadedNamespace;xo.loadNamespaces;xo.loadLanguages;const uue=(t,e,n,r)=>{const i=[n,{code:e,...r||{}}];if(t?.services?.logger?.forward)return t.services.logger.forward(i,"warn","react-i18next::",!0);ng(i[0])&&(i[0]=`react-i18next:: ${i[0]}`),t?.services?.logger?.warn?t.services.logger.warn(...i):console?.warn&&console.warn(...i)},Q8={},$Y=(t,e,n,r)=>{ng(n)&&Q8[n]||(ng(n)&&(Q8[n]=new Date),uue(t,e,n,r))},VY=(t,e)=>()=>{if(t.isInitialized)e();else{const n=()=>{setTimeout(()=>{t.off("initialized",n)},0),e()};t.on("initialized",n)}},U3=(t,e,n)=>{t.loadNamespaces(e,VY(t,n))},Z8=(t,e,n,r)=>{if(ng(n)&&(n=[n]),t.options.preload&&t.options.preload.indexOf(e)>-1)return U3(t,n,r);n.forEach(i=>{t.options.ns.indexOf(i)<0&&t.options.ns.push(i)}),t.loadLanguages(e,VY(t,r))},mue=(t,e,n={})=>!e.languages||!e.languages.length?($Y(e,"NO_LANGUAGES","i18n.languages were undefined or empty",{languages:e.languages}),!0):e.hasLoadedNamespace(t,{lng:n.lng,precheck:(r,i)=>{if(n.bindI18n&&n.bindI18n.indexOf("languageChanging")>-1&&r.services.backendConnector.backend&&r.isLanguageChangingTo&&!i(r.isLanguageChangingTo,t))return!1}}),ng=t=>typeof t=="string",hue=t=>typeof t=="object"&&t!==null,pue=/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g,fue={"&":"&","&":"&","<":"<","<":"<",">":">",">":">","'":"'","'":"'",""":'"',""":'"'," ":" "," ":" ","©":"©","©":"©","®":"®","®":"®","…":"…","…":"…","/":"/","/":"/"},gue=t=>fue[t],bue=t=>t.replace(pue,gue);let B3={bindI18n:"languageChanged",bindI18nStore:"",transEmptyNodeValue:"",transSupportBasicHtmlNodes:!0,transWrapTextNodes:"",transKeepBasicHtmlNodesFor:["br","strong","i","p"],useSuspense:!0,unescape:bue,transDefaultProps:void 0};const xue=(t={})=>{B3={...B3,...t}},yue=()=>B3;let GY;const vue=t=>{GY=t},wue=()=>GY,Sue={type:"3rdParty",init(t){xue(t.options.react),vue(t)}},_ue=w.createContext();class kue{constructor(){this.usedNamespaces={}}addUsedNamespaces(e){e.forEach(n=>{this.usedNamespaces[n]||(this.usedNamespaces[n]=!0)})}getUsedNamespaces(){return Object.keys(this.usedNamespaces)}}var vM={exports:{}},wM={};var J8;function Nue(){if(J8)return wM;J8=1;var t=jg();function e(m,p){return m===p&&(m!==0||1/m===1/p)||m!==m&&p!==p}var n=typeof Object.is=="function"?Object.is:e,r=t.useState,i=t.useEffect,s=t.useLayoutEffect,o=t.useDebugValue;function l(m,p){var f=p(),x=r({inst:{value:f,getSnapshot:p}}),v=x[0].inst,b=x[1];return s(function(){v.value=f,v.getSnapshot=p,c(v)&&b({inst:v})},[m,f,p]),i(function(){return c(v)&&b({inst:v}),m(function(){c(v)&&b({inst:v})})},[m]),o(f),f}function c(m){var p=m.getSnapshot;m=m.value;try{var f=p();return!n(m,f)}catch{return!0}}function d(m,p){return p()}var u=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?d:l;return wM.useSyncExternalStore=t.useSyncExternalStore!==void 0?t.useSyncExternalStore:u,wM}var eH;function WY(){return eH||(eH=1,vM.exports=Nue()),vM.exports}var cO=WY();const Cue=(t,e)=>ng(e)?e:hue(e)&&ng(e.defaultValue)?e.defaultValue:Array.isArray(t)?t[t.length-1]:t,Pue={t:Cue,ready:!1},Tue=()=>()=>{},Dt=(t,e={})=>{const{i18n:n}=e,{i18n:r,defaultNS:i}=w.useContext(_ue)||{},s=n||r||wue();s&&!s.reportNamespaces&&(s.reportNamespaces=new kue),s||$Y(s,"NO_I18NEXT_INSTANCE","useTranslation: You will need to pass in an i18next instance by using initReactI18next");const o=w.useMemo(()=>({...yue(),...s?.options?.react,...e}),[s,e]),{useSuspense:l,keyPrefix:c}=o,d=i||s?.options?.defaultNS,u=ng(d)?[d]:d||["translation"],m=w.useMemo(()=>u,u);s?.reportNamespaces?.addUsedNamespaces?.(m);const p=w.useRef(0),f=w.useCallback(k=>{if(!s)return Tue;const{bindI18n:D,bindI18nStore:H}=o,z=()=>{p.current+=1,k()};return D&&s.on(D,z),H&&s.store.on(H,z),()=>{D&&D.split(" ").forEach(Y=>s.off(Y,z)),H&&H.split(" ").forEach(Y=>s.store.off(Y,z))}},[s,o]),x=w.useRef(),v=w.useCallback(()=>{if(!s)return Pue;const k=!!(s.isInitialized||s.initializedStoreOnce)&&m.every(te=>mue(te,s,o)),D=e.lng||s.language,H=p.current,z=x.current;if(z&&z.ready===k&&z.lng===D&&z.keyPrefix===c&&z.revision===H)return z;const L={t:s.getFixedT(D,o.nsMode==="fallback"?m:m[0],c),ready:k,lng:D,keyPrefix:c,revision:H};return x.current=L,L},[s,m,c,o,e.lng]),[b,g]=w.useState(0),{t:_,ready:C}=cO.useSyncExternalStore(f,v,v);w.useEffect(()=>{if(s&&!C&&!l){const k=()=>g(D=>D+1);e.lng?Z8(s,e.lng,m,k):U3(s,m,k)}},[s,e.lng,m,C,l,b]);const P=s||{},N=w.useRef(null),A=w.useRef(),T=k=>{const D=Object.getOwnPropertyDescriptors(k);D.__original&&delete D.__original;const H=Object.create(Object.getPrototypeOf(k),D);if(!Object.prototype.hasOwnProperty.call(H,"__original"))try{Object.defineProperty(H,"__original",{value:k,writable:!1,enumerable:!1,configurable:!1})}catch{}return H},F=w.useMemo(()=>{const k=P,D=k?.language;let H=k;k&&(N.current&&N.current.__original===k?A.current!==D?(H=T(k),N.current=H,A.current=D):H=N.current:(H=T(k),N.current=H,A.current=D));const z=[_,H,C];return z.t=_,z.i18n=H,z.ready=C,z},[_,P,C,P.resolvedLanguage,P.language,P.languages]);if(s&&l&&!C)throw new Promise(k=>{const D=()=>k();e.lng?Z8(s,e.lng,m,D):U3(s,m,D)});return F},{slice:Aue,forEach:jue}=[];function Mue(t){return jue.call(Aue.call(arguments,1),e=>{if(e)for(const n in e)t[n]===void 0&&(t[n]=e[n])}),t}function Eue(t){return typeof t!="string"?!1:[/<\s*script.*?>/i,/<\s*\/\s*script\s*>/i,/<\s*img.*?on\w+\s*=/i,/<\s*\w+\s*on\w+\s*=.*?>/i,/javascript\s*:/i,/vbscript\s*:/i,/expression\s*\(/i,/eval\s*\(/i,/alert\s*\(/i,/document\.cookie/i,/document\.write\s*\(/i,/window\.location/i,/innerHTML/i].some(n=>n.test(t))}const tH=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/,Due=function(t,e){const r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{path:"/"},i=encodeURIComponent(e);let s=`${t}=${i}`;if(r.maxAge>0){const o=r.maxAge-0;if(Number.isNaN(o))throw new Error("maxAge should be a Number");s+=`; Max-Age=${Math.floor(o)}`}if(r.domain){if(!tH.test(r.domain))throw new TypeError("option domain is invalid");s+=`; Domain=${r.domain}`}if(r.path){if(!tH.test(r.path))throw new TypeError("option path is invalid");s+=`; Path=${r.path}`}if(r.expires){if(typeof r.expires.toUTCString!="function")throw new TypeError("option expires is invalid");s+=`; Expires=${r.expires.toUTCString()}`}if(r.httpOnly&&(s+="; HttpOnly"),r.secure&&(s+="; Secure"),r.sameSite)switch(typeof r.sameSite=="string"?r.sameSite.toLowerCase():r.sameSite){case!0:s+="; SameSite=Strict";break;case"lax":s+="; SameSite=Lax";break;case"strict":s+="; SameSite=Strict";break;case"none":s+="; SameSite=None";break;default:throw new TypeError("option sameSite is invalid")}return r.partitioned&&(s+="; Partitioned"),s},nH={create(t,e,n,r){let i=arguments.length>4&&arguments[4]!==void 0?arguments[4]:{path:"/",sameSite:"strict"};n&&(i.expires=new Date,i.expires.setTime(i.expires.getTime()+n*60*1e3)),r&&(i.domain=r),document.cookie=Due(t,e,i)},read(t){const e=`${t}=`,n=document.cookie.split(";");for(let r=0;r-1&&(r=window.location.hash.substring(window.location.hash.indexOf("?")));const s=r.substring(1).split("&");for(let o=0;o0&&s[o].substring(0,l)===e&&(n=s[o].substring(l+1))}}return n}},Lue={name:"hash",lookup(t){let{lookupHash:e,lookupFromHashIndex:n}=t,r;if(typeof window<"u"){const{hash:i}=window.location;if(i&&i.length>2){const s=i.substring(1);if(e){const o=s.split("&");for(let l=0;l0&&o[l].substring(0,c)===e&&(r=o[l].substring(c+1))}}if(r)return r;if(!r&&n>-1){const o=i.match(/\/([a-zA-Z-]*)/g);return Array.isArray(o)?o[typeof n=="number"?n:0]?.replace("/",""):void 0}}}return r}};let wb=null;const rH=()=>{if(wb!==null)return wb;try{if(wb=typeof window<"u"&&window.localStorage!==null,!wb)return!1;const t="i18next.translate.boo";window.localStorage.setItem(t,"foo"),window.localStorage.removeItem(t)}catch{wb=!1}return wb};var Oue={name:"localStorage",lookup(t){let{lookupLocalStorage:e}=t;if(e&&rH())return window.localStorage.getItem(e)||void 0},cacheUserLanguage(t,e){let{lookupLocalStorage:n}=e;n&&rH()&&window.localStorage.setItem(n,t)}};let Sb=null;const aH=()=>{if(Sb!==null)return Sb;try{if(Sb=typeof window<"u"&&window.sessionStorage!==null,!Sb)return!1;const t="i18next.translate.boo";window.sessionStorage.setItem(t,"foo"),window.sessionStorage.removeItem(t)}catch{Sb=!1}return Sb};var Iue={name:"sessionStorage",lookup(t){let{lookupSessionStorage:e}=t;if(e&&aH())return window.sessionStorage.getItem(e)||void 0},cacheUserLanguage(t,e){let{lookupSessionStorage:n}=e;n&&aH()&&window.sessionStorage.setItem(n,t)}},zue={name:"navigator",lookup(t){const e=[];if(typeof navigator<"u"){const{languages:n,userLanguage:r,language:i}=navigator;if(n)for(let s=0;s0?e:void 0}},Uue={name:"htmlTag",lookup(t){let{htmlTag:e}=t,n;const r=e||(typeof document<"u"?document.documentElement:null);return r&&typeof r.getAttribute=="function"&&(n=r.getAttribute("lang")),n}},Bue={name:"path",lookup(t){let{lookupFromPathIndex:e}=t;if(typeof window>"u")return;const n=window.location.pathname.match(/\/([a-zA-Z-]*)/g);return Array.isArray(n)?n[typeof e=="number"?e:0]?.replace("/",""):void 0}},Hue={name:"subdomain",lookup(t){let{lookupFromSubdomainIndex:e}=t;const n=typeof e=="number"?e+1:1,r=typeof window<"u"&&window.location?.hostname?.match(/^(\w{2,5})\.(([a-z0-9-]{1,63}\.[a-z]{2,6})|localhost)/i);if(r)return r[n]}};let KY=!1;try{document.cookie,KY=!0}catch{}const XY=["querystring","cookie","localStorage","sessionStorage","navigator","htmlTag"];KY||XY.splice(1,1);const que=()=>({order:XY,lookupQuerystring:"lng",lookupCookie:"i18next",lookupLocalStorage:"i18nextLng",lookupSessionStorage:"i18nextLng",caches:["localStorage"],excludeCacheFor:["cimode"],convertDetectedLanguage:t=>t});class YY{constructor(e){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};this.type="languageDetector",this.detectors={},this.init(e,n)}init(){let e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{languageUtils:{}},n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};this.services=e,this.options=Mue(n,this.options||{},que()),typeof this.options.convertDetectedLanguage=="string"&&this.options.convertDetectedLanguage.indexOf("15897")>-1&&(this.options.convertDetectedLanguage=i=>i.replace("-","_")),this.options.lookupFromUrlIndex&&(this.options.lookupFromPathIndex=this.options.lookupFromUrlIndex),this.i18nOptions=r,this.addDetector(Fue),this.addDetector(Rue),this.addDetector(Oue),this.addDetector(Iue),this.addDetector(zue),this.addDetector(Uue),this.addDetector(Bue),this.addDetector(Hue),this.addDetector(Lue)}addDetector(e){return this.detectors[e.name]=e,this}detect(){let e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:this.options.order,n=[];return e.forEach(r=>{if(this.detectors[r]){let i=this.detectors[r].lookup(this.options);i&&typeof i=="string"&&(i=[i]),i&&(n=n.concat(i))}}),n=n.filter(r=>r!=null&&!Eue(r)).map(r=>this.options.convertDetectedLanguage(r)),this.services&&this.services.languageUtils&&this.services.languageUtils.getBestMatchFromCodes?n:n.length>0?n[0]:null}cacheUserLanguage(e){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:this.options.caches;n&&(this.options.excludeCacheFor&&this.options.excludeCacheFor.indexOf(e)>-1||n.forEach(r=>{this.detectors[r]&&this.detectors[r].cacheUserLanguage(e,this.options)}))}}YY.type="languageDetector";const $ue={nav:{printers:"Printers",archives:"Archives",queue:"Queue",stats:"Statistics",profiles:"Profiles",maintenance:"Maintenance",projects:"Projects",inventory:"Filament",files:"File Manager",notifications:"Notifications",settings:"Settings",system:"System",collapseSidebar:"Collapse sidebar",expandSidebar:"Expand sidebar",update:"Update",updateAvailable:"Update available: v{{version}}",updateAvailableBanner:"Version {{version}} is available!",viewUpdate:"View update",viewOnGithub:"View on GitHub",keyboardShortcuts:"Keyboard shortcuts (?)",switchToLight:"Switch to light mode",switchToDark:"Switch to dark mode",smartSwitches:"Smart Switches",logout:"Logout"},common:{save:"Save",saving:"Saving...",cancel:"Cancel",delete:"Delete",edit:"Edit",add:"Add",close:"Close",confirm:"Confirm",loading:"Loading...",error:"Error",success:"Success",warning:"Warning",enabled:"Enabled",disabled:"Disabled",yes:"Yes",no:"No",on:"On",off:"Off",all:"All",none:"None",search:"Search",filter:"Filter",sort:"Sort",refresh:"Refresh",download:"Download",upload:"Upload",uploading:"Uploading...",uploadFailed:"Upload failed",actions:"Actions",status:"Status",name:"Name",description:"Description",date:"Date",time:"Time",hours:"hours",minutes:"minutes",seconds:"seconds",days:"days",enable:"Enable",disable:"Disable",permissions:"Permissions",noPrinters:"No printers configured",noData:"No data available",linkNotFound:"Link not found",required:"Required",optional:"Optional",dismiss:"Dismiss",apply:"Apply",reset:"Reset",export:"Export",import:"Import",clear:"Clear",selectAll:"Select All",deselectAll:"Deselect All",noChange:"— No change —",unchanged:"Unchanged",unassigned:"Unassigned",unknown:"Unknown",unknownError:"Unknown error",today:"Today",tomorrow:"Tomorrow",asap:"ASAP",overdue:"Overdue",now:"Now",collapse:"Collapse",expand:"Expand",viewArchive:"View archive",viewInFileManager:"View in File Manager",addedBy:"Added by {{username}}",prints:"prints",more:"+{{count}} more",ascending:"Ascending",descending:"Descending",back:"Back",copy:"Copy",copied:"Copied!",printer:"Printer",remove:"Remove",type:"Type",print:"Print",rename:"Rename",move:"Move",create:"Create",duplicate:"Duplicate",left:"Left",right:"Right"},printers:{title:"Printers",addPrinter:"Add Printer",editPrinter:"Edit Printer",deletePrinter:"Delete Printer",printerName:"Printer Name",serialNumber:"Serial Number",ipAddress:"IP Address / Hostname",accessCode:"Access Code",model:"Model",nozzleCount:"Nozzle Count",autoArchive:"Auto Archive",status:{available:"Available",idle:"Idle",printing:"Printing",paused:"Paused",offline:"Offline",problem:"Problem",error:"Error",finished:"Finished",unknown:"Unknown"},temperatures:{nozzle:"Nozzle",bed:"Bed",chamber:"Chamber"},progress:"{{percent}}% complete",timeRemaining:"{{time}} remaining",deleteConfirm:'Are you sure you want to delete "{{name}}"?',maintenanceOk:"Maintenance OK",maintenanceWarning:"{{count}} warning",maintenanceWarning_plural:"{{count}} warnings",maintenanceDue:"{{count}} due",maintenanceDue_plural:"{{count}} due",sort:{name:"Name",status:"Status",model:"Model",location:"Location",ascending:"Sort ascending",descending:"Sort descending"},cardSize:{small:"Small cards",medium:"Medium cards",large:"Large cards",extraLarge:"Extra large cards"},hideOffline:"Hide offline",nextAvailable:"Next available",powerOn:"Power On",offlinePrintersWithPlugs:"Offline printers with smart plugs",noPrintersConfigured:"No printers configured yet",search:"Search printers...",noSearchResults:"No printers match your search or filters",filter:{allStatuses:"All statuses",allLocations:"All locations"},readyToPrint:"Ready to print",external:"External",extL:"Ext-L",extR:"Ext-R",deleteArchives:"Delete print archives",noLabel:"No label",printPreview:"Print preview",width:"Width",height:"Height",noObjectsFound:"No objects found",objectsLoadedOnPrintStart:"Objects are loaded when a print starts",willBeSkipped:"Will be skipped",name:"Name",serialCannotBeChanged:"Serial number cannot be changed",locationHelp:"Used to group printers and filter queue jobs",wifiSignal:{veryWeak:"Very weak",weak:"Weak",fair:"Fair",good:"Good",excellent:"Excellent"},maintenanceUpToDate:"All maintenance up to date - Click to view",chamberLightOn:"Turn on chamber light",chamberLightOff:"Turn off chamber light",files:"Files",browseFiles:"Browse printer files",autoOffAfterPrint:"Auto power-off after print",autoOffExecuted:"Auto-off was executed - turn printer on to reset",hmsErrors:"HMS Errors",viewHmsErrors:"View {{count}} HMS error(s)",resume:"Resume",pause:"Pause",stop:"Stop",camera:"Camera",skipObject:"Skip Object",reconnect:"Reconnect",forceRefresh:"Force Refresh",forceRefreshSuccess:"Refresh requested",mqttDebug:"MQTT Debug",printerInformation:"Printer Information",copyToClipboard:"Copy",copied:"Copied!",state:"State",wifiSignalLabel:"WiFi Signal",developerMode:"Developer Mode",enabled:"Enabled",disabled:"Disabled",addedOn:"Added",sdCard:"SD Card",inserted:"Inserted",notInserted:"Not inserted",totalPrintHours:"Print Hours",activeNozzle:"Active: {{nozzle}} nozzle",nozzleRack:"Nozzle Rack",nozzleDocked:"Docked",nozzleMounted:"Mounted",nozzleActive:"Active",nozzleIdle:"Idle",nozzleDiameter:"Diameter",nozzleType:"Type",nozzleStatus:"Status",nozzleFilament:"Filament",nozzleWear:"Wear",nozzleMaxTemp:"Max Temp",nozzleSerial:"Serial",nozzleHardenedSteel:"Hardened Steel",nozzleStainlessSteel:"Stainless Steel",nozzleTungstenCarbide:"Tungsten Carbide",nozzleFlow:"Flow",nozzleHighFlow:"High Flow",nozzleStandardFlow:"Standard",firmwareUpdate:"Firmware Update",firmwareInstructions:"On the printer's touchscreen, go to",firmwareNav:"Navigate to",settings:"Settings",firmware:"Firmware",discoverPrinters:"Discover Printers",searching:"Searching...",manualEntry:"Manual Entry",addFromCloud:"Add from Cloud",toast:{printerDeleted:"Printer deleted",missingSpoolAssignment:"Print started on {{printer}}. Missing spool assignment for: {{slots}}",printerAdded:"Printer added",printerUpdated:"Printer updated",failedToDelete:"Failed to delete printer",failedToAdd:"Failed to add printer",failedToUpdate:"Failed to update printer",commandSent:"Command sent",failedToSendCommand:"Failed to send command",turnedOn:"{{name}} turned on",failedToPowerOn:"Failed to power on {{name}}",scriptTriggered:"Script triggered",printStopped:"Print stopped",printPaused:"Print paused",printResumed:"Print resumed",referenceDeleted:"Reference deleted",detectionAreaSaved:"Detection area saved",failedToRunScript:"Failed to run script",failedToStopPrint:"Failed to stop print",failedToPausePrint:"Failed to pause print",failedToResumePrint:"Failed to resume print",failedToControlChamberLight:"Failed to control chamber light",failedToSetSpeed:"Failed to set print speed",failedToUpdateSetting:"Failed to update setting",failedToSkipObjects:"Failed to skip objects",failedToRereadRfid:"Failed to re-read RFID",failedToCheckPlate:"Failed to check plate",failedToUpdateLabel:"Failed to update label",failedToDeleteReference:"Failed to delete reference",failedToSaveDetectionArea:"Failed to save detection area",plateCheckEnabled:"Plate check enabled",plateCheckDisabled:"Plate check disabled",calibrationSaved:"Calibration saved!",calibrationFailed:"Calibration failed",rfidRereadInitiated:"RFID re-read initiated"},connection:{connected:"Connected",offline:"Offline"},plateStatus:{markCleared:"Mark plate as cleared",cleared:"Plate Clear",notCleared:"Plate not Clear",inUse:"Plate in Use"},queue:{inQueue:"{{count}} print in queue",inQueue_plural:"{{count}} prints in queue"},controls:"Controls",rfid:{reread:"Re-read RFID"},bedJog:{title:"Move build plate",bed:"Bed",step:"Step (mm)",up:"Move plate up",down:"Move plate down",disabledWhilePrinting:"Disabled while printing",notHomedTitle:"Printer is not homed",notHomedMessage:"The Z axis has not been homed since the last print. Home Z first for safe positioning, or move anyway — soft endstops will be bypassed.",homeZ:"Home Z",moveAnyway:"Move anyway",homingStarted:"Homing Z axis…"},permission:{noAdd:"You do not have permission to add printers",noEdit:"You do not have permission to edit printers",noDelete:"You do not have permission to delete printers",noControl:"You do not have permission to control printers",noFiles:"You do not have permission to access printer files",noAmsRfid:"You do not have permission to re-read AMS RFID",noSmartPlugControl:"You do not have permission to control smart plugs",noCamera:"You do not have permission to view cameras"},modal:{addTitle:"Add Printer",editTitle:"Edit Printer",myPrinter:"My Printer",selectModel:"Select model...",locationGroup:"Location / Group (optional)",locationPlaceholder:"e.g., Workshop, Office, Basement",autoArchiveLabel:"Auto-archive completed prints",fromPrinterSettings:"From printer settings",modelOptional:"Model (optional)",saveChanges:"Save Changes"},skipObjects:{tooltip:"Skip objects",onlyWhilePrinting:"Skip objects (only while printing)",requiresMultiple:"Skip objects (requires 2+ objects)",title:"Skip Objects",matchIdsInfo:"Match IDs with your printer display",printerShowsIds:"The printer screen shows object IDs on the build plate",skipSelected:"Skip Selected",skipping:"Skipping...",noObjectsSelected:"No objects selected",selectObjectsToSkip:"Select objects you want to skip from the current print",skipped:"skipped",objectsSkipped:"Objects skipped",activeCount:"{{count}} active",waitForLayer:"Wait for layer 2+ to skip objects (currently layer {{layer}})",skip:"Skip",confirmTitle:"Skip Object?",confirmMessage:'Are you sure you want to skip "{{name}}"? This cannot be undone.'},confirm:{deleteTitle:"Delete Printer",deleteMessage:'Are you sure you want to delete "{{name}}"? This will remove all connection settings.',deleteArchivesNote:"All print history for this printer will be permanently deleted.",keepArchivesNote:"Print history will be kept but no longer associated with this printer.",stopTitle:"Stop Print",stopMessage:'Are you sure you want to stop the current print on "{{name}}"? This will cancel the print job.',stopButton:"Stop Print",pauseTitle:"Pause Print",pauseMessage:'Are you sure you want to pause the current print on "{{name}}"?',pauseButton:"Pause Print",resumeTitle:"Resume Print",resumeMessage:'Are you sure you want to resume the print on "{{name}}"?',resumeButton:"Resume Print",powerOnTitle:"Power On Printer",powerOnMessage:'Are you sure you want to turn ON the power for "{{name}}"?',powerOnButton:"Power On",powerOffTitle:"Power Off Printer",powerOffMessage:'Are you sure you want to turn OFF the power for "{{name}}"?',powerOffWarning:'WARNING: "{{name}}" is currently printing! Are you sure you want to turn OFF the power? This will interrupt the print and may damage the printer.',powerOffButton:"Power Off"},bulk:{select:"Select",selectAll:"Select All",selectByLocation:"Select by Location",selected:"{{count}} selected",actions:{stop:"Stop",pause:"Pause",resume:"Resume",clearPlate:"Clear Bed",clearHMS:"Clear Notifications"},confirm:{stopTitle:"Stop {{count}} Prints",stopMessage:"This will cancel active prints on {{count}} printer(s). This action cannot be undone.",stopButton:"Stop All",pauseTitle:"Pause {{count}} Prints",pauseMessage:"This will pause active prints on {{count}} printer(s).",pauseButton:"Pause All",clearPlateTitle:"Clear {{count}} Print Beds",clearPlateMessage:"This will clear the print bed on {{count}} printer(s) and may trigger queued jobs.",clearPlateButton:"Clear All"},success:"{{action}} completed on {{count}} printer(s)",partial:"{{succeeded}} succeeded, {{failed}} failed",noneApplicable:"No selected printers are in the right state for this action",selectByState:"Select by State"},discovery:{title:"Discover Printers",searching:"Searching...",scanning:"Scanning...",scanProgress:"Scanning... {{scanned}}/{{total}}",foundPrinters:"Found {{count}} printer(s)",noPrintersFound:"No printers found",noPrintersFoundSubnet:"No printers found in the specified subnet.",noPrintersFoundNetwork:"No printers found on the network.",allConfigured:"All discovered printers are already configured.",alreadyAdded:"Already added",select:"Select",manualEntry:"Manual Entry",addFromCloud:"Add from Cloud",subnetToScan:"Subnet to scan",dockerNote:"Docker detected. Enter your printer's subnet in CIDR notation. Requires network_mode: host in docker-compose.yml.",scanSubnet:"Scan Subnet for Printers",discoverNetwork:"Discover Printers on Network",scanningSubnet:"Scanning subnet for Bambu printers...",scanningNetwork:"Scanning network...",serialRequired:"Serial required",unknown:"Unknown",failedToStart:"Failed to start discovery"},drying:{start:"Start Drying",stop:"Stop Drying",temperature:"Temperature",duration:"Duration",hours:"hours",timeRemaining:"{{time}} left",active:"Drying",notSupported:"Drying not supported",powerRequired:"Connect AMS power adapter to enable drying",startingDrying:"Starting drying...",stoppingDrying:"Stopping drying...",rotateTray:"Rotate spool during drying"},filaments:"Filaments",openCameraOverlay:"Open camera overlay",openCameraWindow:"Open camera in new window",firmwareUpdateAvailable:"Firmware update available: {{current}} → {{latest}}",firmwareUpToDate:"Firmware {{version}} — Up to date",firmwareUpdateButton:"Update",plateDetection:{noPermission:"You do not have permission to update printers",enabledClick:"Plate check enabled - Click to disable",disabledClick:"Plate check disabled - Click to enable",manageCalibration:"Manage plate detection calibration",calibrationRequired:"Calibration Required",calibrationInstructions:"Please ensure the build plate is completely empty, then click Calibrate.",calibrationDescription:"Calibration captures a reference image of the empty plate. Future checks will compare against this reference to detect objects.",calibrationTip:"Tip: You can store up to 5 calibrations for different plates. The system automatically uses the best match when checking.",plateEmpty:"Plate appears empty",objectsDetected:"Objects detected on plate",confidence:"Confidence",difference:"Difference",analysisPreview:"Analysis preview:",analysisLegend:"Green box = detection area, Red overlay = differences from calibration",savedReferences:"Saved References ({{count}}/{{max}})",deleteReference:"Delete reference",labelPlaceholder:"Label...",clickToEdit:"{{label}} - Click to edit",clickToAddLabel:"Click to add label"},speed:{title:"Print Speed",silent:"Silent (50%)",standard:"Standard (100%)",sport:"Sport (124%)",ludicrous:"Ludicrous (166%)"},airduct:{title:"Airduct Mode",cooling:"Cooling",heating:"Heating"},noSdCard:"No SD",door:{open:"Open",closed:"Closed"},fans:{partCooling:"Part Cooling Fan",auxiliary:"Auxiliary Fan",chamber:"Chamber Fan"},clickToViewHmsErrors:"Click to view HMS errors",estimatedCompletion:"Estimated completion time",plateNumber:"Plate {{number}}",slotOptions:"Slot options",amsPopup:{friendlyName:"AMS Name",friendlyNamePlaceholder:"e.g. AMS Friendly Name",serialNumber:"Serial Number",firmwareVersion:"Firmware",save:"Save",clear:"Clear",noEditPermission:"You do not have permission to rename AMS units"},firmwareModal:{title:"Firmware Update",titleUpToDate:"Firmware Info",currentVersion:"Current:",latestVersion:"Latest:",releaseNotes:"Release Notes",checkingPrereqs:"Checking prerequisites...",sdCardReady:"SD card ready. Click below to upload firmware.",uploadedSuccess:"Firmware uploaded to SD card!",applyInstructions:"To apply the update on your printer:",step1:"On the printer's touchscreen, go to Settings",step2:"Navigate to Firmware",step3:"Select Update from SD card",step4:"The update will take 10-20 minutes",done:"Done",starting:"Starting...",uploadFirmware:"Upload Firmware",uploadFailed:"Failed to start upload: {{error}}",uploadedToast:"Firmware uploaded! Trigger update from printer screen.",availableVersions:"Available versions",usable:"Usable",unavailable:"Unavailable",installed:"Installed",newerBadge:"newer",olderBadge:"older",currentBadge:"current"},accessCodePlaceholder:"Leave empty to keep current",roi:{title:"Detection Area (ROI)",xStart:"X Start",yStart:"Y Start",width:"Width",height:"Height",instruction:"Adjust the detection area to focus on the build plate. The green box in the preview shows the current area."},developerModeWarning:"Developer LAN mode is not enabled on: {{names}}. Some features may not work.",howToEnable:"How to enable",incompatibleFile:"This file was sliced for {{slicedFor}}, but this printer is a {{printerModel}}",dropNotPrintable:"Only .gcode and .gcode.3mf files can be printed",dropToPrint:"Drop to print",cannotPrint:"Printer busy"},archives:{title:"Print Archives",searchPlaceholder:"Search archives...",filterByPrinter:"Filter by printer",filterByStatus:"Filter by status",sortBy:"Sort by",sortNewest:"Newest first",sortOldest:"Oldest first",sortName:"Name",sortDuration:"Duration",sortLargest:"Largest first",sortSmallest:"Smallest first",sortSize:"Size",noArchives:"No archives found",noArchivesSearch:"No archives match your search",originalPrintNotVisible:"Original print not visible - try clearing filters",noArchivesYet:"No archives yet",prints:"prints",pagination:{showing:"Showing",to:"to",of:"of",show:"Show",page:"Page",all:"All"},loadingArchives:"Loading archives...",releaseToUpload:"Release to upload",showAll:"Show all",showFavoritesOnly:"Show favorites only",gridView:"Grid view",listView:"List view",calendarView:"Calendar view",logView:"Print Log",manageTags:"Manage Tags",showFailedPrints:"Show failed prints",hideFailedPrints:"Hide failed prints",hideDuplicates:"Hide Duplicates",viewOriginalPrint:"Click to view original print (#{{id}})",printTime:"Print Time",filamentUsed:"Filament Used",cost:"Cost",reprint:"Reprint",preview:"Preview",deleteArchive:"Delete Archive",deleteConfirm:"Are you sure you want to delete this archive?",favorite:"Favorite",unfavorite:"Remove from favorites",viewDetails:"View Details",status:{completed:"Completed",failed:"Failed",stopped:"Stopped"},toast:{source3mfAttached:"Source 3MF attached: {{filename}}",failedUploadSource3mf:"Failed to upload source 3MF",source3mfRemoved:"Source 3MF removed",failedRemoveSource3mf:"Failed to remove source 3MF",f3dAttached:"F3D attached: {{filename}}",failedUploadF3d:"Failed to upload F3D",f3dRemoved:"F3D removed",failedRemoveF3d:"Failed to remove F3D",timelapseAttached:"Timelapse attached: {{filename}}",timelapseAlreadyAttached:"Timelapse already attached",noMatchingTimelapse:"No matching timelapse found",failedScanTimelapse:"Failed to scan for timelapse",failedAttachTimelapse:"Failed to attach timelapse",timelapseRemoved:"Timelapse removed",failedRemoveTimelapse:"Failed to remove timelapse",timelapseUploaded:"Timelapse uploaded: {{filename}}",failedUploadTimelapse:"Failed to upload timelapse",archiveDeleted:"Archive deleted",failedDeleteArchive:"Failed to delete archive",addedToFavorites:"Added to favorites",removedFromFavorites:"Removed from favorites",projectUpdated:"Project updated",failedUpdateProject:"Failed to update project",linkCopied:"Link copied to clipboard",failedCopyLink:"Failed to copy link",photoDeleted:"Photo deleted",failedDeletePhoto:"Failed to delete photo",failedDeleteArchives:"Failed to delete archives",failedUpdateFavorites:"Failed to update favorites",exportDownloaded:"Export downloaded",exportFailed:"Export failed"},menu:{print:"Print",schedule:"Schedule",openInBambuStudio:"Open in Slicer",slice:"Slice",externalLink:"External Link",viewOnMakerWorld:"View on MakerWorld",preview3d:"3D Preview",viewTimelapse:"View Timelapse",scanForTimelapse:"Scan for Timelapse",uploadTimelapse:"Upload Timelapse",removeTimelapse:"Remove Timelapse",downloadSource3mf:"Download Source 3MF",uploadSource3mf:"Upload Source 3MF",replaceSource3mf:"Replace Source 3MF",removeSource3mf:"Remove Source 3MF",uploadF3d:"Upload F3D",replaceF3d:"Replace F3D",downloadF3d:"Download F3D",removeF3d:"Remove F3D",download:"Download",copyDownloadLink:"Copy Download Link",qrCode:"QR Code",viewPhotos:"View Photos",viewPhotosCount:"View Photos ({{count}})",projectPage:"Project Page",addToFavorites:"Add to Favorites",removeFromFavorites:"Remove from Favorites",edit:"Edit",goToProject:"Go to Project: {{name}}",addToProject:"Add to Project",removeFromProject:"Remove from Project",loading:"Loading...",noProjectsAvailable:"No projects available",select:"Select",deselect:"Deselect",delete:"Delete"},permission:{noReprint:"You do not have permission to reprint this archive",noAddToQueue:"You do not have permission to add to queue",noUpdateArchives:"You do not have permission to update archives",noUploadFiles:"You do not have permission to upload files",noDownload:"You do not have permission to download archives",noCopyLink:"You do not have permission to copy download links",noDelete:"You do not have permission to delete this archive",noCreate:"You do not have permission to create archives"},card:{previousPlate:"Previous plate",nextPlate:"Next plate",plateNumber:"Plate {{index}}",moreOptions:"Right-click for more options",addToFavorites:"Add to favorites",removeFromFavorites:"Remove from favorites",cancelled:"cancelled",failed:"failed",duplicate:"duplicate",duplicateTitle:"This model has been printed before",openSource3mf:"Open source 3MF in Bambu Studio (right-click for more options)",downloadF3d:"Download Fusion 360 design file",viewTimelapse:"View timelapse",viewPhoto:"View 1 photo",viewPhotos:"View {{count}} photos",openFolder:"Open folder: {{name}}",slicedFile:"Sliced file - ready to print",sourceFile:"Source file only - no AMS mapping available",gcode:"GCODE",source:"SOURCE",project:"Project: {{name}}",estimated:"Estimated: {{time}}",actual:"Actual: {{time}}",accuracy:"Accuracy: {{percent}}%",filament:"{{weight}}g",layer:"{{count}} layer",layers:"{{count}} layers",object:"{{count}} object",objects:"{{count}} objects",slicedFor:"Sliced for {{model}}",uploadedBy:"Uploaded By",noPermissionReprint:"You do not have permission to reprint",noFileForReprint:"No 3MF file available — the file could not be downloaded from the printer when the print was recorded",noPermissionEdit:"You do not have permission to edit archives",noPermissionDelete:"You do not have permission to delete archives",reprint:"Reprint",schedulePrint:"Schedule Print",schedule:"Schedule",openInBambuStudio:"Open in Slicer",openInBambuStudioToSlice:"Open in Slicer to slice",slice:"Slice",externalLink:"External Link",makerWorld:"MakerWorld: {{designer}}",viewProject:"View project",noExternalLink:"No external link",preview3d:"3D Preview",download:"Download",edit:"Edit",delete:"Delete"},modal:{deleteArchive:"Delete Archive",deleteConfirm:'Are you sure you want to delete "{{name}}"? This action cannot be undone.',deleteButton:"Delete",removeSource3mf:"Remove Source 3MF",removeSource3mfConfirm:'Are you sure you want to remove the source 3MF file from "{{name}}"? This will delete the original slicer project file.',removeButton:"Remove",removeF3d:"Remove F3D",removeF3dConfirm:'Are you sure you want to remove the Fusion 360 design file from "{{name}}"?',removeTimelapse:"Remove Timelapse",removeTimelapseConfirm:'Are you sure you want to remove the timelapse video from "{{name}}"?',timelapse:"{{name}} - Timelapse",selectTimelapse:"Select Timelapse",selectTimelapseDesc:"No auto-match found. Select the timelapse for this print:",deleteArchives:"Delete Archives",deleteArchivesConfirm:"Are you sure you want to delete {{count}} archive(s)? This action cannot be undone.",deleteCount:"Delete {{count}}"},page:{title:"Archives",printsCount:"{{filtered}} of {{total}} prints",dropFilesHere:"Drop .3mf files here",releaseToUpload:"Release to upload",only3mfSupported:"Only .3mf files are supported",close:"Close",selected:"{{count}} selected",selectAll:"Select All",tags:"Tags",project:"Project",favorite:"Favorite",delete:"Delete",toggledFavorites:"Toggled favorites for {{count}} archive(s)",failedUpdateFavorites:"Failed to update favorites",archivesDeleted:"{{count}} archive(s) deleted",failedDeleteArchives:"Failed to delete archives",photoDeleted:"Photo deleted",failedDeletePhoto:"Failed to delete photo"},list:{name:"Name",printer:"Printer",date:"Date",size:"Size",actions:"Actions",hasTimelapse:"Has timelapse"},log:{date:"Date",printName:"Print Name",printer:"Printer",user:"User",status:"Status",duration:"Duration",filament:"Filament",allPrinters:"All Printers",allUsers:"All Users",allStatuses:"All Statuses",cancelled:"Cancelled",skipped:"Skipped",dateFrom:"From",dateTo:"To",noEntries:"No print log entries found",showing:"Showing {{count}} of {{total}} entries",rowsPerPage:"Rows",page:"Page",prev:"Prev",next:"Next",clearLog:"Clear Log",clearLogTitle:"Clear Print Log",clearLogConfirm:"All print log entries will be permanently deleted. Archives and queue items are not affected. This action cannot be undone. Are you sure?",clearLogButton:"Clear All",cleared:"{{count}} log entries cleared",clearFailed:"Failed to clear print log"}},queue:{title:"Print Queue",subtitle:"Schedule and manage your print jobs",addToQueue:"Add to Queue",print:"Print",reprint:"Re-print",schedulePrint:"Schedule Print",editQueueItem:"Edit Queue Item",printToPrinters:"Print to {{count}} Printers",queueToPrinters:"Queue to {{count}} Printers",queueSelectedPlates:"Queue {{count}} Plates",selectAllPlates:"Select All {{count}} Plates",deselectAll:"Deselect All",printQueued:"Print queued",itemsQueued:"{{count}} items queued",sending:"Sending...",sendingProgress:"Sending {{current}}/{{total}}...",adding:"Adding...",addingProgress:"Adding {{current}}/{{total}}...",savingProgress:"Saving {{current}}/{{total}}...",clearQueue:"Clear Queue",clearHistory:"Clear History",emptyQueue:"Queue is empty",position:"Position",scheduledTime:"Scheduled Time",moveUp:"Move Up",moveDown:"Move Down",startNow:"Start Now",printingInProgress:"Printing in progress...",viewArchive:"View archive",viewInFileManager:"View in File Manager",itemCount:"{{count}} item",itemCount_plural:"{{count}} items",dragToReorder:"Drag to reorder (ASAP only)",reorderHint:"Position only affects ASAP items. Scheduled items run at their set time.",sjf:{label:"SJF",tooltip:"Shortest Job First — scheduler prioritizes shorter prints"},addedBy:"Added by {{name}}",nextInQueue:"Next in queue",clearPlate:"Clear Plate & Start Next",clearPlateSuccess:"Plate cleared — ready for next print",plateReady:"Plate cleared — ready for next print",plateNumber:"Plate {{index}}",quantity:"Quantity",quantityHint:"Creates {{count}} queue items",activeBatches:"Active Batches",batchProgress:"{{completed}} of {{total}} completed",cancelBatch:"Cancel Remaining",batchCancelled:"Remaining batch items cancelled",cancelBatchConfirmTitle:"Cancel Batch",cancelBatchConfirmMessage:"Cancel all remaining pending items in this batch?",batch:"Batch",sections:{currentlyPrinting:"Currently Printing",queued:"Queued",history:"History"},status:{pending:"Pending",waiting:"Waiting",printing:"Printing",paused:"Paused",completed:"Completed",failed:"Failed",skipped:"Skipped",cancelled:"Cancelled"},summary:{printing:"Printing",queued:"Queued",totalTime:"Total Queue Time",totalWeight:"Total Queue Weight",history:"History"},filter:{allPrinters:"All Printers",unassigned:"Unassigned",allStatus:"All Status",allLocations:"All Locations",any:"Any"},sort:{byPosition:"Sort by Position",byName:"Sort by Name",byPrinter:"Sort by Printer",bySchedule:"Sort by Schedule",byDate:"Sort by Date",ascendingOldest:"Ascending (oldest first)",descendingNewest:"Descending (newest first)"},badges:{staged:"Staged",requiresPrevious:"Requires previous success",autoPowerOff:"Auto power off",gcodeInjection:"G-code"},empty:{title:"No prints scheduled",description:'Schedule a print from the Archives page using the "Schedule" option in the context menu, or drag and drop files to get started.'},time:{asap:"ASAP",overdue:"Overdue",now:"Now",lessThanMinute:"In less than a minute",inMinutes:"In {{count}} min",inHours:"In {{count}} hours"},actions:{stopPrint:"Stop Print",startPrint:"Start Print",requeue:"Re-queue"},bulkEdit:{title:"Edit {{count}} Item",title_plural:"Edit {{count}} Items",description:"Only changed settings will be applied to selected items.",printer:"Printer",noChange:"— No change —",queueOptions:"Queue Options",staged:"Staged (manual start)",autoPowerOff:"Auto power off after print",requirePrevious:"Require previous success",printOptions:"Print Options",bedLevelling:"Bed levelling",flowCalibration:"Flow calibration",vibrationCalibration:"Vibration calibration",layerInspection:"First layer inspection",timelapse:"Timelapse",useAms:"Use AMS",applyChanges:"Apply Changes",selectAll:"Select All",deselectAll:"Deselect All",selected:"{{count}} selected",editSelected:"Edit Selected",cancelSelected:"Cancel Selected"},confirm:{cancelTitle:"Cancel Scheduled Print",cancelMessage:'Are you sure you want to cancel "{{name}}"?',stopTitle:"Stop Print",stopMessage:'Are you sure you want to stop the current print "{{name}}"? This will cancel the print job on the printer.',removeTitle:"Remove from History",removeMessage:'Are you sure you want to remove "{{name}}" from the queue history?',clearHistoryTitle:"Clear History",clearHistoryMessage:"Are you sure you want to remove all {{count}} item(s) from the history?",cancelButton:"Cancel Print",stopButton:"Stop Print",thisPrint:"this print",thisItem:"this item"},toast:{cancelled:"Queue item cancelled",cancelFailed:"Failed to cancel item",removed:"Queue item removed",removeFailed:"Failed to remove item",stopped:"Print stopped",stopFailed:"Failed to stop print",released:"Print released to queue",startFailed:"Failed to start print",reorderFailed:"Failed to reorder queue",historyCleared:"Cleared {{count}} history item(s)",clearHistoryFailed:"Failed to clear history",updateFailed:"Failed to update items",bulkCancelled:"Cancelled {{count}} item(s)",bulkCancelFailed:"Failed to cancel items"},timeline:{listView:"List",timelineView:"Timeline",unassigned:"Unassigned",noData:"No scheduled prints for this day",allDoneBy:"All prints estimated done by {{time}}",staged:"Staged",filterAll:"Show All",filterPrinting:"Printing",filterQueued:"Queued",time:{anyMoment:"any moment",minutesLeft:"{{minutes}}m left",hoursLeft:"{{hours}}h left",hoursMinutesLeft:"{{hours}}h {{minutes}}m left"},day:{previous:"Previous day",next:"Next day",today:"Today"}},permissions:{noStopPrint:"You do not have permission to stop prints",noStartPrint:"You do not have permission to start prints",noEdit:"You do not have permission to edit this queue item",noCancel:"You do not have permission to cancel this queue item",noRequeue:"You do not have permission to re-queue items",noRemove:"You do not have permission to remove this queue item",noClearHistory:"You do not have permission to clear all history",noEditItems:"You do not have permission to edit queue items",noCancelItems:"You do not have permission to cancel queue items"}},backgroundDispatch:{unknownFile:"Unknown file",unknownPrinter:"Unknown printer",startingPrints:"Starting prints",progressSummary:"{{complete}}/{{total}} complete • Dispatched: {{dispatched}} • Processing: {{processing}}",expandDetails:"Expand dispatch details",collapseDetails:"Collapse dispatch details",dismissToast:"Dismiss dispatch toast",cancelDispatchJob:"Cancel dispatch job",cancel:"Cancel",cancelling:"Cancelling…",status:{dispatched:"Dispatched",processing:"Processing",completed:"Completed",failed:"Failed",cancelled:"Cancelled"},toast:{cancellingUpload:"Cancelling upload...",cancelled:"Dispatch cancelled",cancelFailed:"Failed to cancel dispatch",completeWithFailures:"Background dispatch complete: {{completed}} succeeded, {{failed}} failed",completeSuccess:"Background dispatch complete: {{completed}} succeeded",printStartedRemaining:"{{completed}} print(s) started, {{remaining}} more sending..."}},stats:{title:"Dashboard",subtitle:"Drag widgets to rearrange. Click the eye icon to hide.",overview:"Overview",totalPrints:"Total Prints",successRate:"Success Rate",totalPrintTime:"Total Print Time",printTime:"Print Time",totalFilament:"Total Filament Used",filamentUsed:"Filament Used",filamentCost:"Filament Cost",totalCost:"Total Cost",energyUsed:"Energy Used",energyCost:"Energy Cost",energyWarmingUpTooltip:"Energy tracking is still collecting hourly snapshots. Date-range totals will become accurate once at least one snapshot exists before the selected range. Early values may undercount.",averagePrintTime:"Average Print Time",printsPerDay:"Prints per Day",byPrinter:"By Printer",printsByPrinter:"Prints by Printer",byMaterial:"By Material",byMonth:"By Month",last7Days:"Last 7 Days",last30Days:"Last 30 Days",last90Days:"Last 90 Days",allTime:"All Time",quickStats:"Quick Stats",printActivity:"Print Activity",filamentTypes:"Filament Types",filamentTrends:"Filament Trends",failureAnalysis:"Failure Analysis",timeAccuracy:"Time Accuracy",successful:"Successful:",failed:"Failed:",perfectEstimate:"100% = perfect estimate",noTimeAccuracyData:"No time accuracy data yet",noFilamentData:"No filament data available",noPrinterData:"No printer data available",noPrintData:"No print data available",noPrintDataLast30Days:"No print data in the last 30 days",failureReasons:"Failure Reasons",topFailureReasons:"Top Failure Reasons",failedPrintsCount:"{{failed}} / {{total}} prints failed",lastWeekRate:"Last week: {{rate}}%",resetLayout:"Reset Layout",recalculateCosts:"Recalculate Costs",recalculateCostsHint:"Recalculate all archive costs using current filament prices",exportStats:"Export Stats",exportAsCsv:"Export as CSV",exportAsExcel:"Export as Excel",hiddenCount:"{{count}} Hidden",exportDownloaded:"Export downloaded",exportFailed:"Export failed",layoutReset:"Layout reset",recalculatedCosts:"Recalculated costs for {{count}} archives",recalculateFailed:"Failed to recalculate costs",loadingStats:"Loading statistics...",noPermissionResetLayout:"You do not have permission to reset layout",noPermissionRecalculate:"You do not have permission to recalculate costs",noPrintDataInRange:"No print data in selected range",periodFilament:"Period Filament",periodCost:"Period Cost",avgPerPrint:"Avg per Print",usageOverTime:"Usage Over Time",filamentByWeight:"Weight",printDuration:"Print Duration",printerUtilization:"Printer Utilization",filamentSuccess:"Success by Material",printHabits:"Print Habits",printTimeOfDay:"Print Time of Day",colorDistribution:"Color Distribution",noColorData:"No color data available",records:"Records",longestPrint:"Longest Print",heaviestPrint:"Heaviest Print",mostExpensivePrint:"Most Expensive",busiestDay:"Busiest Day",successStreak:"Success Streak",streakPrint:"consecutive print",streakPrints:"{{count}} consecutive prints",printerStats:"Printer Stats",hours:"hours",avgPrints:"Avg. prints",noArchiveData:"No print data available",filamentByTime:"Time",avgWeight:"Avg. weight",avgTime:"Avg. time",filamentByPrints:"Prints",timeframe:{today:"Today","this-week":"This Week","this-month":"This Month","last-7":"Last 7 Days","last-30":"Last 30 Days","last-90":"Last 90 Days","this-year":"This Year","all-time":"All Time",custom:"Custom Range",from:"From",to:"To"},allUsers:"All Users",noUser:"No User (System)",filterByUser:"Filter by User"},maintenance:{title:"Maintenance",overview:"Overview",allOk:"All maintenance up to date",dueCount:"{{count}} item due",dueCount_plural:"{{count}} items due",warningCount:"{{count}} warning",warningCount_plural:"{{count}} warnings",totalPrintTime:"Total Print Time",nextMaintenance:"Next Maintenance",nothingDue:"Nothing due",tasks:"Tasks",lastPerformed:"Last performed",interval:"Interval",hoursRemaining:"{{hours}}h remaining",hoursOverdue:"{{hours}}h overdue",markDone:"Mark as Done",performMaintenance:"Perform Maintenance",history:"History",noHistory:"No maintenance history",editPrintHours:"Edit Print Hours",currentHours:"Current Hours",statusTab:"Status",settingsTab:"Settings",overdueCount:"{{count}} overdue",dueSoonCount:"{{count}} due soon",dueSoon:"Due soon",allGood:"All good",overdueBy:"Overdue by {{duration}}",dueIn:"Due in {{duration}}",timeLeft:"{{duration}} left",day:"1 day",days:"{{count}} days",week:"1 week",weeks:"{{count}} weeks",month:"1 month",months:"{{count}} months",year:"1 year",maintenanceTypes:"Maintenance Types",maintenanceTypesDescription:"System types and your custom maintenance tasks",addCustomType:"Add Custom Type",restoreDefaults:"Restore Default Tasks",intervalType:"Interval Type",intervalValue:"Interval ({{type}})",icon:"Icon",documentationLink:"Documentation Link (optional)",assignToPrinters:"Assign to Printers",selectAtLeastOnePrinter:"Select at least one printer",addType:"Add Type",custom:"Custom",printHours:"Print Hours",calendarDays:"Calendar Days",exampleName:"e.g., Replace HEPA Filter",viewDocumentation:"View documentation",timeBasedInterval:"Time-based interval",intervalOverrides:"Interval Overrides",intervalOverridesDescription:"Customize intervals for specific printers",assignedToPrinters:"Assigned to printers:",noPrintersAssigned:"No printers assigned",addPrinterShort:"Add:",printersAssignedClick:"{{count}} printer(s) assigned - click to manage",removeFromPrinter:"Remove from this printer",types:{lubricateCarbonRods:"Lubricate Carbon Rods",lubricateRails:"Lubricate Linear Rails",cleanNozzle:"Clean Nozzle/Hotend",checkBelts:"Check Belt Tension",cleanBuildPlate:"Clean Build Plate",checkExtruder:"Check Extruder Gears",checkCooling:"Check Cooling Fans",generalInspection:"General Inspection",cleanCarbonRods:"Clean Carbon Rods",lubricateSteelRods:"Lubricate Steel Rods",cleanSteelRods:"Clean Steel Rods",cleanLinearRails:"Clean Linear Rails",checkPtfeTube:"Check PTFE Tube",replaceHepaFilter:"Replace HEPA Filter",replaceCarbonFilter:"Replace Carbon Filter",lubricateLeftNozzleRail:"Lubricate Left Nozzle Rail"},maintenanceComplete:"Maintenance marked as complete",typeUpdated:"Maintenance type updated",typeDeleted:"Maintenance type deleted",defaultsRestored:"Restored {{count}} default task(s)",printHoursUpdated:"Print hours updated",printerAssigned:"Printer assigned",printerRemoved:"Printer removed",deleteTypeConfirm:'Delete "{{name}}"?',deleteSystemTypeTitle:"Delete default maintenance task?",deleteSystemTypeMessage:'Are you sure you want to delete the default maintenance task "{{name}}"?',noPermissionUpdate:"You do not have permission to update maintenance items",noPermissionPerform:"You do not have permission to perform maintenance",noPermissionEditTypes:"You do not have permission to edit maintenance types",noPermissionDeleteTypes:"You do not have permission to delete maintenance types",noPermissionEditHours:"You do not have permission to edit print hours",noPermissionRemovePrinter:"You do not have permission to remove printer assignments",noPermissionAssignPrinter:"You do not have permission to assign printers",noPermissionEditIntervals:"You do not have permission to edit intervals",configureSettings:"Configure maintenance types and intervals"},settings:{title:"Settings",general:"General",tabs:{general:"General",smartPlugs:"Smart Plugs",notifications:"Notifications",queue:"Workflow",filament:"Filament",network:"Network",apiKeys:"API Keys",virtualPrinter:"Virtual Printer",spoolbuddy:"SpoolBuddy",failureDetection:"Failure Detection",users:"Authentication",backup:"Backup",emailAuth:"Email Authentication",ldap:"LDAP",twoFa:"Two-Factor Auth",oidc:"SSO / OIDC"},spoolbuddy:{infoTitle:"SpoolBuddy devices",infoBody:"SpoolBuddy kiosks register themselves automatically via heartbeat. Unregister a device here if it is no longer in use or if a stale duplicate was left behind by a daemon crash.",duplicatesTitle:"{{count}} devices registered",duplicatesBody:"Only the first registered device is used by the kiosk UI. If one of these is a stale duplicate from a crash, unregister it — an online device will re-register itself on its next heartbeat.",empty:"No SpoolBuddy devices registered yet.",online:"Online",offline:"Offline",unregister:"Unregister",unregisterSuccess:"Device unregistered",unregisterError:"Failed to unregister device",confirmTitle:"Unregister SpoolBuddy device?",confirmBody:'This will remove "{{hostname}}" ({{deviceId}}) from the database. If the device is online, it will re-register itself on its next heartbeat.',ipAddress:"IP address",firmware:"Firmware",lastSeen:"Last seen",daemonUptime:"Daemon uptime",systemUptime:"System uptime",never:"never",nfc:"NFC",scale:"Scale",cpuTemp:"CPU temp",memory:"Memory",disk:"Disk",update:"Update",updateConfirmTitle:"Update Spoolbuddy daemon?",updateConfirmBody:'Trigger a software update on "{{hostname}}"? The daemon will restart once the update is applied.',restartBrowser:"Restart Browser",restartBrowserConfirmTitle:"Restart kiosk browser?",restartBrowserConfirmBody:'Restart the kiosk browser on "{{hostname}}"? The display will blank briefly.',restartDaemon:"Restart Daemon",restartDaemonConfirmTitle:"Restart Spoolbuddy daemon?",restartDaemonConfirmBody:'Restart the Spoolbuddy daemon on "{{hostname}}"? The device will go offline for a few seconds.',reboot:"Reboot",rebootConfirmTitle:"Reboot device?",rebootConfirmBody:'Reboot "{{hostname}}"? The device will be offline for around a minute.',shutdown:"Shutdown",shutdownConfirmTitle:"Shutdown device?",shutdownConfirmBody:'Shutdown "{{hostname}}"? You will need physical access to power it back on.',commandConfirm:"Confirm",commandQueued:"Command queued",commandError:"Failed to send command"},ldap:{title:"LDAP Authentication",enabledDesc:"LDAP authentication is enabled",disabledDesc:"LDAP authentication is disabled",disabledHint:"Configure and save LDAP settings below, then enable.",enabled:"LDAP authentication enabled",disabled:"LDAP authentication disabled",feature1:"Users can login with LDAP credentials",feature2:"Local admin account remains as fallback",feature3:"LDAP groups are mapped to BamBuddy groups on login",serverConfig:"LDAP Server Configuration",serverUrl:"Server URL",serverUrlHint:"Use ldaps:// for SSL or ldap:// with StartTLS",security:"Security",securityHint:"StartTLS upgrades a plain connection to TLS. LDAPS uses TLS from the start.",bindDn:"Bind DN (Service Account)",bindPassword:"Bind Password",searchBase:"Search Base DN",userFilter:"User Search Filter",userFilterHint:"{username} is replaced with the login username. Use (uid={username}) for OpenLDAP.",autoProvision:"Auto-provision users",autoProvisionHint:"Automatically create a BamBuddy account on first LDAP login",defaultGroup:"Default group",defaultGroupNone:"— None (no fallback) —",defaultGroupHint:"Fallback group assigned when an LDAP user authenticates but is not listed in any mapped LDAP group. Leave empty to leave unmapped users without permissions.",groupMapping:"Group Mapping (JSON)",groupMappingHint:"Map LDAP group DNs to BamBuddy groups. Available groups: ",testConnection:"Test Connection",settingsSaved:"LDAP settings saved",errors:{serverRequired:"LDAP server URL is required",searchBaseRequired:"Search base DN is required",enableAuthFirst:"Enable authentication first",configureLdapFirst:"Save LDAP settings first"}},email:{smtpSettings:"SMTP Configuration",smtpHost:"SMTP Server",smtpPort:"SMTP Port",security:"Security",authentication:"Authentication",username:"Username",password:"Password",fromEmail:"From Email",fromName:"From Name",testConnection:"Test SMTP Connection",testRecipient:"Test Recipient Email",sendTest:"Send Test Email",sending:"Sending...",save:"Save Settings",saving:"Saving...",advancedAuth:"Advanced Authentication",advancedAuthEnabled:"Advanced Authentication is enabled",advancedAuthEnabledDesc:"Email-based user management features are active. New users will receive auto-generated passwords via email, and users can reset their passwords through the forgot password feature.",advancedAuthDisabled:"Advanced Authentication is disabled",advancedAuthDisabledDesc:"Enable advanced authentication to activate email-based features for user management.",enable:"Enable",disable:"Disable",feature1:"Passwords are auto-generated and emailed to new users",feature2:"Users can login with username or email",feature3:"Forgot password feature is available",feature4:"Admins can reset user passwords via email",errors:{requiredFields:"Please fill in all required fields",usernameRequired:"Username is required when authentication is enabled",enterTestEmail:"Please enter a test email address",smtpServerAndEmail:"Please fill in SMTP Server and From Email before testing",usernamePasswordRequired:"Username and Password are required when authentication is enabled",configureSmtpFirst:"Please configure and test SMTP settings first",enableAuthFirst:"Please enable authentication first to use email-based features."},success:{settingsSaved:"SMTP settings saved successfully"},securityOptions:{starttls:"STARTTLS (Port 587)",ssl:"SSL/TLS (Port 465)",none:"None (Port 25)"},authOptions:{enabled:"Enabled",disabled:"Disabled"}},appearance:"Appearance",notifications:"Notifications",smartPlugs:"Smart Plugs",spoolman:"Spoolman",updates:"Updates",language:"Language",languageDescription:"Select your preferred language",theme:"Theme",themeLight:"Light",themeDark:"Dark",themeSystem:"System",defaultView:"Default View",defaultViewDescription:"Page to show when opening the app",checkForUpdates:"Check for Updates",autoUpdate:"Auto Update",currentVersion:"Current Version",latestVersion:"Latest Version",upToDate:"You are up to date",updateAvailable:"Update available",notificationLanguage:"Notification Language",notificationLanguageDescription:"Language for push notifications",bedCooledThreshold:"Bed Cooled Threshold",bedCooledThresholdDescription:"Temperature below which the bed is considered cooled after a print",userNotificationsEnabled:"User Notifications",userNotificationsEnabledDescription:"Enable the user notifications menu and email notifications for print job events. Requires Advanced Authentication.",userNotificationsDisabledHint:"Enable Advanced Authentication to use user notifications.",notificationProviders:"Notification Providers",addProvider:"Add Provider",editProvider:"Edit Provider",providerType:"Provider Type",testNotification:"Test Notification",testSuccess:"Test notification sent successfully",testFailed:"Failed to send test notification",quietHours:"Quiet Hours",quietHoursDescription:"Do not disturb during these hours",quietHoursStart:"Start",quietHoursEnd:"End",events:{title:"Notification Events",printStart:"Print Started",printComplete:"Print Completed",printFailed:"Print Failed",printStopped:"Print Stopped",printProgress:"Progress Milestones",printProgressDescription:"Notify at 25%, 50%, 75%",printerOffline:"Printer Offline",printerError:"Printer Error",filamentLow:"Low Filament",maintenanceDue:"Maintenance Due",maintenanceDueDescription:"Notify when maintenance is needed"},smartPlug:{title:"Smart Plugs",add:"Add Smart Plug",edit:"Edit Smart Plug",name:"Name",ipAddress:"IP Address",linkedPrinter:"Linked Printer",autoOn:"Auto Power On",autoOnDescription:"Turn on when print starts",autoOff:"Auto Power Off",autoOffDescription:"Turn off after print completes",offDelay:"Off Delay",offDelayMinutes:"Minutes after print",offDelayTemp:"When nozzle below temperature",currentState:"Current State",turnOn:"Turn On",turnOff:"Turn Off"},filamentTracking:"Filament Tracking",filamentTrackingDesc:"Choose how to track your filament spools. You can use the built-in inventory or connect an external Spoolman server.",filamentChecks:"Filament checks",disableFilamentWarnings:"Disable filament warnings",disableFilamentWarningsDesc:"Don't show warnings about insufficient filament when printing or queueing",preferLowestFilament:"Prefer lowest remaining filament",preferLowestFilamentDesc:"When multiple spools match, use the one with the least filament remaining",trackingModeBuiltIn:"Built-in Inventory",trackingModeBuiltInDesc:"RFID auto-matching and usage tracking included",trackingModeSpoolmanDesc:"External filament management server",builtInFeatureRfid:"Automatically detects Bambu Lab RFID spools in AMS",builtInFeatureUsage:"Tracks filament consumption per print",builtInFeatureCatalog:"Manage spools, colors, and K-factor profiles",builtInFeatureThirdParty:"Third-party spools can be assigned to inventory spools",amsSyncButton:"Sync Weights from AMS",amsSyncTitle:"Sync Spool Weights from AMS",amsSyncMessage:"This will overwrite all inventory spool weights with the current AMS remain% values from connected printers. Use this to recover from corrupted weight data. Printers must be online.",amsSyncing:"Syncing...",amsSyncSuccess:"{{synced}} spool(s) synced, {{skipped}} skipped",amsSyncError:"Failed to sync weights from AMS",spoolmanUrl:"Spoolman URL",spoolmanUrlHint:"URL of your Spoolman server (e.g., http://localhost:7912)",spoolmanConnected:"Connected",spoolmanDisconnected:"Disconnected",status:"Status",connect:"Connect",disconnect:"Disconnect",howSyncWorks:"How Sync Works",syncInfoRfidOnly:"Only official Bambu Lab spools with RFID are synced",syncInfoAutoCreate:"New spools are auto-created in Spoolman on first sync",syncInfoThirdPartySkipped:"Non-Bambu Lab spools (third-party, refilled) are skipped",linkingExistingSpools:"Linking Existing Spools",linkingExistingSpoolsDesc:'To link existing Spoolman spools to your AMS, hover over an AMS slot and click "Link to Spoolman".',syncMode:"Sync Mode",syncModeAuto:"Automatic",syncModeManual:"Manual Only",syncModeAutoDesc:"AMS data syncs automatically when changes are detected",syncModeManualDesc:"Only sync when manually triggered",syncAmsData:"Sync AMS Data",syncAmsDataDesc:"Manually sync printer AMS data to Spoolman",allPrinters:"All Printers",noDefaultPrinter:"No default (ask each time)",sidebarOrder:"Sidebar order",saveThumbnails:"Save thumbnails",captureFinishPhoto:"Capture finish photo",noPrintersConfigured:"No printers configured",archiveMode:{always:"Always create archive entry",never:"Never create archive entry",ask:"Ask each time"},checkForUpdatesLabel:"Check for updates",checkPrinterFirmware:"Check printer firmware",includeBetaUpdates:"Include beta versions",includeBetaUpdatesDesc:"Notify about beta and prerelease versions when checking for updates",enableRetry:"Enable retry",homeAssistantDescription:"Control smart plugs via Home Assistant",environmentManagedLabel:"(Environment Managed)",autoEnabledViaEnv:"Automatically enabled via environment variables",urlFromEnvReadOnly:"Value set by HA_URL environment variable (read-only)",tokenFromEnvReadOnly:"Value set by HA_TOKEN environment variable (read-only)",mqttConnectedTo:"Connected to",prometheusDescription:"Expose printer data in Prometheus format",noSmartPlugsTitle:"No smart plugs configured",noSmartPlugsDescription:"Add a Tasmota-based smart plug to track energy usage and automate power control.",noProvidersTitle:"No providers configured",noProvidersDescription:"Add a provider to receive alerts.",noTemplatesAvailable:"No templates available. Restart the backend to seed default templates.",apiPermissionView:"View printer status and queue",apiPermissionEdit:"Add and remove items from print queue",apiKeysEmptyTitle:"No API keys",apiKeysEmptyDescription:"Create an API key to integrate with external services.",noUsersFound:"No users found",noGroupsFound:"No groups found",noGroupsAvailable:"No groups available",passwordsDoNotMatch:"Passwords do not match",systemGroupWarning:"System group names cannot be changed",authDisabledTitle:"Authentication is Disabled",authDisabledFeature1:"Require login to access the system",authDisabledFeature2:"Create multiple users with group-based permissions",authDisabledFeature3:"Control access with 50+ granular permissions",userHasCreated:"This user has created:",userItemsQuestion:"What would you like to do with these items?",deleteUserConfirm:"Are you sure you want to delete this user?",actionCannotBeUndone:"This action cannot be undone.",addFirstSmartPlug:"Add Your First Smart Plug",providers:"Providers",log:"Log",testAll:"Test All",testResults:"Test Results",testPassedCount:"{{count}} passed",testFailedCount:"{{count}} failed",messageTemplates:"Message Templates",messageTemplatesDescription:"Customize notification messages for each event.",apiKeys:"API Keys",apiKeysDescription:"Create API keys for external integrations and webhooks.",createKey:"Create Key",apiKeyCreated:"API Key Created Successfully",apiKeyCopyWarning:"Copy this key now - it won't be shown again!",useInApiBrowser:"Use in API Browser",createNewApiKey:"Create New API Key",keyName:"Key Name",keyNamePlaceholder:"e.g., Home Assistant, OctoPrint",readStatus:"Read Status",readStatusDescription:"View printer status and queue",manageQueue:"Manage Queue",manageQueueDescription:"Add and remove items from print queue",controlPrinter:"Control Printer",controlPrinterDescription:"Pause, resume, and stop prints",unnamedKey:"Unnamed Key",lastUsed:"Last used",read:"Read",control:"Control",createFirstKey:"Create Your First Key",webhookEndpoints:"Webhook Endpoints",webhookApiKeyHint:"Use your API key in the X-API-Key header.",webhook:{getAllStatus:"Get all printer status",getSpecificStatus:"Get specific printer status",addToQueue:"Add to print queue",pausePrint:"Pause print",resumePrint:"Resume print",stopPrint:"Stop print"},apiBrowser:"API Browser",apiBrowserDescription:"Explore and test all available API endpoints.",apiKeyForTesting:"API Key for Testing",apiKeyPlaceholder:"Paste your API key here to test authenticated endpoints...",apiKeyHint:"This key will be sent as X-API-Key header with requests.",deleteApiKeyTitle:"Delete API Key",deleteApiKeyMessage:"Are you sure you want to delete this API key? Any integrations using this key will stop working.",deleteKey:"Delete Key",amsDisplayThresholds:"AMS Display Thresholds",amsThresholdsDescription:"Configure color thresholds for AMS humidity and temperature indicators.",humidity:"Humidity",goodGreen:"Good (green)",fairOrange:"Fair (orange)",aboveFairBad:"Above fair threshold shows as red (bad)",fairAlsoDryingThreshold:"This threshold is also used to trigger auto-drying when enabled",temperature:"Temperature",goodBlue:"Good (blue)",aboveFairHot:"Above fair threshold shows as red (hot)",historyRetention:"History Retention",keepSensorHistory:"Keep sensor history for",historyRetentionDescription:"Older humidity and temperature data will be automatically deleted",defaultPrintOptions:"Default Print Options",defaultPrintOptionsDescription:"Set default values for print options when starting new prints. These can be overridden per print in the print dialog.",defaultBedLevelling:"Bed Levelling",defaultBedLevellingDesc:"Auto-level bed before print",defaultFlowCali:"Flow Calibration",defaultFlowCaliDesc:"Calibrate extrusion flow",defaultVibrationCali:"Vibration Calibration",defaultVibrationCaliDesc:"Reduce ringing artifacts",defaultLayerInspect:"First Layer Inspection",defaultLayerInspectDesc:"AI inspection of first layer",defaultTimelapse:"Timelapse",defaultTimelapseDesc:"Record timelapse video",staggeredStart:"Staggered Start",staggeredStartDescription:"Default group size and interval when staggering multi-printer batch starts. Can be overridden per batch in the print modal.",plateClear:"Plate-Clear Confirmation",requirePlateClear:"Require plate-clear confirmation",requirePlateClearDescription:'When enabled, the scheduler waits for per-printer plate-clear confirmation before starting queued prints on printers with finished jobs. Disabling this also hides the plate status badge and the "Mark plate as cleared" button on printer cards.',gcodeInjection:"G-code Injection",gcodeInjectionDescription:'Configure custom G-code to inject at the start and/or end of prints for auto-print systems like Farmloop, SwapMod, AutoClear, and Printflow 3D. Snippets are configured per printer model and applied when "Inject G-code" is enabled on a queue item.',gcodeInjectionNoPrinters:"No printers found. Add printers to configure G-code snippets.",gcodeStartLabel:"Start G-code",gcodeEndLabel:"End G-code",gcodeStartPlaceholder:"G-code prepended before the print starts...",gcodeEndPlaceholder:"G-code appended after the print ends...",staggerGroupSize:"Group size",staggerGroupSizeHelp:"Printers to start simultaneously per group",staggerInterval:"Interval (minutes)",staggerIntervalHelp:"Delay between each group starting",queueDrying:"Queue Auto-Drying",queueDryingDescription:"Automatically dry AMS filament when printer is idle between queued prints. Uses humidity threshold above to trigger drying.",queueDryingEnabled:"Enable auto-drying",queueDryingEnabledDescription:"Start AMS drying automatically when printer is idle and humidity is above threshold",queueDryingBlock:"Wait for drying to complete",queueDryingBlockDescription:"Block the print queue until drying finishes. When off, prints take priority over drying.",ambientDryingEnabled:"Ambient drying",ambientDryingEnabledDescription:"Automatically dry filament on idle printers when humidity exceeds threshold, even without queued prints.",dryingPresets:"Drying Presets",dryingPresetsDescription:"Temperature and duration per filament type. AMS 2 Pro uses lower temps, AMS-HT supports higher temps.",dryingFilament:"Filament",printModal:"Print Modal",expandCustomMapping:"Expand custom mapping by default",expandCustomMappingDescription:"When printing to multiple printers, show per-printer AMS mapping expanded",authentication:"Authentication",authEnabledDescription:"Your instance is secured with user authentication",authDisabledDescription:"Enable to require login and manage user access",authDisabledMessage:"Enable authentication to create user accounts, manage permissions, and secure your Bambuddy instance.",enableAuthentication:"Enable Authentication",currentUser:"Current User",changePassword:"Change Password",admin:"Admin",users:"Users",addUser:"Add User",groups:"Groups",addGroup:"Add Group",system:"System",noDescription:"No description",userCount:"{{count}} users",permissionCount:"{{count}} permissions",createUser:"Create User",username:"Username",enterUsername:"Enter username",password:"Password",enterPassword:"Enter password (min 6 characters)",confirmPassword:"Confirm Password",confirmPasswordPlaceholder:"Confirm password",viewReleaseOnGitHub:"View release on GitHub",turnAllPlugsOn:"Turn all plugs on",turnAllPlugsOff:"Turn all plugs off",clearNotificationLogs:"Clear Notification Logs",clearLogsMessage:"This will permanently delete all notification logs older than 30 days. This action cannot be undone.",clearLogs:"Clear Logs",resetUiPreferences:"Reset UI Preferences",resetUiPreferencesMessage:"This will reset all UI preferences to defaults: sidebar order, theme, dashboard layout, view modes, and sorting preferences. Your printers, archives, and server settings will NOT be affected. The page will reload after clearing.",resetPreferences:"Reset Preferences",deleteGroupTitle:"Delete Group",deleteGroupMessage:"Are you sure you want to delete this group? Users in this group will lose these permissions.",deleteGroup:"Delete Group",disableAuthenticationTitle:"Disable Authentication",disableAuthenticationMessage:"Are you sure you want to disable authentication? This will make your Bambuddy instance accessible without login. All users will remain in the database but authentication will be disabled.",disableAuthentication:"Disable Authentication",configureBambuddy:"Configure Bambuddy",systemDefault:"System Default",archiveSettings:"Archive Settings",newWindow:"New Window",embeddedOverlay:"Embedded Overlay",preferredSlicer:"Preferred Slicer",preferredSlicerDescription:"Choose which slicer application to open files with",externalCameras:"External Cameras",costTracking:"Cost Tracking",printsOnly:"Prints Only",totalConsumption:"Total Consumption",dataManagement:"Data Management",storageUsage:"Storage Usage",storageUsageDescription:"Breakdown of data usage by category",storageUsageTotal:"Total",storageUsageErrors:"Errors",storageUsageOtherBreakdown:"Other (includes static assets, scripts, and configuration files)",storageUsageSystem:"System",storageUsageData:"Data",storageUsageUnavailable:"Storage usage information unavailable",clearNotificationLogsDescription:"Delete notification logs older than 30 days",resetUiPreferencesDescription:"Reset sidebar order, theme, view modes, and layout preferences. Printers, archives, and settings are not affected.",enableHomeAssistant:"Enable Home Assistant",enableMqtt:"Enable MQTT",useTls:"Use TLS",enableMetricsEndpoint:"Enable Metrics Endpoint",availableMetrics:"Available Metrics",editUser:"Edit User",deleteUserTitle:"Delete User",groupName:"Group Name",leaveEmptyForAnonymous:"Leave empty for anonymous",leaveEmptyForNoAuth:"Leave empty for no authentication",enterNewPassword:"Enter new password",confirmNewPassword:"Confirm new password",enterGroupName:"Enter group name",enterDescriptionOptional:"Enter description (optional)",enterCurrentPassword:"Enter current password",enterNewPasswordMin6:"Enter new password (min 6 characters)",toast:{keyCopied:"Key copied to clipboard",copyFailed:"Failed to copy key",keyAddedToBrowser:"Key added to API Browser",clearLogsFailed:"Failed to clear logs",uiPreferencesReset:"UI preferences reset. Refreshing...",authDisabled:"Authentication disabled successfully",authDisableFailed:"Failed to disable authentication",apiKeyCreated:"API key created",apiKeyDeleted:"API key deleted",userCreated:"User created successfully",userUpdated:"User updated successfully",userDeleted:"User deleted successfully",groupCreated:"Group created successfully",groupUpdated:"Group updated successfully",groupDeleted:"Group deleted successfully",fillRequiredFields:"Please fill in all required fields",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 6 characters",enterGroupName:"Please enter a group name",settingsSaved:"Settings saved",cameraSettingsSaved:"Camera settings saved",enterCameraUrl:"Please enter a camera URL",passwordChanged:"Password changed successfully",connectionFailed:"Connection failed",testFailed:"Test failed",cameraConnected:"Camera connected{{resolution}}"},testConnection:"Test Connection",catalog:{spoolCatalog:"Spool Catalog",spoolCatalogDescription:"Empty spool weights by brand/type. Used for automatic weight lookup when adding spools.",searchCatalog:"Search catalog...",addNewEntry:"Add New Entry",namePlaceholder:"Name (e.g., Bambu Lab - Plastic)",weight:"Weight",type:"Type",default:"Default",custom:"Custom",noMatch:"No entries match your search",empty:"No entries in catalog",deleteEntry:"Delete Entry",deleteConfirm:'Are you sure you want to delete "{{name}}"?',resetCatalog:"Reset Catalog",resetConfirm:"Reset catalog to defaults? This will remove all custom entries.",loadFailed:"Failed to load spool catalog",nameWeightRequired:"Name and weight are required",entryAdded:"Entry added",addFailed:"Failed to add entry",entryUpdated:"Entry updated",updateFailed:"Failed to update entry",entryDeleted:"Entry deleted",deleteFailed:"Failed to delete entry",resetSuccess:"Catalog reset to defaults",resetFailed:"Failed to reset catalog",exported:"Exported {{count}} entries",imported:"Imported {{added}} entries ({{skipped}} skipped)",importFailed:"Failed to import: invalid JSON format",exportTooltip:"Export catalog to JSON",importTooltip:"Import catalog from JSON",resetTooltip:"Reset to defaults",selectedCount:"{{count}} selected",deleteSelected:"Delete Selected",bulkDeleteConfirm:"Are you sure you want to delete {{count}} entries?",bulkDeleted:"Deleted {{count}} entries",bulkDeleteFailed:"Failed to delete entries"},colorCatalog:{title:"Color Catalog",description:"Filament colors by manufacturer/material. Used for automatic color lookup when adding spools.",searchColors:"Search colors...",allManufacturers:"All manufacturers",addNewColor:"Add New Color",manufacturer:"Manufacturer",colorName:"Color Name",hex:"Hex",materialOptional:"Material (optional)",showing:"Showing {{filtered}} of {{total}} colors",noMatch:"No colors match your search",empty:"No colors in catalog",deleteColor:"Delete Color",deleteConfirm:'Are you sure you want to delete "{{name}}"?',resetCatalog:"Reset Color Catalog",resetConfirm:"Reset catalog to defaults? This will remove all custom colors.",sync:"Sync",starting:"Starting...",syncTooltip:"Sync from FilamentColors.xyz (2000+ colors, may take a minute)",loadFailed:"Failed to load color catalog",fieldsRequired:"Manufacturer, color name, and hex color are required",colorAdded:"Color added",addFailed:"Failed to add color",colorUpdated:"Color updated",updateFailed:"Failed to update color",colorDeleted:"Color deleted",deleteFailed:"Failed to delete color",resetSuccess:"Color catalog reset to defaults",resetFailed:"Failed to reset catalog",syncUpToDate:"Already up to date ({{count}} colors checked)",syncComplete:"Added {{added}} new colors ({{skipped}} already existed)",syncError:"Sync error",syncFailed:"Failed to sync from FilamentColors.xyz",exported:"Exported {{count}} colors",imported:"Imported {{added}} colors ({{skipped}} skipped)",importFailed:"Failed to import: invalid JSON format",selectedCount:"{{count}} selected",deleteSelected:"Delete Selected",bulkDeleteConfirm:"Are you sure you want to delete {{count}} colors?",bulkDeleted:"Deleted {{count}} colors",bulkDeleteFailed:"Failed to delete colors"},dateFormat:"Date Format",dateFormatUs:"US (MM/DD/YYYY)",dateFormatEu:"EU (DD/MM/YYYY)",dateFormatIso:"ISO (YYYY-MM-DD)",timeFormat:"Time Format",timeFormat12:"12-hour (3:30 PM)",timeFormat24:"24-hour (15:30)",defaultPrinter:"Default Printer",defaultPrinterDescription:"Pre-select this printer for uploads, reprints, and other operations.",slicerBambuStudio:"Bambu Studio",slicerOrcaSlicer:"OrcaSlicer",sidebarOrderDescription:"Drag items in the sidebar to reorder. Reset to default order here.",setDefault:"Set Default",sidebarOrderSetDefaultHint:"Set default applies the current menu order to users who haven't customized theirs.",sidebarDefaultSet:"Default menu order has been set.",sidebarDefaultCleared:"Default menu order cleared.",sidebarDefaultFailed:"Failed to set default menu order.",reset:"Reset",darkMode:"Dark Mode",lightMode:"Light Mode",active:"(active)",background:"Background",accent:"Accent",style:"Style",bgNeutral:"Neutral",bgWarm:"Warm",bgCool:"Cool",bgOled:"OLED Black",bgSlate:"Slate Blue",bgForest:"Forest Green",accentGreen:"Green",accentTeal:"Teal",accentBlue:"Blue",accentOrange:"Orange",accentPurple:"Purple",accentRed:"Red",styleClassic:"Classic",styleGlow:"Glow",styleVibrant:"Vibrant",themeToggleHint:"Toggle between dark and light mode using the sun/moon icon in the sidebar.",autoArchivePrints:"Auto-archive prints",autoArchiveDescription:"Automatically save 3MF files when prints complete",saveThumbnailsDescription:"Extract and save preview images from 3MF files",captureFinishPhotoDescription:"Take a photo from printer camera when print completes",ffmpegNotInstalled:"ffmpeg not installed",ffmpegRequired:"Camera capture requires ffmpeg. Install it via brew install ffmpeg (macOS) or apt install ffmpeg (Linux).",camera:"Camera",cameraViewMode:"Camera View Mode",cameraOverlayDescription:"Camera opens in a resizable overlay on the main screen",cameraWindowDescription:"Camera opens in a separate browser window",externalCamerasDescription:"Configure external cameras to replace the built-in printer camera. Supports MJPEG streams, RTSP, HTTP snapshots, and USB cameras (V4L2). When enabled, the external camera is used for live view and finish photos.",cameraPlaceholderUsb:"Device path (/dev/video0)",cameraPlaceholderUrl:"Camera URL (rtsp://... or http://...)",cameraTypeMjpeg:"MJPEG Stream",cameraTypeRtsp:"RTSP Stream",cameraTypeSnapshot:"HTTP Snapshot",cameraTypeUsb:"USB Camera (V4L2)",cameraRotation:"Rotation",test:"Test",connected:"Connected",disconnected:"Disconnected",currency:"Currency",defaultFilamentCost:"Default filament cost (per kg)",electricityCost:"Electricity cost per kWh",energyDisplayMode:"Energy display mode",energyModePrintDescription:"Dashboard shows sum of energy used during prints",energyModeTotalDescription:"Dashboard shows lifetime energy from smart plugs",fileManager:"File Manager",createArchiveEntry:"Create Archive Entry When Printing",createArchiveEntryDescription:"When printing from File Manager, optionally create an archive entry",lowDiskSpaceWarning:"Low Disk Space Warning",lowDiskSpaceDescription:"Show warning when free disk space falls below this threshold",printerFirmware:"Printer Firmware",checkFirmwareDescription:"Check for printer firmware updates from Bambu Lab",bambuddySoftware:"Bambuddy Software",autoCheckDescription:"Automatically check for new versions on startup",checkNow:"Check now",updateAvailableVersion:"Update available: v{{version}}",releaseNotes:"Release Notes",updateViaDocker:"Update via Docker Compose:",installUpdate:"Install Update",latestVersionRunning:"You're running the latest version",failedToCheckUpdates:"Failed to check for updates: {{error}}",backupRestore:"Backup & Restore",backupRestoreDescription:"Export/import settings and configure GitHub backup",goToBackup:"Go to Backup",externalUrl:"External URL",externalUrlDescription:"The external URL where Bambuddy is accessible. Used for notification images and external integrations.",bambuddyUrl:"Bambuddy URL",externalUrlHint:"Include protocol and port (e.g., http://192.168.1.100:8000)",ftpRetry:"FTP Retry",ftpRetryDescription:"Retry FTP operations when printer WiFi is unreliable. Applies to 3MF downloads, print uploads, timelapse downloads, and firmware updates.",autoRetryDescription:"Automatically retry failed FTP operations",retryAttempts:"Retry attempts",retryDelay:"Retry delay",connectionTimeout:"Connection timeout",time_one:"{{count}} time",time_other:"{{count}} times",second_one:"{{count}} second",second_other:"{{count}} seconds",nSeconds:"{{count}} seconds",increaseForWeakWifi:"Increase for printers with weak WiFi",homeAssistant:"Home Assistant",homeAssistantFullDescription:"Connect to Home Assistant to control smart plugs via HA's REST API. Supports switch, light, input_boolean, and script entities.",homeAssistantUrl:"Home Assistant URL",longLivedAccessToken:"Long-Lived Access Token",haTokenHint:"Create a token in HA: Profile → Long-Lived Access Tokens → Create Token",connectionSuccessful:"Connection Successful",connectionFailed:"Connection Failed",haConnectionSuccess:"Successfully connected to Home Assistant.",haConnectionFailed:"Failed to connect to Home Assistant.",mqttPublishing:"MQTT Publishing",mqttDescription:"Publish BamBuddy events to an external MQTT broker for integration with Node-RED, Home Assistant, and other automation systems.",mqttEnableDescription:"Publish events to external MQTT broker",brokerHostname:"Broker hostname",port:"Port",usernameOptional:"Username (optional)",passwordOptional:"Password (optional)",topicPrefix:"Topic prefix",topicPrefixHint:"Topics will be: {{prefix}}/printers//status, etc.",prometheusMetrics:"Prometheus Metrics",prometheusEndpointDescription:"Expose printer metrics at /api/v1/metrics for Prometheus/Grafana monitoring.",bearerTokenOptional:"Bearer Token (optional)",bearerTokenHint:"If set, requests must include Authorization: Bearer ",metricsConnectionStatus:"Connection status",metricsPrinterState:"Printer state (idle/printing/etc)",metricsPrintProgress:"Print progress 0-100%",metricsBedTemp:"Bed temperature",metricsNozzleTemp:"Nozzle temperature",metricsPrintsTotal:"Total prints by result",metricsMore:"...and more (layers, fans, queue, filament usage)",smartPlugsDescription:"Connect smart plugs (Tasmota or Home Assistant) to automate power control and track energy usage for your printers.",allOn:"All On",allOff:"All Off",addSmartPlug:"Add Smart Plug",energySummary:"Energy Summary",currentPower:"Current Power",plugsOnline:"{{reachable}}/{{total}} plugs online",today:"Today",yesterday:"Yesterday",total:"Total",enablePlugsForSummary:"Enable plugs to see energy summary",addNotificationProvider:"Add",systemBadge:"(System)",creating:"Creating...",changing:"Changing...",deleteUserAndItems:"Delete user AND their items",deleteUserKeepItems:"Delete user, keep items (become ownerless)",ok:"OK",twoFa:{totpTitle:"Authenticator App (TOTP)",totpDesc:"Use an authenticator app like Google Authenticator, Aegis or Authy.",emailOtpTitle:"Email OTP",emailOtpDesc:"Send a one-time code to {{email}} when you log in.",emailOtpNoEmail:"Add an email address to your account to enable this method.",addEmailFirst:"Your account has no email address. Ask an admin to add one before enabling Email OTP.",setupTotp:"Set up Authenticator App",setupAuthApp:"Set up Authenticator App",setupInstructions:"Scan the QR code below with your authenticator app, then confirm with a code.",manualEntry:"Can't scan? Enter this secret manually:",scannedContinue:"I've scanned the code — continue",enterCodeToConfirm:"Enter the 6-digit code from your authenticator app to confirm setup.",activate:"Activate",disableTotp:"Disable Authenticator",disableConfirmHint:"Enter a valid TOTP code or a backup code to disable the authenticator.",totpDisabled:"Authenticator app disabled.",emailOtpEnabled:"Email OTP enabled.",emailOtpDisabled:"Email OTP disabled.",smtpRequired:"Please configure and test SMTP settings first.",invalidCode:"Invalid code. Please try again.",enableEmailOtp:"Enable Email OTP",disableEmailOtp:"Disable Email OTP",emailSetupEnterCode:"A verification code has been sent to your email address. Enter it below to confirm you own this inbox.",verifyAndEnable:"Verify & Enable",emailDisablePasswordHint:"Enter your account password to confirm disabling email OTP.",passwordPlaceholder:"Enter your password",backupCodesTitle:"Save your backup codes",backupCodesWarning:"Save these codes somewhere safe. Each code can only be used once and they will not be shown again.",backupCodesRemaining:"{{count}} backup codes remaining",savedCodes:"I've saved my codes",regenBackup:"Regenerate Backup Codes",regenBackupHint:"Enter your current TOTP code to generate 10 new backup codes. All existing backup codes will be invalidated.",newBackupCodes:"New backup codes",linkedAccounts:"Linked SSO Accounts",linkedAccountsDesc:"These external identity providers are linked to your account.",oidcUnlinked:"Account unlinked."},oidc:{title:"SSO / OIDC Providers",desc:"Configure OpenID Connect providers to allow single sign-on via external identity providers.",addProvider:"Add Provider",newProvider:"New Provider",empty:"No OIDC providers configured yet.",created:"Provider created.",updated:"Provider updated.",deleted:"Provider deleted.",deleteTitle:"Delete Provider",deleteMessage:'Delete "{{name}}"? All linked user accounts will be disconnected.',form:{name:"Display Name",issuerUrl:"Issuer URL",clientId:"Client ID",clientSecret:"Client Secret",scopes:"Scopes",iconUrl:"Icon URL (optional)",enabled:"Enabled",autoCreate:"Auto-create users",autoCreateDesc:"Automatically create a local account on first login.",autoLink:"Auto-link existing accounts",autoLinkDesc:"Link existing local accounts by matching email on first login.",secretHint:"leave blank to keep current",secretPlaceholder:"new secret"}}},notification:{printStarted:{title:"Print Started",body:"{{printer}}: {{filename}} has started printing"},printCompleted:{title:"Print Completed",body:"{{printer}}: {{filename}} completed successfully"},printFailed:{title:"Print Failed",body:"{{printer}}: {{filename}} has failed"},printStopped:{title:"Print Stopped",body:"{{printer}}: {{filename}} was stopped"},printProgress:{title:"Print Progress",body:"{{printer}}: {{filename}} is {{percent}}% complete"},printerOffline:{title:"Printer Offline",body:"{{printer}} is offline"},printerError:{title:"Printer Error",body:"{{printer}}: {{error}}"},filamentLow:{title:"Low Filament",body:"{{printer}}: Filament is running low"},maintenanceDue:{title:"Maintenance Due",body:"{{printer}}: {{items}} need attention"}},errors:{generic:"Something went wrong",networkError:"Network error. Please check your connection.",notFound:"Not found",unauthorized:"Unauthorized",serverError:"Server error",validationError:"Please check your input",printerConnectionFailed:"Failed to connect to printer",saveFailed:"Failed to save changes",deleteFailed:"Failed to delete",loadFailed:"Failed to load data"},hmsErrors:{title:"Errors - {{name}}",noErrors:"No errors",viewOnWiki:"View on Bambu Lab Wiki",clearInstructions:"Clear errors on the printer to dismiss them here.",clearErrors:"Clear Errors",clearSuccess:"HMS errors cleared",clearFailed:"Failed to clear HMS errors"},mqttDebug:{title:"MQTT Debug Log",searchPlaceholder:"Search topic or payload...",noMessages:"No messages logged yet",startLoggingHint:'Click "Start Logging" to begin capturing MQTT messages',noMessagesMatch:"No messages match your filter",adjustFilterHint:"Try adjusting your search or filter criteria",incoming:"Incoming",outgoing:"Outgoing",loggingStopped:"Logging stopped",loggingActive:"Logging active - messages will auto-refresh",startLogging:"Start Logging",stopLogging:"Stop Logging",clearLog:"Clear Log",topic:"Topic",timestamp:"Timestamp",direction:"Direction",all:"All"},printerFiles:{title:"File Manager",storageUsed:"Used:",storageFree:"Free:",filterPlaceholder:"Filter files...",deleteButton:"Delete",deleteFiles:"Delete {{count}} Files",deleteFileConfirm:'Delete "{{name}}"? This cannot be undone.',deleteFilesConfirm:"Delete {{count}} selected files? This cannot be undone.",noFiles:"No files on printer",loadingFiles:"Loading files...",failedToLoad:"Failed to load files",toast:{filesDeleted:"Deleted {{count}} file(s)",deleteFailed:"Delete failed: {{error}}"}},confirm:{delete:"Are you sure you want to delete this?",unsavedChanges:"You have unsaved changes. Are you sure you want to leave?",clearQueue:"Are you sure you want to clear the queue?"},login:{title:"Bambuddy Login",subtitle:"Sign in to your account",username:"Username",usernamePlaceholder:"Enter your username",usernameOrEmail:"Username or Email",usernameOrEmailPlaceholder:"Username or @ Email",password:"Password",passwordPlaceholder:"Enter your password",signIn:"Sign in",signingIn:"Logging in...",forgotPassword:"Forgot your password?",loginSuccess:"Logged in successfully",loginFailed:"Login failed",enterCredentials:"Please enter username and password",enterEmail:"Please enter your email address",oidcLoginFailed:"OIDC login failed",oidcErrors:{providerError:"The identity provider returned an error",missingParameters:"OIDC callback is missing required parameters",invalidState:"OIDC state is invalid or has already been used",stateExpired:"OIDC login session expired — please try again",providerNotFound:"OIDC provider not found",discoveryFailed:"Failed to fetch OIDC discovery document",invalidDiscovery:"OIDC discovery document is invalid",networkError:"Network error during OIDC token exchange",badResponse:"Unexpected response during OIDC token exchange",noIdToken:"OIDC provider did not return an ID token",validationFailed:"OIDC token validation failed",nonceMismatch:"OIDC nonce mismatch — possible replay attack",missingSubClaim:"OIDC token is missing the sub claim",noLinkedAccount:"No local account is linked to this OIDC identity",accountInactive:"Your account is inactive",userResolutionFailed:"Failed to resolve your account",internalError:"An internal error occurred during OIDC login",tokenExchangeFailed:"OIDC token exchange failed"},forgotPasswordTitle:"Forgot Password",forgotPasswordMessage:"If you've forgotten your password, please contact your system administrator to reset it.",forgotPasswordEmailMessage:"Enter your email address and we'll send you a new password.",emailAddress:"Email Address",emailPlaceholder:"your.email@example.com",cancel:"Cancel",sending:"Sending...",sendResetEmail:"Send Reset Email",howToReset:"How to reset your password:",resetStep1:"Contact your Bambuddy administrator",resetStep2:"Ask them to reset your password in User Management",resetStep3:"They can set a new temporary password for you",resetStep4:"Log in with the new password and change it in Settings",gotIt:"Got it",resetPassword:{title:"Set New Password",subtitle:"Enter and confirm your new password below.",newPassword:"New Password",newPasswordPlaceholder:"At least 8 characters",confirmPassword:"Confirm Password",confirmPasswordPlaceholder:"Repeat new password",saving:"Saving…",submit:"Set New Password",backToLogin:"Back to login",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 8 characters",resetFailed:"Password reset failed. The link may have expired."},twoFA:{title:"Two-Factor Authentication",subtitle:"Your account is protected with 2FA. Enter the verification code below.",methodAuthenticator:"Authenticator App",methodEmail:"Email Code",methodBackup:"Backup Code",instructionsTotp:"Open your authenticator app and enter the 6-digit code for Bambuddy.",instructionsEmail:"A 6-digit code has been sent to your email address. It expires in 10 minutes.",instructionsEmailNotSent:"Click the button below to receive a verification code via email.",instructionsBackup:"Enter one of your 8-character backup recovery codes. Each code can only be used once.",sendCodeButton:"Send Code via Email",sendingCode:"Sending...",resendCode:"Resend code",codeLabel:"Verification Code",backupCodeLabel:"Backup Code",codePlaceholder:"000000",backupCodePlaceholder:"XXXXXXXX",verifyButton:"Verify",verifyingButton:"Verifying...",backToLogin:"← Back to login",orContinueWith:"or continue with",signInWith:"Sign in with {{provider}}",enterCode:"Please enter the verification code",sendCodeFailed:"Failed to send verification code",invalidCode:"Invalid code. Please try again."}},setup:{title:"Bambuddy Setup",subtitle:"Configure authentication for your Bambuddy instance",enableAuth:"Enable Authentication",adminAccount:"Admin Account",adminAccountDesc:"If admin users already exist, authentication will be enabled using the existing admin accounts. Leave the fields below empty to use existing admins, or enter new credentials to create a new admin user.",adminUsername:"Admin Username",adminPassword:"Admin Password",optionalIfAdminExists:"(optional if admin users exist)",adminUsernamePlaceholder:"Enter admin username (optional)",adminPasswordPlaceholder:"Enter admin password (optional)",confirmPassword:"Confirm Password",confirmPasswordPlaceholder:"Confirm admin password",settingUp:"Setting up...",completeSetup:"Complete Setup",toast:{authEnabledAdminCreated:"Authentication enabled and admin user created",authEnabledExistingAdmins:"Authentication enabled using existing admin users",setupCompleted:"Setup completed",enterBothCredentials:"Please enter both admin username and password, or leave both empty to use existing admin users",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 6 characters"}},changePassword:{title:"Change Password",currentPassword:"Current Password",currentPasswordPlaceholder:"Enter current password",newPassword:"New Password",newPasswordPlaceholder:"Enter new password (min 6 characters)",confirmPassword:"Confirm New Password",confirmPasswordPlaceholder:"Confirm new password",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 6 characters",changing:"Changing...",success:"Password changed successfully",failed:"Failed to change password"},plateAlert:{title:"Print Paused!",message:"Objects detected on build plate. The print has been automatically paused. Please clear the plate and resume the print.",understand:"I Understand"},camera:{title:"Camera View",invalidPrinterId:"Invalid printer ID",live:"Live",snapshot:"Snapshot",restartStream:"Restart stream",refreshSnapshot:"Refresh snapshot",fullscreen:"Fullscreen",exitFullscreen:"Exit fullscreen",connectingToCamera:"Connecting to camera...",capturingSnapshot:"Capturing snapshot...",connectionLost:"Connection lost",connectionFailed:"Camera connection failed",reconnecting:"Reconnecting in {{countdown}}s... (attempt {{attempt}}/{{max}})",reconnectNow:"Reconnect now",cameraUnavailable:"Camera unavailable",cameraUnavailableDesc:"Make sure the printer is powered on and connected.",noCamera:"No camera available",retry:"Retry",cameraStream:"Camera stream",zoomOut:"Zoom out",zoomIn:"Zoom in",resetZoom:"Reset zoom",recording:"Recording",startRecording:"Start Recording",stopRecording:"Stop Recording",chamberLight:"Toggle chamber light"},groups:{title:"Group Management",subtitle:"Manage permission groups for access control",backToSettings:"Back to Settings",createGroup:"Create Group",noPermission:"You do not have permission to access this page.",system:"System",noDescription:"No description",usersCount:"{{count}} users",permissionsCount:"{{count}} permissions",edit:"Edit",delete:"Delete",toast:{created:"Group created successfully",updated:"Group updated successfully",deleted:"Group deleted successfully",enterGroupName:"Please enter a group name"},modal:{editGroup:"Edit Group",createGroup:"Create Group",cancel:"Cancel",saving:"Saving...",creating:"Creating...",saveChanges:"Save Changes"},form:{groupName:"Group Name",groupNamePlaceholder:"Enter group name",systemGroupWarning:"System group names cannot be changed",description:"Description",descriptionPlaceholder:"Enter description (optional)",permissions:"Permissions ({{count}} selected)"},deleteModal:{title:"Delete Group",message:"Are you sure you want to delete this group? Users in this group will lose these permissions.",confirm:"Delete Group"},editor:{title:"Edit Group",createTitle:"Create Group",search:"Search permissions...",selectAll:"Select All",clearAll:"Clear All",permissionsSelected:"{{count}} selected",noResults:"No permissions match your search"}},users:{title:"User Management",subtitle:"Manage users and their access to your Bambuddy instance",backToSettings:"Back to Settings",createUser:"Create User",noPermission:"You do not have permission to access this page.",admin:"Admin",noGroups:"No groups",active:"Active",inactive:"Inactive",edit:"Edit",delete:"Delete",system:"System",noGroupsAvailable:"No groups available",table:{username:"Username",groups:"Groups",status:"Status",actions:"Actions"},toast:{created:"User created successfully",updated:"User updated successfully",deleted:"User deleted successfully",fillRequired:"Please fill in all required fields",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 6 characters"},modal:{createUser:"Create User",editUser:"Edit User",cancel:"Cancel",creating:"Creating...",saving:"Saving...",saveChanges:"Save Changes",advancedAuthSubtitle:"with Advanced Authentication"},form:{username:"Username",usernamePlaceholder:"Enter username",email:"Email",emailPlaceholder:"user@example.com",password:"Password",passwordPlaceholder:"Enter password",confirmPassword:"Confirm Password",confirmPasswordPlaceholder:"Confirm password",newPasswordPlaceholder:"Enter new password",confirmNewPasswordPlaceholder:"Confirm new password",leaveBlankToKeep:"leave blank to keep current",groups:"Groups",optional:"optional",autoGeneratedPassword:"A secure password will be automatically generated and emailed to the user.",passwordManagedByAdvancedAuth:'Password is managed by Advanced Authentication. Use "Reset Password" to send a new password to the user via email.',resetPassword:"Reset Password",resettingPassword:"Resetting Password..."},deleteModal:{title:"Delete User",message:"Are you sure you want to delete this user? This action cannot be undone.",confirm:"Delete User"}},streamOverlay:{title:"Stream Overlay",invalidPrinterId:"Invalid printer ID",cameraStream:"Camera stream",progress:"Progress",eta:"ETA",printerIdle:"Printer is idle",printerOffline:"Printer offline",status:{printing:"Printing",paused:"Paused",finished:"Finished",failed:"Failed",idle:"Idle",unknown:"Unknown"}},profiles:{title:"Profiles",subtitle:"Manage your slicer presets and pressure advance calibrations",tabs:{cloud:"Cloud Profiles",local:"Local Profiles",kprofiles:"K-Profiles"},localProfiles:{title:"Local Profiles",subtitle:"Import and manage slicer presets from OrcaSlicer",import:"Import Profiles",importDesc:"Drop .bbscfg, .bbsflmt, .orca_filament, .zip, or .json files here",importing:"Importing...",search:"Search local presets...",noPresets:"No local presets yet",badge:"Local",edit:"Edit",delete:"Delete",cancel:"Cancel",deleteConfirmTitle:"Delete Preset",deleteConfirm:"Are you sure you want to delete this preset? This cannot be undone.",source:"Source",inheritsFrom:"Inherits",filamentType:"Type",vendor:"Vendor",compatiblePrinters:"Printers",nozzleTemp:"Nozzle Temp",cost:"Cost",density:"Density",pressureAdvance:"Pressure Advance",filament:"Filament",process:"Process",printer:"Printer",toast:{importSuccess:"{{count}} preset(s) imported",importSkipped:"{{count}} preset(s) skipped (duplicates)",importError:"{{count}} error(s) during import",deleted:"Preset deleted",updated:"Preset updated"}},connectedAs:"Connected as",logout:"Logout",noLogoutPermission:"You do not have permission to logout",failedToLoad:"Failed to load profiles",retry:"Retry",time:{justNow:"Just now",minsAgo:"{{count}}m ago",hoursAgo:"{{count}}h ago",daysAgo:"{{count}}d ago"},toast:{loggedOut:"Logged out"},login:{title:"Connect to Bambu Cloud",subtitle:"Sync your slicer presets across devices",email:"Email",password:"Password",region:"Region",regionGlobal:"Global",regionChina:"China",verificationCode:"Verification Code",totpCode:"Authenticator Code",checkEmail:"Check your email ({{email}}) for a 6-digit code",enterTotpHint:"Enter the 6-digit code from your authenticator app",accessToken:"Access Token",accessTokenHint:"Paste your Bambu Lab access token (from Bambu Studio)",back:"Back",loginButton:"Login",verifyButton:"Verify",setTokenButton:"Set Token",useToken:"Use access token instead",useEmail:"Login with email instead",toast:{loggedIn:"Logged in successfully",codeSent:"Verification code sent to your email",enterTotp:"Enter code from your authenticator app",tokenSet:"Token set successfully"}},presets:{myPreset:"My preset (editable)",duplicate:"Duplicate",editable:"Editable",failedToLoadDetails:"Failed to load preset details",deleteConfirm:"Delete this preset?",deleteWarning:'This will permanently delete "{{name}}" from Bambu Cloud. This cannot be undone.',noDuplicatePermission:"You do not have permission to duplicate presets",noEditPermission:"You do not have permission to edit presets",noDeletePermission:"You do not have permission to delete presets",types:{filament:"Filament preset",printer:"Printer preset",process:"Process preset"},toast:{deleted:"Preset deleted",created:"Preset created",updated:"Preset updated",duplicated:"Preset duplicated",fieldAdded:'Field "{{key}}" added',exported:"Preset exported"},baseLabel:"Base: {{name}}",currentLabel:"Current: {{name}}",newPreset:"New Preset",editPreset:"Edit Preset",duplicatePreset:"Duplicate Preset",createNewPreset:"Create New Preset",customizeSettings:"Customize settings for your new preset",compareWithBase:"Compare with base preset",compare:"Compare",basePreset:"Base Preset",selectBasePreset:"Select base preset...",presetName:"Preset Name",myCustomPreset:"My custom preset",inheritsFrom:"Inherits from",dropJsonToImport:"Drop JSON to import",tabs:{common:"Common",allFields:"All Fields"},availableFields:"Available Fields",searchFieldsPlaceholder:"Search fields...",noMatchingFields:"No matching fields",allFieldsAdded:"All fields added",addCustomField:"Add custom field",yourOverrides:"Your Overrides",noOverridesYet:"No overrides yet",clickFieldsToAdd:"Click fields on the left to add them",saveAsTemplate:"Save as template",jsonTip:"Tip: Drag & drop a .json file anywhere on this modal to import settings"},cloudView:{searchPlaceholder:"Search presets...",templates:"Templates",refresh:"Refresh",newPreset:"New Preset",clearFilters:"Clear filters",compareMode:"Compare Mode",selectAnotherPreset:"Select another {{type}} preset",clickTwoPresets:"Click two presets of the same type to compare",selectFirst:"1. Select first",selectSecond:"2. Select second",compareNow:"Compare Now",lastSynced:"Last synced:",showingCount:"Showing {{showing}} of {{total}} presets",noPresetsFound:"No presets found",columns:{filament:"Filament",process:"Process",printer:"Printer"},noFilamentPresets:"No filament presets",noProcessPresets:"No process presets",noPrinterPresets:"No printer presets",filters:{type:"Type",owner:"Owner",printer:"Printer",nozzle:"Nozzle",filament:"Filament",layer:"Layer",all:"All",myPresets:"My Presets",builtIn:"Built-in",process:"Process"},noTemplatesPermission:"You do not have permission to manage templates",noRefreshPermission:"You do not have permission to refresh profiles",noCreatePermission:"You do not have permission to create presets"},templates:{title:"Quick Templates",noTemplates:"No templates yet",createFirst:"Create templates from the preset editor",typeFilter:"Type:",deleteTitle:"Delete Template",deleteWarning:"This action cannot be undone",deleteConfirm:'Are you sure you want to delete "{{name}}"?',namePlaceholder:"Template name",descriptionPlaceholder:"Description",settingsJson:"Settings (JSON)",fieldsCount:"{{count}} fields",shownInModals:"Shown in modals",hiddenInModals:"Hidden in modals",apply:"Apply",toast:{deleted:"Template deleted",updated:"Template updated",created:"Template created",applied:"Template applied"}}},support:{debugLoggingActive:"Debug logging is active",manageLogs:"Manage",collectItem7:"Printer connectivity and firmware versions",collectItem8:"Integration status (Spoolman, MQTT, HA)",collectItem9:"Network interfaces (subnets only)",collectItem10:"Python package versions",collectItem11:"Database health checks",collectItem12:"Docker environment details"},fileManager:{title:"File Manager",subtitle:"Organize and manage your print files",uploadFiles:"Upload Files",newFolder:"New Folder",folderName:"Folder Name",folderNamePlaceholder:"e.g., Functional Parts",renameFile:"Rename File",renameFolder:"Rename Folder",moveFiles:"Move {{count}} File(s)",rootNoFolder:"Root (No Folder)",current:"current",linkFolder:"Link Folder",linkFolderDescription:'Link "{{name}}" to a project or archive for quick access.',project:"Project",archive:"Archive",noProjectsFound:"No projects found",noArchivesFound:"No archives found",unlink:"Unlink",link:"Link",dragDropFiles:"Drag & drop files here",dropFilesHere:"Drop files here",orClickToBrowse:"or click to browse",allFileTypesSupported:"All file types supported. ZIP files will be extracted.",zipFilesDetected:"ZIP files detected",zipExtractOptions:"ZIP files will be extracted. Choose how to handle folder structure:",preserveZipStructure:"Preserve folder structure from ZIP",createFolderFromZip:"Create folder from ZIP filename",stlThumbnailGeneration:"STL thumbnail generation",zipMayContainStl:"ZIP files may contain STL files. Thumbnails can be generated during extraction.",thumbnailsCanBeGenerated:"Thumbnails can be generated for STL files. Large models may take longer to process.",generateThumbnailsForStl:"Generate thumbnails for STL files",threemfDetected:"3MF files detected",threemfExtractionInfo:"Printer model, material, color, and print settings will be automatically extracted from 3MF files.",willBeExtracted:"Will be extracted",filesExtracted:"{{count}} files extracted",uploadComplete:"Upload complete: {{succeeded}} succeeded",uploadFailed:"Upload failed",zipFilesFailed:"{{count}} files failed",uploading:"Uploading...",changeLink:"Change Link...",linkTo:"Link to...",linkToProjectOrArchive:"Link to project or archive",addToQueue:"Add to Queue",schedulePrint:"Schedule",generateThumbnail:"Generate Thumbnail",generateThumbnails:"Generate Thumbnails",generateThumbnailsForMissing:"Generate thumbnails for STL files missing them",gridView:"Grid view",listView:"List view",lowDiskSpaceWarning:"Low disk space warning",lowDiskSpaceDetails:"Only {{free}} free of {{total}} total. Threshold is set to {{threshold}} GB in settings.",files:"Files",folders:"Folders",size:"Size",free:"Free",allFiles:"All Files",wrap:"Wrap",enableTextWrapping:"Enable text wrapping",disableTextWrapping:"Disable text wrapping",collapse:"Collapse",collapseFoldersByDefault:"Collapse folders by default",expandFoldersByDefault:"Expand folders by default",dragToResizeTooltip:"Drag to resize, double-click to reset",searchFiles:"Search files...",allTypes:"All types",prints:"Prints",ascending:"Ascending",descending:"Descending",resultsCount:"{{showing}} of {{total}} files",selectAll:"Select All",deselectAll:"Deselect All",selected:"{{count}} selected",adding:"Adding...",loadingFiles:"Loading files...",folderIsEmpty:"Folder is empty",noFilesYet:"No files yet",folderEmptyDescription:"Upload files or move files into this folder to get started.",noFilesDescription:"Upload files to start organizing your print-related files.",noMatchingFiles:"No matching files",noMatchingFilesDescription:"No files match your current search or filter criteria.",clearFilters:"Clear filters",printedCount:"Printed {{count}}x",uploadedBy:"Uploaded By",deleteFolder:"Delete Folder",deleteFile:"Delete File",deleteFilesCount:"Delete {{count}} Files",deleteFolderConfirm:"Are you sure you want to delete this folder? All files inside will also be deleted.",deleteFileConfirm:"Are you sure you want to delete this file?",deleteFilesConfirm:"Are you sure you want to delete {{count}} selected files? This action cannot be undone.",deleting:"Deleting...",noPermissionRenameFolder:"You do not have permission to rename folders",noPermissionLinkFolder:"You do not have permission to link folders",noPermissionDeleteFolder:"You do not have permission to delete folders",noPermissionPrint:"You do not have permission to print",noPermissionAddToQueue:"You do not have permission to add to queue",noPermissionDownload:"You do not have permission to download files",noPermissionRenameFile:"You do not have permission to rename this file",noPermissionGenerateThumbnail:"You do not have permission to generate thumbnails",noPermissionDeleteFile:"You do not have permission to delete this file",noPermissionCreateFolder:"You do not have permission to create folders",noPermissionUpload:"You do not have permission to upload files",noPermissionMoveFiles:"You do not have permission to move files",noPermissionDeleteFiles:"You do not have permission to delete files",linkExternal:"Link External",linkExternalFolder:"Link External Folder",linkExternalFolderDescription:"Mount a host directory (NAS, USB, network share) into the File Manager. Files are not copied — they are accessed directly from the original path.",externalFolderNamePlaceholder:"e.g., NAS Prints",externalPath:"Host Path",externalPathHelp:"Absolute path to the directory on the Docker host. Must be bind-mounted into the container.",readOnly:"Read Only",readOnlyHelp:"prevents uploads and deletions",showHiddenFiles:"Show hidden files (dotfiles)",externalFolder:"External Folder",scanFolder:"Scan",toast:{folderCreated:"Folder created",folderDeleted:"Folder deleted",fileDeleted:"File deleted",filesDeleted:"Deleted {{count}} files",filesMoved:"Files moved",folderLinked:"Folder linked",folderUnlinked:"Folder unlinked",externalFolderLinked:"External folder linked and scanned",folderScanned:"Scan complete: {{added}} added, {{removed}} removed",addedToQueue:"Added {{count}} file(s) to queue",addedToQueuePartial:"Added {{added}} file(s), {{failed}} failed",failedToAddToQueue:"Failed to add files: {{error}}",fileRenamed:"File renamed",folderRenamed:"Folder renamed",thumbnailsGenerated:"Generated {{count}} thumbnail(s)",thumbnailsGeneratedPartial:"Generated {{succeeded}} thumbnail(s), {{failed}} failed",noStlMissingThumbnails:"No STL files missing thumbnails",failedToGenerateThumbnails:"Failed to generate thumbnails: {{error}}",thumbnailGenerated:"Thumbnail generated",failedToGenerateThumbnail:"Failed to generate thumbnail: {{error}}"}},projects:{title:"Projects",subtitle:"Organize and track your 3D printing projects",newProject:"New Project",editProject:"Edit Project",deleteProject:"Delete Project",projectName:"Project Name",description:"Description",noProjects:"No projects yet",noProjectsFiltered:"No {{status}} projects",noProjectsFilteredHelp:"You don't have any {{status}} projects. Projects will appear here when their status changes.",createFirst:"Create your first project to start organizing related prints, tracking progress, and managing your builds.",createFirstButton:"Create Your First Project",create:"Create",files:"Files",prints:"Prints",plates:"plates",parts:"parts",lastModified:"Last Modified",deleteConfirm:"Are you sure you want to delete this project? Archives and queue items will be unlinked but not deleted.",addFiles:"Add Files",removeFile:"Remove File",viewDetails:"View Details",namePlaceholder:"e.g., Voron 2.4 Build",descriptionPlaceholder:"Optional description...",color:"Color",targetPlates:"Target Plates",targetPlatesPlaceholder:"e.g., 25",targetPlatesHelp:"Number of print jobs",targetParts:"Target Parts",targetPartsPlaceholder:"e.g., 150",targetPartsHelp:"Total objects needed",tagsLabel:"Tags (comma-separated)",tagsPlaceholder:"e.g., voron, functional, gift",dueDate:"Due Date",priority:"Priority",priorityLow:"Low",priorityNormal:"Normal",priorityHigh:"High",priorityUrgent:"Urgent",statusActive:"Active",statusCompleted:"Completed",statusArchived:"Archived",done:"Done",completed:"completed",failed:"failed",inQueue:"in queue",noPrintsYet:"No prints yet",printJobs:"Print jobs (plates)",partsPrinted:"Parts printed",failedParts:"Failed parts",import:"Import",export:"Export",importProject:"Import project",exportAll:"Export all projects",loading:"Loading projects...",noEditPermission:"You do not have permission to edit projects",noDeletePermission:"You do not have permission to delete projects",noCreatePermission:"You do not have permission to create projects",noImportPermission:"You do not have permission to import projects",noExportPermission:"You do not have permission to export projects",toast:{created:"Project created",updated:"Project updated",deleted:"Project deleted",imported:"Project imported",multipleImported:"{{count}} projects imported",importFailed:"Import failed",exported:"Projects exported (metadata only)"}},projectDetail:{notFound:"Project not found",backToProjects:"Back to Projects",export:"Export",exportProject:"Export project",noExportPermission:"You do not have permission to export projects",noEditPermission:"You do not have permission to edit projects",partOf:"Part of:",priorityLabel:"Priority:",noPrints:"No prints in this project yet",status:{active:"Active",completed:"Completed",archived:"Archived"},priority:{low:"Low",normal:"Normal",high:"High",urgent:"Urgent"},dueDate:{overdue:"Overdue",today:"Due today",daysLeft:"{{count}} days left"},progress:{platesProgress:"Plates Progress",partsProgress:"Parts Progress",printJobs:"print jobs",parts:"parts",percentComplete:"{{percent}}% complete",remaining:"{{count}} remaining"},stats:{printJobs:"Print Jobs",total:"total",failed:"{{count}} failed",partsPrinted:"{{count}} parts printed",printTime:"Print Time",filamentUsed:"Filament Used"},cost:{title:"Cost Tracking",filamentCost:"Filament Cost",energy:"Energy",totalCost:"Total Cost",total:"Total",includesBom:"incl. BOM",budget:"Budget",remaining:"Remaining"},subProjects:{title:"Sub-projects ({{count}})"},notes:{title:"Notes",noEditPermission:"You do not have permission to edit notes",placeholder:"Add notes about this project...",empty:"No notes yet. Click Edit to add notes."},files:{title:"Files",linkFolders:"Link folders from the File Manager",forQuickAccess:"to this project for quick access.",fileCount:"{{count}} file(s)",empty:"No folders linked. Go to File Manager and link a folder to this project.",noFiles:"No files in this folder.",print:"Print Now",addToQueue:"Add to Queue"},bom:{title:"Bill of Materials",acquired:"{{completed}}/{{total}} acquired",showAll:"Show all",hideDone:"Hide done",addPart:"Add Part",noAddPermission:"You do not have permission to add parts",partNamePlaceholder:"Part name (e.g., M3x8 screws)",partName:"Part name",qty:"Qty",price:"Price ({{currency}})",sourcingUrlPlaceholder:"Sourcing URL (optional)",remarksPlaceholder:"Remarks (optional)",deletePart:"Delete Part",deleteConfirm:'Are you sure you want to delete "{{name}}"?',noUpdatePermission:"You do not have permission to update parts",noEditPermission:"You do not have permission to edit parts",noDeletePermission:"You do not have permission to delete parts",totalCost:"Total cost:",empty:"No parts in the bill of materials. Add hardware, electronics, or other components to track what needs to be sourced."},timeline:{title:"Activity Timeline",empty:"No activity yet."},template:{saveAsTemplate:"Save as Template",noCreatePermission:"You do not have permission to create templates"},queue:{title:"Queue",viewAll:"View all",printing:"{{count}} printing",queued:"{{count}} queued"},prints:{title:"Prints ({{count}})"},toast:{projectUpdated:"Project updated",partAdded:"Part added",partRemoved:"Part removed",exportFailed:"Export failed",projectExported:"Project exported",templateCreated:"Template created"}},system:{title:"System Information",version:"Version",uptime:"Uptime",cpuUsage:"CPU Usage",memoryUsage:"Memory Usage",diskUsage:"Disk Usage",networkInfo:"Network Info",logs:"Logs",debugMode:"Debug Mode",enableDebug:"Enable Debug Logging",disableDebug:"Disable Debug Logging",downloadLogs:"Download Logs",clearLogs:"Clear Logs",dockerInfo:"Docker Info",containerName:"Container Name",imageName:"Image Name",platform:"Platform",architecture:"Architecture"},library:{title:"Filament Library",addFilament:"Add Filament",editFilament:"Edit Filament",deleteFilament:"Delete Filament",vendor:"Vendor",material:"Material",color:"Color",kFactor:"K Factor",temperature:"Temperature",noFilaments:"No filaments in library",deleteConfirm:"Are you sure you want to delete this filament?",importFromPrinter:"Import from Printer",exportToFile:"Export to File"},spoolman:{title:"Spoolman Integration",enabled:"Spoolman Enabled",url:"Spoolman URL",connected:"Connected",disconnected:"Not Connected",testConnection:"Test Connection",sync:"Sync",syncing:"Syncing...",lastSync:"Last Sync",linkToSpoolman:"Link to Spoolman",openInSpoolman:"Open in Spoolman",unlinkSpool:"Unlink Spool",unlinkConfirmTitle:"Unlink Spool?",unlinkConfirmMessage:"This will disconnect the spool from Spoolman. The spool data in Spoolman will remain unchanged.",selectSpool:"Select Spool",noUnlinkedSpools:"No unlinked spools available",linkSuccess:"Spool linked to Spoolman successfully",linkFailed:"Failed to link spool",unlinkSuccess:"Spool unlinked from Spoolman successfully",unlinkFailed:"Failed to unlink spool",spoolId:"Spool ID",fillSourceLabel:"(Spoolman)",weight:"Weight",remaining:"Remaining",disableWeightSync:"Disable AMS Estimated Weight Sync",disableWeightSyncDesc:"Don't update remaining capacity from AMS estimates. Use this if you prefer Spoolman's usage tracking over AMS percentage-based estimates. New spools will still use the AMS estimate as their initial weight.",reportPartialUsage:"Report Partial Usage for Failed Prints",reportPartialUsageDesc:"When a print fails or is cancelled, report the estimated filament used up to that point based on layer progress."},inventory:{title:"Spool Inventory",addSpool:"Add Spool",editSpool:"Edit Spool",material:"Material",selectMaterial:"Select material...",subtype:"Subtype",brand:"Brand",searchBrand:"Search brand...",useCustomBrand:'Use "{{brand}}"',useCustomMaterial:"Use custom material: {{material}}",colorName:"Color Name",colorNamePlaceholder:"Jade White, Fire Red...",color:"Color",hexColor:"Hex Color",pickColor:"Pick custom color",labelWeight:"Label Weight",coreWeight:"Empty Spool Weight",searchSpoolWeight:"Search spool weight...",weightUsed:"Used",currentWeight:"Remaining Weight",measuredWeight:"Measured Weight",spoolName:"Spool",costPerKg:"Cost per kg",measuredWeightError:"Measured weight must be between {{min}}g and {{max}}g.",slicerFilament:"Slicer Filament",slicerFilamentName:"Slicer Preset Name",slicerPreset:"Slicer Preset",searchPresets:"Search filament presets...",selectedPreset:"Selected",noPresetsFound:"No presets found",tempOverrides:"Temperature Overrides",note:"Note",notePlaceholder:"Any additional notes about this spool...",archive:"Archive",restore:"Restore",noSpools:"No spools yet. Add your first spool to get started.",noManualSpools:"No manually added spools available. Add a spool to your inventory first.",kProfiles:"K-Profiles",addKProfile:"Add K-Profile",assignSpool:"Assign Spool",unassignSpool:"Unassign",assignSuccess:"Spool assigned and AMS slot configured",assignFailed:"Failed to assign spool",selectSpool:"Select a spool to assign to this slot",assigned:"Assigned",assigning:"Assigning...",searchSpools:"Search spools...",showAllSpools:"Show all spools",allMaterials:"All Materials",filterByBrand:"Filter by brand...",showArchived:"Show archived",quickAdd:"Quick Add (Stock)",quantity:"Quantity",stock:"Stock",configured:"Configured",spoolsCreated:"{{count}} spools created",spoolCreated:"Spool created",spoolUpdated:"Spool updated",spoolDeleted:"Spool deleted",spoolArchived:"Spool archived",spoolRestored:"Spool restored",deleteConfirm:"Are you sure you want to delete this spool? This cannot be undone.",archiveConfirm:"Are you sure you want to archive this spool?",advancedSettings:"Advanced Settings",filamentInfoTab:"Filament Info",paProfileTab:"PA Profile",filamentInfo:"Filament",additional:"Additional",loadingPresets:"Loading cloud presets...",cloudConnected:"Cloud connected",cloudNotConnected:"Cloud not connected (using defaults)",recentColors:"Recent",searchColors:"Search colors...",searchResults:"Search results",allColors:"All colors",commonColors:"Common colors",showLess:"Show less",showAll:"Show all",noColorsFound:"No colors match your search",noResults:"No matches found",selectMaterialFirst:"Please select a material first in the Filament Info tab.",noPrintersConfigured:"No printers configured. Add printers to use PA profiles.",matchingFilter:"Matching",anyBrand:"Any brand",anyVariant:"Any variant",autoSelect:"Auto-select",matches:"matches",match:"match",noMatches:"No matches",connected:"Connected",offline:"Offline",printerOffline:"Printer is offline. Connect to view calibration profiles.",noKProfilesMatch:"No K-profiles match the selected filament.",leftNozzle:"Left Nozzle",rightNozzle:"Right Nozzle",profilesSelected:"calibration profile(s) selected",totalInventory:"Total Inventory",totalConsumed:"Total Consumed",byMaterial:"By Material",inPrinter:"In Printer",lowStock:"Low Stock",sinceTracking:"Since tracking started",loadedInAms:"Loaded in AMS/Ext",remaining:"Remaining",weightCheck:"Weight Check",lastWeighed:"Last weighed",neverWeighed:"Never weighed",search:"Search spools...",showing:"Showing",to:"to",of:"of",show:"Show",spools:"spools",spool:"spool",page:"Page",noSpoolsMatch:"No results found",noSpoolsMatchDesc:"Try adjusting your search or filters to find what you're looking for.",active:"Active",archived:"Archived",all:"All",used:"Used",new:"New",clearFilters:"Clear filters",table:"Table",cards:"Cards",net:"Net",groupSimilar:"Group",groupedSpools:"{{count}} identical spools",groupedRows:"rows",columns:"Columns",configureColumns:"Configure Columns",configureColumnsDesc:"Drag to reorder columns or use arrows. Toggle visibility with the eye icon.",visible:"visible",reset:"Reset",cancel:"Cancel",applyChanges:"Apply Changes",moveUp:"Move up",moveDown:"Move down",hideColumn:"Hide column",showColumn:"Show column",linkToSpool:"Link to Spool",tagLinked:"Tag linked to spool",tagLinkFailed:"Failed to link tag",tagAlreadyLinked:"Tag already linked to another spool",unknownTag:"Unknown RFID tag detected",usageHistory:"Usage History",noUsageHistory:"No usage recorded yet",printName:"Print Name",weightConsumed:"Weight Consumed",clearHistory:"Clear",historyCleared:"Usage history cleared",fillSourceLabel:"(Inv)",lowStockThresholdError:"Threshold must be between 0.1 and 99.9",assignMismatchTitle:"Material mismatch",assignMismatchMessage:'The selected spool material "{{spoolMaterial}}" does not match the tray material "{{trayMaterial}}" for {{location}}. Assign anyway?',assignMismatchConfirm:"Assign Anyway",assignPartialMismatchMessage:'The spool material "{{spoolMaterial}}" is similar to but not exactly matching "{{trayMaterial}}" in {{location}}. Do you want to proceed?',assignProfileMismatchMessage:'The spool profile "{{spoolProfile}}" does not match the tray profile "{{trayProfile}}" in {{location}}. Do you want to proceed?'},timelapse:{title:"Timelapse",create:"Create Timelapse",download:"Download",delete:"Delete",preview:"Preview",frameRate:"Frame Rate",quality:"Quality",processing:"Processing...",noTimelapses:"No timelapses available"},ams:{title:"AMS",slot:"Slot",empty:"Empty",emptySlot:"Empty slot",unknown:"Unknown",humidity:"Humidity",temperature:"Temperature",filamentType:"Filament Type",filamentColor:"Color",remaining:"Remaining",history:"AMS History",noHistory:"No history available",configureSlot:"Configure Slot",externalSpool:"External Spool",profile:"Profile",kFactor:"K Factor",fill:"Fill",configure:"Configure",used:"used",remainingUnit:"remaining"},printModal:{title:"Start Print",selectPrinter:"Select Printer",selectPlate:"Select Plate",filamentMapping:"Filament Mapping",totalCost:"Total cost:",slotRemainingShort:" - {{grams}}g left",printSettings:"Print Settings",bedLeveling:"Bed Leveling",flowCalibration:"Flow Calibration",vibrationCalibration:"Vibration Calibration",layerInspection:"First Layer Inspection",timelapse:"Timelapse",startPrint:"Start Print",addToQueue:"Add to Queue",cancel:"Cancel",noPrintersAvailable:"No printers available",printerBusy:"Printer is busy",printerOffline:"Printer is offline",sameTypeDifferentColor:"Same type, different color",filamentTypeNotLoaded:"Filament type not loaded",openCalendar:"Open calendar",leftNozzle:"L",rightNozzle:"R",leftNozzleTooltip:"Left nozzle",rightNozzleTooltip:"Right nozzle",filamentOverride:"Filament Override",filamentOverrideHint:"Optionally override filaments for model-based assignment. The scheduler will match against your selected filaments instead of the original 3MF values.",originalFilament:"Original",overrideWith:"Override with",resetToOriginal:"Reset to original",insufficientFilamentTitle:"Not enough filament",insufficientFilamentMessage:"Some assigned spools have less filament remaining than this print needs:",insufficientFilamentLine:"{{printer}} - {{slot}}: needs {{required}}g, remaining {{remaining}}g",printAnyway:"Print anyway",forceColorMatch:"Force color match",staggerPrinterStarts:"Stagger printer starts",staggerGroupSize:"Group size",staggerInterval:"Interval (min)",staggerPreview:"{{printers}} printers → {{groups}} groups of {{size}}, starting every {{interval}} min",staggerLastGroup:"last group: {{count}}",staggerTotal:"total: {{minutes}} min",staggerToPrinters:"Stagger to {{count}} printers",gcodeInjection:"Inject auto-print G-code"},backup:{title:"Backup & Restore",createBackup:"Create Backup",restoreBackup:"Restore Backup",restoreDescription:"Replace all data from a backup file",downloadBackup:"Download Backup",uploadBackup:"Upload Backup",lastBackup:"Last Backup",autoBackup:"Auto Backup",backupNow:"Backup Now",restoreWarning:"Warning: Restoring a backup will overwrite all current data.",includeArchives:"Include Archives",includeSettings:"Include Settings",includeProfiles:"Include Profiles",backupSuccess:"Backup created successfully",restoreSuccess:"Backup restored successfully",backupFailed:"Backup failed",restoreFailed:"Restore failed",restoreNote:"Virtual Printer will be stopped during restore",githubBackup:"GitHub Backup",enabled:"Enabled",cloudLoginRequired:"Bambu Cloud login required. Sign in under Profiles → Cloud Profiles to enable GitHub backup.",cloudLoginRequiredShort:"Cloud login required",githubDescription:"Automatically sync your profiles to a private GitHub repository for backup and version history.",repositoryUrl:"Repository URL",personalAccessToken:"Personal Access Token",tokenSaved:"(saved)",enterNewToken:"Enter new token to update",tokenHint:"Fine-grained token with Contents read/write permission",branch:"Branch",manualOnly:"Manual only",hourly:"Hourly",daily:"Daily",weekly:"Weekly",includeInBackup:"Include in backup",kProfiles:"K-Profiles",kProfilesDescription:"Pressure advance calibration from connected printers",noPrintersConnected:"No printers connected",printersConnected:"{{connected}}/{{total}} connected",cloudProfiles:"Cloud Profiles",cloudProfilesDescription:"Filament, printer, and process presets from Bambu Cloud",appSettings:"App Settings",appSettingsDescription:"Bambuddy configuration (complete database)",spoolInventory:"Spool Inventory",spoolInventoryDescription:"Filament spools, usage history, and cost tracking",printArchives:"Print Archives",printArchivesDescription:"Print history metadata (no gcode/3MF files)",lastBackupAt:"Last backup:",noBackupsYet:"No backups yet",next:"Next:",startingBackup:"Starting backup...",test:"Test",enableBackup:"Enable Backup",testConnection:"Test Connection",enterRepoUrl:"Enter repository URL",enterRepoAndToken:"Enter repository URL and access token",repoRequired:"Repository URL is required",tokenRequired:"Access token is required",githubBackupEnabled:"GitHub backup enabled",tokenUpdated:"Token updated",settingsSaved:"Settings saved",failedToSave:"Failed to save: {{message}}",backupCompleteFiles:"Backup complete - {{count}} files updated",backupSkippedNoChanges:"Backup skipped - no changes",backupFailed2:"Backup failed: {{message}}",clearedLogs:"Cleared {{count}} logs",failedToClearLogs:"Failed to clear logs: {{message}}",history:"History",clear:"Clear",date:"Date",status:"Status",commit:"Commit",localBackup:"Local Backup",localBackupDescription:"Create a complete backup of your Bambuddy data including the database, archives, uploads, and all files.",downloadBackupLabel:"Download Backup",completeBackupZip:"Complete backup: database + all files (ZIP)",download:"Download",preparingBackup:"Preparing backup...",creatingArchive:"Creating backup archive... This may take a while for large archives.",downloadingFile:"Downloading backup file...",backupDownloaded:"Backup downloaded successfully",failedToCreateBackup:"Failed to create backup: {{message}}",restore:"Restore",restoreReplacesAll:"Restore replaces all data.",restoreReplacesAllDetail:"Your current database and files will be completely replaced. A restart is required after restore.",restoreConfirmTitle:"Restore Backup",restoreConfirmMessage:'Are you sure you want to restore from "{{filename}}"? This will completely replace your current database and all files. The application will need to be restarted after restore.',restoreConfirmButton:"Restore Backup",uploadingFile:"Uploading backup file...",backupRestoredRestart:"Backup restored. Please restart Bambuddy.",failedToRestore:"Failed to restore backup. Please check the file format.",reloadNow:"Reload Now",creatingBackup:"Creating Backup",restoringBackup:"Restoring Backup",preparing:"Preparing...",processing:"Processing...",doNotClosePage:"Please do not close this page or navigate away. This operation may take several minutes for large backups.",restoring:"Restoring...",restoreComplete:"Restore Complete",restoreFailed2:"Restore Failed",importSettings:"Import settings from a backup file",pleaseWaitRestoring:"Please wait while your data is being restored",selectBackupFile:"Click to select backup file (.json or .zip)",duplicateHandling:"How duplicate handling works:",matchPrinters:"Printers",matchPrintersBy:"matched by serial number",matchSmartPlugs:"Smart Plugs",matchSmartPlugsBy:"matched by IP address",matchNotificationProviders:"Notification Providers",matchNotificationProvidersBy:"matched by name",matchFilaments:"Filaments",matchFilamentsBy:"matched by name + type + brand",matchArchives:"Archives",matchArchivesBy:"matched by content hash (always skipped)",matchPendingUploads:"Pending Uploads",matchPendingUploadsBy:"matched by filename",matchSettingsTemplates:"Settings & Templates",matchSettingsTemplatesBy:"always overwritten",replaceExisting:"Replace existing data",keepExisting:"Keep existing data",overwriteDescription:"Overwrite items that already exist with backup data",keepDescription:"Only restore items that don't already exist",overwriteCaution:"Caution:",overwriteWarning:"Overwriting will replace your current configurations with data from the backup. Printer access codes are never overwritten for security.",cancel:"Cancel",processingBackup:"Processing backup file...",itemsRestored:"Items Restored",itemsSkipped:"Items Skipped",restored:"Restored",skippedAlreadyExist:"Skipped (already exist)",filesCategory:"Files (3MF, thumbnails, etc.)",andMore:"...and {{count}} more",newApiKeysGenerated:"New API Keys Generated",keysShownOnce:"These keys are only shown once. Copy them now!",copy:"Copy",noDataFound:"No data was found to restore in the backup file.",close:"Close",scheduledBackup:"Scheduled Backups",scheduledBackupDescription:"Automatically create backup snapshots on a schedule. Output directory can be mounted to a NAS or external storage.",frequency:"Frequency",backupTime:"Time",retention:"Retention",retentionDescription:"Number of backups to keep",outputPath:"Output Path",outputPathPlaceholder:"Default: {{path}}",outputPathDescription:"Leave empty for default location",runNow:"Run Now",backupFiles:"Backup Files",noScheduledBackups:"No backups yet",deleteBackup:"Delete",deleteBackupConfirm:"Delete this backup file?",backupRunning:"Backup in progress...",scheduledBackupComplete:"Backup completed successfully",scheduledBackupFailed:"Backup failed",nextBackup:"Next backup",backupSize:"Size",utc:"UTC",defaultPathLabel:"Default:",categories:{settings:"Settings",notification_providers:"Notification Providers",notification_templates:"Notification Templates",smart_plugs:"Smart Plugs",printers:"Printers",filaments:"Filaments",maintenance_types:"Maintenance Types",archives:"Archives",projects:"Projects",pending_uploads:"Pending Uploads",external_links:"External Links",api_keys:"API Keys"}},tags:{title:"Tags",addTag:"Add Tag",editTag:"Edit Tag",deleteTag:"Delete Tag",tagName:"Tag Name",tagColor:"Tag Color",noTags:"No tags",deleteConfirm:"Are you sure you want to delete this tag?",manageTags:"Manage Tags"},uploadModal:{title:"Upload 3MF Files",dragDrop:"Drag & drop .3mf files here",or:"or",browseFiles:"Browse Files",extractionInfo:"The printer model will be automatically extracted from the 3MF file metadata.",uploaded:"uploaded",failed:"failed",uploading:"Uploading...",upload:"Upload",uploadFailed:"Upload failed"},editArchive:{title:"Edit Archive",name:"Name",namePlaceholder:"Print name",printer:"Printer",noPrinter:"No printer",project:"Project",noProject:"No project",itemsPrinted:"Items Printed",itemsPrintedHelp:"Number of items produced in this print job",notes:"Notes",notesPlaceholder:"Add notes about this print...",externalLink:"External Link",externalLinkPlaceholder:"https://printables.com/model/...",externalLinkHelp:"Link to Printables, Thingiverse, or other source",tags:"Tags",tagsPlaceholder:"Add tags...",addMoreTags:"Add more tags...",matchingTags:'Matching "{{query}}"',existingTags:"Existing tags",clickToAdd:"(click to add)",status:"Status",failureReason:"Failure Reason",selectReason:"Select reason...",photos:"Photos of Printed Result",photosHelp:"Click + to add photos of your printed result",printResult:"Print result",saving:"Saving...",failureReasons:{adhesionFailure:"Adhesion failure",spaghettiDetached:"Spaghetti / Detached",layerShift:"Layer shift",cloggedNozzle:"Clogged nozzle",filamentRunout:"Filament runout",warping:"Warping",stringing:"Stringing",underExtrusion:"Under-extrusion",powerFailure:"Power failure",userCancelled:"User cancelled",other:"Other"},statuses:{completed:"Completed",failed:"Failed",aborted:"Cancelled",printing:"Printing"}},kProfiles:{title:"K-Profiles",noPrintersConfigured:"No Printers Configured",addPrinterInSettings:"Add a printer in Settings to manage K-profiles",noActivePrinters:"No Active Printers",enablePrinterConnection:"Enable a printer connection to view its K-profiles",loadingProfiles:"Loading K-Profiles...",printerOffline:"Printer Offline",printerOfflineDesc:"The selected printer is not connected. Power it on to view K-profiles.",noMatchingProfiles:"No Matching Profiles",noMatchingProfilesDesc:"No profiles match your search criteria",noKProfiles:"No K-Profiles",noKProfilesDesc:"No pressure advance profiles found for {{diameter}}mm nozzle",createFirstProfile:"Create First Profile",printer:"Printer",nozzle:"Nozzle",refresh:"Refresh",addProfile:"Add Profile",export:"Export",import:"Import",select:"Select",selectAll:"Select All",delete:"Delete",searchPlaceholder:"Search by name or filament...",allExtruders:"All Extruders",leftOnly:"Left Only",rightOnly:"Right Only",allFlow:"All Flow",hfOnly:"HF Only",sOnly:"S Only",sortName:"Sort: Name",sortKValue:"Sort: K-Value",sortFilament:"Sort: Filament",leftExtruder:"Left Extruder",rightExtruder:"Right Extruder",modal:{addTitle:"Add K-Profile",editTitle:"Edit K-Profile",profileName:"Profile Name",profileNamePlaceholder:"My PLA Profile",kValue:"K-Value",kValuePlaceholder:"0.020",kValueHelp:"Typical range: 0.01 - 0.06 for PLA, 0.02 - 0.10 for PETG",filament:"Filament",selectFilament:"Select filament...",noFilamentsHelp:"No filaments found. Create a K-profile in Bambu Studio first.",flowType:"Flow Type",highFlow:"High Flow",standard:"Standard",nozzleSize:"Nozzle Size",extruder:"Extruder",extruders:"Extruders",left:"Left",right:"Right",notes:"Notes (stored locally)",notesPlaceholder:"Add notes about this profile...",notesHelp:"Notes are saved in Bambuddy, not on the printer",syncing:"Syncing with printer...",savingExtruder:"Saving to extruder {{current}}/{{total}}...",pleaseWait:"Please wait"},deleteConfirm:{title:"Delete Profile",cannotUndo:"This cannot be undone",message:'Are you sure you want to delete "{{name}}" from the printer?'},bulkDelete:{title:"Delete Profiles",cannotUndo:"This cannot be undone",message:"Are you sure you want to delete {{count}} selected profiles from the printer?"},toast:{profileSaved:"K-profile saved",profilesSaved:"K-profile saved to {{count}} extruders",selectAtLeastOneExtruder:"Please select at least one extruder",profileDeleted:"K-profile deleted",profilesDeleted:"Deleted {{count}} profiles",exportedProfiles:"Exported {{count}} profiles",importedProfiles:"Imported {{count}} of {{total}} profiles",noProfilesToExport:"No profiles to export",invalidFileFormat:"Invalid file format",failedToParseImport:"Failed to parse import file",failedToSaveBatch:"Failed to save K-profiles",noteSaved:"Note saved",failedToSaveNote:"Failed to save note"},permission:{noRead:"You do not have permission to refresh profiles",noCreate:"You do not have permission to add profiles",noUpdate:"You do not have permission to update K-profiles",noDelete:"You do not have permission to delete K-profiles",noExport:"You do not have permission to export profiles",noImport:"You do not have permission to import profiles"}},virtualPrinter:{title:"Virtual Printer",running:"Running",stopped:"Stopped",description:{default:"Enable a virtual printer that appears in Bambu Studio and OrcaSlicer. Files sent to this printer will be archived directly without printing.",proxy:"Enable a proxy that relays slicer traffic to a real printer, allowing remote printing over any network."},enable:{title:"Enable Virtual Printer",visibleInSlicer:'Visible as "Bambuddy" in slicer discovery',proxyingTo:"Proxying to {{name}}",notActive:"Not active"},model:{title:"Printer Model",description:"Select which printer model to emulate.",restartWarning:"Changing the model will restart the virtual printer"},accessCode:{title:"Access Code",isSet:"Access code is set",notSet:"No access code set - required to enable",placeholder:"Enter 8-char code",placeholderChange:"Enter new code to change",hint:"Must be exactly 8 characters. Used by slicers to authenticate.",charCount:"({{count}}/8)"},targetPrinter:{title:"Target Printer",configured:"Proxy target configured",notConfigured:"No target printer selected - required for proxy mode",placeholder:"Select a printer...",hint:"Select the printer to proxy slicer traffic to. The printer must be in LAN mode.",noPrinters:"No printers configured. Add a printer first to use proxy mode."},remoteInterface:{title:"Network Interface Override",configured:"Interface override active",optional:"Optional - use if auto-detected IP is wrong (e.g. multiple NICs, Docker, VPN)",placeholder:"Auto-detect (default)...",hint:"Override the IP address advertised via SSDP and used in the TLS certificate. Useful when Bambuddy has multiple network interfaces."},mode:{title:"Mode",archive:"Archive",archiveDesc:"Archive files immediately",review:"Review",reviewDesc:"Review before archiving",queue:"Queue",queueDesc:"Archive and add to queue",proxy:"Proxy",proxyDesc:"Relay to real printer"},autoDispatch:{title:"Auto-dispatch",description:"Automatically start prints when added to queue. When off, prints wait for manual dispatch."},setupRequired:{title:"Setup Required",description:"The virtual printer feature requires additional system configuration before it will work. This includes port forwarding, firewall rules, and platform-specific settings.",readGuide:"Read the setup guide before enabling"},howItWorks:{title:"How it works",step1:"On the same LAN, virtual printers appear in your slicer (Bambu Studio / OrcaSlicer) automatically via discovery. From other networks, add them manually by IP address and access code.",step2:'In Archive, Review, and Queue modes, use the "Send" button in your slicer to upload 3MF files to Bambuddy. The slicer will show "Print success" — the file is stored, not printed.',step3:"In Proxy mode, the virtual printer relays all traffic to a real printer — prints start immediately as if connected directly."},status:{title:"Status Details",printerName:"Printer Name",model:"Model",serialNumber:"Serial Number",mode:"Mode",pendingFiles:"Pending Files",targetPrinter:"Target Printer",ftpPort:"FTP Port",mqttPort:"MQTT Port",ftpConnections:"FTP Connections",mqttConnections:"MQTT Connections"},toast:{updated:"Virtual printer settings updated",failedToUpdate:"Failed to update settings",accessCodeRequired:"Please set an access code first",targetPrinterRequired:"Please select a target printer first",bindIpRequired:"Please set a bind IP first",accessCodeEmpty:"Access code cannot be empty",accessCodeLength:"Access code must be exactly 8 characters",created:"Virtual printer created",failedToCreate:"Failed to create virtual printer",deleted:"Virtual printer deleted",failedToDelete:"Failed to delete virtual printer"},list:{title:"Virtual Printers",add:"Add",addFirst:"Add Virtual Printer",empty:"No virtual printers configured. Add one to get started."},bindIp:{title:"Bind Interface",placeholder:"Select interface...",hint:"Network interface for this virtual printer to bind to. Must be unique per printer."},proxy:{accessCodeHint:"In proxy mode, use your target printer's access code in the slicer. The connection is forwarded transparently to the real printer."},addDialog:{title:"Add Virtual Printer",name:"Name",hint:"You can configure access code, target printer, and other settings after creating.",create:"Create"},deleteConfirm:{title:"Delete Virtual Printer",message:'Are you sure you want to delete "{{name}}"? This will stop all services for this printer.'}},modelViewer:{openInSlicer:"Open in Slicer",tabs:{model:"3D Model",gcode:"G-code Preview"},notAvailable:"not available",notSliced:"not sliced",plates:"Plates",allPlates:"All Plates",plateNumber:"Plate {{number}}",plateCount:"{{count}} plate",plateCount_other:"{{count}} plates",objectCount:"{{count}} object",objectCount_other:"{{count}} objects",filamentCount:"{{count}} filament",filamentCount_other:"{{count}} filaments",eta:"ETA {{minutes}} min",noPreview:"No preview available for this file",pagination:{pageOf:"Page {{current}} of {{total}}",prev:"Prev",next:"Next"},errors:{failedToLoad:"Failed to load file",noMeshes:"No meshes found in 3MF file",unsupportedFormat:"Unsupported file format"}},maintenanceDescriptions:{lubricateCarbonRods:"Apply lubricant to carbon rods for smooth motion",lubricateRails:"Apply lubricant to linear rails for smooth motion",cleanNozzle:"Clean hotend and nozzle to prevent clogs",checkBelts:"Verify belt tension for accurate prints",cleanBuildPlate:"Clean build plate for better adhesion",checkExtruder:"Inspect extruder gears for wear",checkCooling:"Ensure cooling fans are working properly",generalInspection:"General printer inspection",cleanCarbonRods:"Clean carbon rods to reduce friction",lubricateSteelRods:"Apply lubricant to steel rods for smooth motion",cleanSteelRods:"Clean steel rods to reduce friction",cleanLinearRails:"Wipe linear rails to remove dust and debris",checkPtfeTube:"Inspect PTFE tube for wear or damage",replaceHepaFilter:"Replace HEPA filter for air quality",replaceCarbonFilter:"Replace activated carbon filter",lubricateLeftNozzleRail:"Lubricate left nozzle rail (H2 series)"},smartPlugs:{offline:"Offline",admin:"Admin",openPlugAdminPage:"Open plug admin page",deleteSmartPlug:"Delete Smart Plug",turnOnSmartPlug:"Turn On Smart Plug",turnOffSmartPlug:"Turn Off Smart Plug",turnOn:"Turn On",turnOff:"Turn Off",addSmartPlug:{scanningNetwork:"Scanning network...",chooseEntity:"Choose an entity...",connectionFailed:"Connection failed",searchEntities:"Search entities...",searchPowerSensors:"Search power sensors...",searchEnergySensors:"Search energy sensors...",placeholders:{plugName:"Living Room Plug",mqttStateOnValue:"ON, true, 1",mqttSameAsPower:"Same as power topic, or different"}},linkedTo:"Linked to:",monitorOnly:"Monitor Only",alerts:"Alerts",scheduleOn:"On {{time}}",scheduleOff:"Off {{time}}",on:"On",off:"Off",power:"Power",kwhToday:"kWh Today",settings:"Settings",automationSettings:"Automation Settings",showInSwitchbar:"Show in Switchbar",quickAccessSidebar:"Quick access from sidebar",enabled:"Enabled",enableAutomation:"Enable automation for this plug",autoOn:"Auto On",autoOnDescription:"Turn on when print starts",autoOff:"Auto Off",autoOffDescription:"Turn off when print completes (one-shot)",autoOffPersistent:"Keep Enabled",autoOffPersistentDescription:"Stay enabled between prints instead of one-shot",turnOffDelayMode:"Turn Off Delay Mode",time:"Time",temp:"Temp",delayMinutes:"Delay (minutes)",tempThreshold:"Temperature threshold (°C)",tempThresholdDescription:"Turns off when nozzle cools below this temperature",edit:"Edit",deleteConfirm:'Are you sure you want to delete "{{name}}"? This cannot be undone.',turnOnConfirm:'Are you sure you want to turn on "{{name}}"?',turnOffConfirm:'Are you sure you want to turn off "{{name}}"? This will cut power to the connected device.',failedToTurn:'Failed to turn {{action}} "{{name}}"',unknown:"Unknown",addTitle:"Add Smart Plug",editTitle:"Edit Smart Plug",stopScanning:"Stop Scanning",discoverTasmota:"Discover Tasmota Devices",foundDevices:"Found {{count}} device(s) - click to select:",noDevicesFound:"No Tasmota devices found on your network",haNotConfigured:"Home Assistant is not configured. Set it up in",haSettingsPath:"Settings → Network → Home Assistant",selectEntity:"Select Entity *",ipAddress:"IP Address *",nameLabel:"Name *",username:"Username",password:"Password",authHint:"Leave empty if your Tasmota device doesn't require authentication",linkToPrinter:"Link to Printer",noPrinter:"No printer (manual control only)",linkingDescription:"Linking enables automatic on/off when prints start/complete",powerAlerts:"Power Alerts",alertAbove:"Alert if above (W)",alertBelow:"Alert if below (W)",alertDescription:"Get notified when power consumption crosses these thresholds. Leave empty to disable that direction.",dailySchedule:"Daily Schedule",turnOnAt:"Turn On at",turnOffAt:"Turn Off at",scheduleDescription:"Automatically turn the plug on/off at these times daily. Leave empty to skip that action.",showOnPrinterCard:"Show on Printer Card",displayOnPrinterCard:"Display button on printer card",connectedResult:"Connected!",deviceLabel:"Device: {{name}} - ",stateLabel:"State: {{state}}",test:"Test",delete:"Delete",save:"Save",add:"Add",cancel:"Cancel",failedToStartScan:"Failed to start scan",nameRequired:"Name is required",entityRequired:"Entity is required for Home Assistant plugs",mqttTopicRequired:"At least one MQTT topic must be configured for power, energy, or state monitoring",loadingEntities:"Loading entities...",loading:"Loading...",failedToLoadEntities:"Failed to load entities: {{error}}",noEntitiesMatching:'No entities found matching "{{search}}"',noEntitiesAvailable:"No entities available",searchingEntities:"Searching all entities ({{count}} found)",showingEntities:"Showing switch, light, input_boolean ({{count}} available)",energyMonitoringOptional:"Energy Monitoring (Optional)",energyMonitoringHint:"Search and select sensors that provide power/energy data.",powerSensorW:"Power Sensor (W)",energyTodayKwh:"Energy Today (kWh)",totalEnergyKwh:"Total Energy (kWh)",noMatchingSensors:"No matching sensors",none:"None",mqttNotConfigured:"MQTT broker not configured. Set broker address in",mqttSettingsPath:"Settings → Network → MQTT Publishing",mqttNotConfiguredSuffix:"(you don't need to enable publishing, just fill in the broker details).",mqttMonitorOnlyDescription:"MQTT plugs receive power/energy data via MQTT subscription. On/off control is not available - use your MQTT broker or home automation system.",powerMonitoring:"Power Monitoring",energyMonitoring:"Energy Monitoring",stateMonitoring:"State Monitoring",optional:"optional",topic:"Topic",jsonPath:"JSON Path",multiplier:"Multiplier",onValue:"ON Value",mqttPowerHint:`JSON path extracts value from JSON payload (e.g., "power_l1"). Leave empty if topic publishes raw numeric values. Use multiplier 0.001 for mW→W, 1000 for kW→W.`,mqttEnergyHint:`JSON path extracts value from JSON payload. Leave empty for raw values. Use multiplier 0.001 for Wh→kWh, 1000 for MWh→kWh.`,mqttStateHint:`JSON path extracts value from JSON payload. Leave empty for raw values. @@ -32,7 +32,7 @@ ON值:表示"ON"的确切字符串。留空以自动检测(ON、true、1) 乘數:Wh→kWh使用0.001,MWh→kWh使用1000。`,mqttStateHint:`JSON路徑從JSON負載中提取值。原始值請留空。 ON值:表示"ON"的確切字串。留空以自動檢測(ON、true、1)。`,restControl:"控制",restOnUrl:"開啟 URL",restOffUrl:"關閉 URL",restOnBody:"開啟請求內容",restOffBody:"關閉請求內容",restMethod:"HTTP 方法",restHeaders:"自訂標頭(JSON)",restStatusUrl:"狀態 URL",restStatusPath:"狀態 JSON 路徑",restStatusOnValue:"ON 值",restPowerUrl:"功率URL",restPowerPath:"功率 JSON 路徑",restPowerMultiplier:"功率乘數",restEnergyUrl:"能耗URL",restEnergyPath:"能耗 JSON 路徑",restEnergyMultiplier:"能耗乘數",restUrlRequired:"REST 插座至少需要一個 URL(ON 或 OFF)",restHeadersHint:'例如:{"Authorization": "Bearer your-token"}',restBodyHint:'例如:ON、{"state": "on"}',restStatusHint:"用於輪詢目前狀態的 URL",restPathHint:"例如:state 或 data.power.status",restPowerUrlHint:"功率資料的獨立URL(留空則使用狀態URL)",restEnergyUrlHint:"能耗資料的獨立URL(留空則使用狀態URL)",restEnergyHint:"每個值可以使用獨立的URL,或回退到狀態 URL。使用乘數進行單位轉換(例如:0.001 將 Wh 轉換為 kWh)。",testConnection:"測試連線",connectionSuccess:"連線成功",noSwitchesInSwitchbar:"開關欄中沒有開關",enableSwitchbarHint:'在設定 > 智慧插座中啟用"在開關欄顯示"'},notifications:{providerTypes:{callmebot:"CallMeBot/WhatsApp",ntfy:"ntfy",pushover:"Pushover",telegram:"Telegram",email:"電子郵件",discord:"Discord",webhook:"Webhook",homeassistant:"Home Assistant"},providerDescriptions:{email:"SMTP 電子郵件通知",telegram:"透過 Telegram 機器人傳送通知",discord:"透過 Webhook 傳送到 Discord 頻道",ntfy:"免費、可自託管的推送通知",pushover:"簡單、可靠的推送通知",callmebot:"透過 CallMeBot 免費傳送 WhatsApp 通知",webhook:"通用 HTTP POST 到任意 URL",homeassistant:"Home Assistant 儀表板中的持久通知"},lastSuccess:"上次:{{date}}",error:"錯誤",printer:"印表機:",allPrinters:"所有印表機",sendTestNotification:"傳送測試通知",eventSettings:"事件設定",enabled:"已啟用",sendFromProvider:"從此提供者傳送通知",printEvents:"列印事件",printerStatus:"印表機狀態",amsAlarms:"AMS 警報",amsHtAlarms:"AMS-HT 警報",printQueue:"列印佇列",start:"開始",plateCheck:"熱床檢測",complete:"完成",failed:"失敗",stopped:"已停止",progress:"進度",offline:"離線",lowFilament:"耗材不足",maintenance:"維護",amsHumidity:"AMS 濕度",amsTemp:"AMS 溫度",amsHtHumidity:"AMS-HT 濕度",amsHtTemp:"AMS-HT 溫度",bedCooled:"熱床已冷卻",firstLayer:"首層完成",quiet:"免打擾",digest:"摘要 {{time}}",printStarted:"列印已開始",plateNotEmpty:"熱床非空",plateNotEmptyDescription:"列印前偵測到物體",printCompleted:"列印已完成",bedCooledLabel:"熱床已冷卻",bedCooledDescription:"列印後熱床溫度降至閾值以下",firstLayerCompleteLabel:"首層列印完成",firstLayerCompleteDescription:"首層完成時傳送帶照片的通知",missingSpoolAssignmentLabel:"缺少料卷分配",missingSpoolAssignmentDescription:"當列印開始且所需料盤沒有分配料卷時傳送通知",printFailed:"列印失敗",printStopped:"列印已停止",progressMilestones:"進度里程碑",progressMilestonesDescription:"在 25%、50%、75% 時通知",printerOffline:"印表機離線",printerError:"印表機錯誤",lowFilamentLabel:"耗材不足",maintenanceDue:"需要維護",maintenanceDueDescription:"需要維護時通知",amsHumidityHigh:"AMS 濕度過高",amsHumidityHighDescription:"普通 AMS 濕度超過閾值",amsTemperatureHigh:"AMS 溫度過高",amsTemperatureHighDescription:"普通 AMS 溫度超過閾值",amsHtHumidityHigh:"AMS-HT 濕度過高",amsHtHumidityHighDescription:"AMS-HT 濕度超過閾值",amsHtTemperatureHigh:"AMS-HT 溫度過高",amsHtTemperatureHighDescription:"AMS-HT 溫度超過閾值",jobAdded:"任務已新增",jobAddedDescription:"任務已新增到佇列",jobAssigned:"任務已分配",jobAssignedDescription:"基於模型的任務已分配給印表機",jobStarted:"任務已開始",jobStartedDescription:"佇列任務已開始列印",jobWaiting:"任務等待中",jobWaitingDescription:"任務正在等待耗材或印表機",jobSkipped:"任務已跳過",jobSkippedDescription:"任務已跳過(上一個失敗)",jobFailed:"任務失敗",jobFailedDescription:"任務啟動失敗",queueComplete:"佇列已完成",queueCompleteDescription:"所有佇列任務已完成",quietHours:"免打擾時段",noNotificationsDuring:"在此時段內不傳送通知",editProviderToChangeQuietHours:"編輯提供者以更改免打擾時段",dailyDigest:"每日摘要",batchNotifications:"將通知彙總為每日摘要",sendAt:"傳送於 {{time}}",editProviderToChangeDigestTime:"編輯提供者以更改摘要時間",edit:"編輯",deleteProvider:"刪除通知提供者",deleteConfirm:'確定要刪除"{{name}}"嗎?此操作無法復原。',delete:"刪除",addTitle:"新增通知提供者",editTitle:"編輯通知提供者",nameLabel:"名稱 *",namePlaceholder:"我的通知",providerTypeLabel:"提供者類型 *",configuration:"設定",testConfiguration:"測試設定",printerFilter:"印表機篩選",onlyFromPrinter:"僅傳送來自此印表機的事件通知",quietHoursDnd:"免打擾時段",quietStart:"開始",quietEnd:"結束",dailyDigestLabel:"每日摘要",sendDigestAt:"傳送摘要於",digestCollected:"事件將被收集並在此時間作為單條摘要傳送",notificationEvents:"通知事件",progressPercent:"(25%、50%、75%)",bedCooledAfterPrint:"(列印完成後)",cancel:"取消",save:"儲存",add:"新增",nameRequired:"名稱為必填項",fieldRequired:"{{field}}為必填項",phoneNumber:"電話號碼",apiKey:"API 金鑰",serverUrl:"伺服器 URL",topic:"主題",authToken:"認證權杖",userKey:"使用者金鑰",appToken:"應用程式權杖",priority:"優先順序",botToken:"機器人權杖",chatId:"聊天 ID",smtpServer:"SMTP 伺服器",smtpPort:"SMTP 連接埠",security:"安全",authentication:"認證",username:"使用者名稱",password:"密碼",fromEmail:"寄件人信箱",toEmail:"收件人信箱",webhookUrl:"Webhook URL",payloadFormat:"負載格式",authorization:"授權",titleFieldName:"標題欄位名",messageFieldName:"訊息欄位名",editTemplate:"編輯範本:{{name}}",titleLabel:"標題",bodyLabel:"正文",titlePlaceholder:"通知標題...",bodyPlaceholder:"通知正文...",availableVariables:"可用變數",clickToInsert:"點選插入到正文游標位置",livePreview:"即時預覽",hide:"隱藏",show:"顯示",loadingPreview:"載入預覽中...",enterTemplateContent:"輸入範本內容以檢視預覽",titlePreview:"標題:",bodyPreview:"正文:",resetToDefault:"恢復預設",titleRequired:"標題為必填項",bodyRequired:"正文為必填項",notificationLog:"通知日誌",showFailedOnly:"僅顯示失敗",last24Hours:"最近 24 小時",last7Days:"最近 7 天",last30Days:"最近 30 天",last90Days:"最近 90 天",justNow:"剛剛",noFailedNotifications:"沒有失敗的通知",noNotificationsLogged:"沒有通知紀錄",unknownProvider:"未知提供者",logTitle:"標題",logMessage:"訊息",logError:"錯誤",logProvider:"提供者:{{type}}",logTime:"時間:{{time}}",refresh:"重新整理",clearOld:"清除舊紀錄",statsSummary:"最近 {{days}} 天:",statsNotifications:"條通知",statsSent:"{{count}} 條已傳送",statsFailed:"{{count}} 條失敗",eventTypes:{print_start:"列印已開始",print_complete:"列印完成",print_failed:"列印失敗",print_stopped:"列印已停止",print_progress:"進度",printer_offline:"印表機離線",printer_error:"印表機錯誤",filament_low:"耗材不足",maintenance_due:"需要維護",test:"測試"},userEmail:{title:"通知",emailNotifications:"郵件通知",emailNotificationsDesc:"接收您自己列印任務的郵件通知。郵件將透過進階身份驗證中設定的 SMTP 設定傳送。",sendingTo:"通知將傳送至",noEmailWarning:"您的帳戶沒有郵件地址。請聯絡管理員新增。",printJobNotifications:"列印任務通知",printJobNotificationsDesc:"選擇哪些事件會觸發您提交的列印任務的郵件通知。",printJobStarts:"列印任務開始",printJobStartsDesc:"當您的列印任務開始時收到通知。",printJobFinishes:"列印任務完成",printJobFinishesDesc:"當您的列印任務成功完成時收到通知。",printErrors:"列印錯誤",printErrorsDesc:"當您的列印任務失敗或遇到錯誤時收到通知。",printJobStops:"列印任務停止",printJobStopsDesc:"當您的列印任務被取消或停止時收到通知。",saveSuccess:"通知偏好設定已儲存。",saveError:"儲存通知偏好設定失敗。"}},richTextEditor:{bold:"粗體",italic:"斜體",underline:"底線",bulletList:"無序列表",numberedList:"有序列表",alignLeft:"左對齊",alignCenter:"居中對齊",alignRight:"右對齊",addLink:"新增連結",removeLink:"移除連結"},externalLinks:{noLinksConfigured:"未設定外部連結",deleteLink:"刪除連結",removeCustomIcon:"移除自訂圖示",openInNewTab:"在新標籤頁中開啟",placeholders:{linkName:"我的連結"}},keyboardShortcuts:{title:"鍵盤快捷鍵",navigation:"導航",archivesSection:"歸檔",kProfilesSection:"K 值設定",generalSection:"通用",shortcuts:{goToPrinters:"前往印表機",goToArchives:"前往歸檔",goToQueue:"前往佇列",goToStats:"前往統計",goToProfiles:"前往雲端設定",goToSettings:"前往設定",focusSearch:"聚焦搜尋",openUploadModal:"開啟上傳對話方塊",clearSelection:"清除選擇 / 取消焦點",contextMenu:"卡片右鍵選單",refreshProfiles:"重新整理設定",newProfile:"新增設定",exitSelectionMode:"結束選擇模式",showHelp:"顯示此協助"},footer:"按 Esc 或點選外部關閉"},notificationLog:{title:"通知日誌",events:{printStarted:"列印開始",printComplete:"列印完成",printFailed:"列印失敗",printStopped:"列印停止",progress:"進度",printerOffline:"印表機離線",printerError:"印表機錯誤",lowFilament:"耗材不足",maintenanceDue:"維護到期",test:"測試"},timeAgo:{justNow:"剛剛",minutesAgo:"{{minutes}} 分鐘前",hoursAgo:"{{hours}} 小時前"}},restoreBackup:{title:"恢復備份",restoring:"恢復中...",restoreComplete:"恢復完成",restoreFailed:"恢復失敗",importSettings:"從備份檔案匯入設定",pleaseWait:"請稍候,正在恢復您的資料",clickToSelect:"點選選擇備份檔案(.json 或 .zip)",howDuplicateHandling:"重複處理方式:",categories:{printers:"印表機",smartPlugs:"智慧插座",notificationProviders:"通知提供者",filaments:"耗材",archives:"歸檔",pendingUploads:"待處理上傳",settingsTemplates:"設定和範本"},matchingInfo:{printers:"按序列號匹配",smartPlugs:"按 IP 位址匹配",notificationProviders:"按名稱匹配",filaments:"按名稱 + 類型 + 品牌匹配",archives:"按內容雜湊匹配",pendingUploads:"按檔名匹配",settingsTemplates:"始終覆蓋"},replaceExisting:"替換現有資料",keepExisting:"保留現有資料",replaceDescription:"用備份資料覆蓋已存在的項目",keepDescription:"僅恢復不存在的項目",caution:"注意:",cautionText:"覆蓋將用備份資料替換您目前的設定。出於安全考慮,印表機存取碼永遠不會被覆蓋。",itemsRestored:"已恢復項目",itemsSkipped:"已跳過項目",restored:"已恢復",skipped:"已跳過(已存在)",filesLabel:"檔案(3MF、縮圖等)",newApiKeysGenerated:"已產生新 API 金鑰",newApiKeysWarning:"這些金鑰僅顯示一次。請立即複製!",processingBackup:"處理備份檔案中...",noDataFound:"備份檔案中未找到可恢復的資料。",failedToRestore:"恢復備份失敗。請檢查檔案格式。"},backupExport:{title:"匯出備份",selectData:"選擇要包含的資料",selectAll:"全選",selectNone:"全不選",categoryDescriptions:{settings:"語言、主題、更新偏好",notifications:"ntfy、Pushover、Discord 等",templates:"自訂訊息範本",smartPlugs:"Tasmota 插座設定",externalLinks:"側邊欄外部服務連結",printers:"印表機資訊(不含存取碼)",plateDetection:"空列印板參考影像",filaments:"耗材類型和成本",maintenance:"自訂維護計畫",archives:"所有列印資料 + 檔案(3MF、縮圖、照片)",projects:"專案、材料清單和附件",pendingUploads:"虛擬印表機待審核的上傳",apiKeys:"Webhook API 金鑰(匯入時產生新金鑰)"},requiresPrinters:"需要選擇印表機",zipFileWarning:"將建立 ZIP 檔案。",zipFileDescription:"包括所有 3MF 檔案、縮圖、縮時攝影和照片。這可能需要一些時間並產生較大的檔案。",includeAccessCodes:"包含存取碼",includeAccessCodesDescription:"用於轉移到另一臺機器",includeAccessCodesWarning:"存取碼將以明文形式包含。請妥善保管此備份檔案!",categoriesSelected:"已選擇 {{selectedCount}} 個類別"},pendingUploads:{placeholders:{notes:"新增關於此列印的備註..."},discardUpload:"丟棄上傳",archiveAllUploads:"歸檔所有上傳",discardAllUploads:"丟棄所有上傳",archive:"歸檔",timeAgo:{justNow:"剛剛",minutesAgo:"{{minutes}} 分鐘前",hoursAgo:"{{hours}} 小時前",daysAgo:"{{days}} 天前"}},apiBrowser:{placeholders:{requestBody:"JSON 請求體...",searchEndpoints:"搜尋端點..."}},configureAmsSlot:{title:"設定 AMS 槽位",slotConfigured:"槽位已設定!",configuringSlot:"正在設定槽位:",slotLabel:"{{ams}} 槽位 {{slot}}",searchPresets:"搜尋預設...",colorPlaceholder:"顏色名稱或十六進位(例如:棕色、FF8800)",clearCustomColor:"清除自訂顏色",noCloudPresets:"無雲端預設。登入拓竹雲以同步。",noPresetsAvailable:"無可用預設。登入拓竹雲或匯入本機設定。",noMatchingPresets:"未找到匹配的預設。",custom:"自訂",builtin:"內建",settingsSentToPrinter:"設定已傳送到印表機",filamentProfile:"耗材設定",kProfileLabel:"K 值設定(壓力推進)",filteringFor:"篩選:{{material}}",noKProfile:"無 K 值設定(使用預設值 0.020)",noMatchingKProfiles:"未找到匹配的 K 值設定。將使用預設 K=0.020。",selectFilamentFirst:"請先選擇耗材設定",kFromCalibration:"K={{value}}(來自印表機校準)",customColorLabel:"自訂顏色(可選)",presetColors:"{{name}} 顏色:",showLessColors:"顯示更少顏色",showMoreColors:"顯示更多顏色",clear:"清除",hexLabel:"十六進位:#{{hex}}",resetting:"重設中...",resetSlot:"重設槽位",cancel:"取消",configuring:"設定中...",configureSlot:"設定槽位"},githubBackup:{title:"GitHub 備份",history:"歷史",downloadBackup:"下載備份",restoreBackup:"恢復備份",noBackupsYet:"尚無備份"},emailSettings:{placeholders:{fromName:"BamBuddy"}},tagManagement:{searchTags:"搜尋標籤...",renameTag:"重新命名標籤",deleteTag:"刪除標籤"},notificationTemplates:{placeholders:{title:"通知標題...",body:"通知正文..."}},batchTag:{placeholders:{newTag:"輸入新標籤..."}},photoGallery:{deletePhoto:"刪除照片"},filamentHoverCard:{copySpoolUuid:"複製耗材 UUID"},kProfilesView:{hasNote:"有備註",copyProfile:"複製設定"},layout:{openMenu:"開啟選單",noPermissionSystemInfo:"您沒有檢視系統資訊的權限"},dashboard:{dragToReorder:"拖曳以重新排列",hideWidget:"隱藏小工具"},notificationProviderCard:{deleteNotificationProvider:"刪除通知提供者"},fileManagerModal:{closeFileManager:"關閉檔案管理器",sortFiles:"排序檔案",goToParentFolder:"返回上級資料夾",threeView:"3D 檢視"},embeddedCameraViewer:{refreshStream:"重新整理流",close:"關閉",zoomOut:"縮小",resetZoom:"重設縮放",zoomIn:"放大",dragToResize:"拖曳調整大小"},timelapseViewer:{skipBack5s:"後退 5 秒",skipForward5s:"前進 5 秒"},notificationProviders:{descriptions:{email:"SMTP 郵件通知",telegram:"透過 Telegram 機器人通知",discord:"透過 Webhook 傳送到 Discord 頻道",ntfy:"免費、可自託管的推送通知",pushover:"簡單、可靠的推送通知",callmebot:"透過 CallMeBot 的免費 WhatsApp 通知",webhook:"通用 HTTP POST 到任意 URL"}},logViewer:{searchPlaceholder:"搜尋訊息或日誌名稱...",noLogEntries:"未找到日誌條目"},switchbarPopover:{noSwitchesInSwitchbar:"切換欄中沒有開關"},projectPageModal:{placeholders:{title:"標題",designer:"設計師",license:"許可證",description:"輸入描述...",profileTitle:"設定標題",profileDescription:"設定描述..."}},spoolmanSettings:{},time:{unknown:"-",waiting:"等待中",justNow:"剛剛",now:"現在",minsAgo:"{{count}} 分鐘前",inMins:"{{count}} 分鐘後",hoursAgo:"{{count}} 小時前",inHours:"{{count}} 小時後",daysAgo:"{{count}} 天前",inDays:"{{count}} 天後"},spoolbuddy:{nav:{dashboard:"儀表板",ams:"AMS",inventory:"庫存",writeTag:"寫入",settings:"設定"},status:{nfcReady:"NFC 就緒",nfcOff:"NFC 關閉",offline:"離線",online:"線上",noPrinters:"無印表機",deviceOffline:"裝置離線",waitingConnection:"等待裝置連線...",systemReady:"系統就緒",status:"狀態"},dashboard:{readyToScan:"準備掃描",idleMessage:"將耗材放在磅秤上以識別",nfcHint:"NFC 標籤將自動讀取",device:"裝置",syncWeight:"同步重量",weightSynced:"已同步!",unknownTag:"未知標籤",newTag:"偵測到新標籤",onScale:"在磅秤上",linkSpool:"連結到耗材",linkTagTitle:"將標籤連結到耗材",linkTag:"連結標籤",selectSpool:"選擇要連結此標籤的耗材:",noUntagged:"未找到沒有標籤的耗材",tagDetected:"偵測到標籤",noTag:"無標籤",tagId:"標籤",grossWeight:"毛重",spoolSize:"耗材盤尺寸",close:"關閉",currentSpool:"目前耗材"},modal:{spoolDetected:"偵測到耗材",assignToAms:"分配到 AMS",syncWeight:"同步重量",weightSynced:"已同步!",syncing:"同步中...",newTagDetected:"偵測到新標籤",addToInventory:"新增到庫存",assignToAmsTitle:"分配到 AMS",selectSlot:"選擇槽位",assign:"分配",assigning:"分配中...",assignSuccess:"已分配!",assignError:"分配耗材失敗。請重試。",noPrinterSelected:"選擇印表機...",noAmsDetected:"此印表機未偵測到 AMS",slot:"槽位"},weight:{noReading:"無讀數",stable:"穩定",measuring:"測量中...",tare:"去皮",calibrate:"校準"},spool:{remaining:"剩餘",material:"材料",brand:"品牌",color:"顏色",coreWeight:"軸心重",labelWeight:"標籤重",scaleWeight:"磅秤重",netWeight:"淨重",lastUsed:"上次使用"},ams:{noData:"未偵測到 AMS",connectAms:"連線 AMS 以檢視耗材槽位",noPrinter:"未選擇印表機",selectPrinter:"從頂部欄選擇印表機",printerDisconnected:"印表機已斷開",humidity:"濕度",level:"餘量",active:"活躍",slot:"槽位",empty:"空"},inventory:{search:"搜尋耗材...",empty:"庫存中沒有耗材",noResults:"沒有匹配的耗材",spools:"個耗材",addSpool:"新增耗材"},settings:{tabDevice:"裝置",tabDisplay:"顯示",tabScale:"磅秤",tabUpdates:"更新",nfcReader:"NFC 讀卡器",type:"類型",connection:"連線",notConnected:"不適用",deviceInfo:"裝置資訊",hostname:"主機",uptime:"執行時間",systemConfig:"後端與認證",backendUrl:"Bambuddy 後端 URL",apiToken:"API 權杖",apiTokenPlaceholder:"輸入 API 權杖",saveConfig:"儲存設定",systemQueued:"設定已加入佇列。",nfcDiagnostic:"NFC 診斷",scaleDiagnostic:"磅秤診斷",readTagDiagnostic:"讀取標籤診斷",testNfc:"測試讀卡器",testScale:"測試精度",testReadTag:"讀取標籤",systemFieldsRequired:"後端 URL 為必填項。",brightness:"亮度",saved:"已儲存",noBacklight:"未偵測到 DSI 背光。亮度控制需要 DSI 螢幕。",screenBlank:"螢幕熄滅超時",screenBlankDesc:"不活動後螢幕關閉。觸控喚醒。",displayNote:"亮度作為軟體濾鏡套用。",scaleCalibration:"磅秤校準",currentWeight:"目前重量",tareOffset:"去皮",calFactor:"係數",knownWeight:"已知重量",calStep1:"移除磅秤上所有物品並按設定零點。",calStep2:"將已知重量放在磅秤上。",setZero:"設定零點",calibrateNow:"校準",calibrated:"已校準",tareSet:"去皮命令已傳送。等待裝置回應...",tareFailed:"傳送去皮命令失敗",zeroSet:"零點已設定。將已知重量放在磅秤上。",calibrationDone:"校準完成!",calibrationFailed:"校準失敗",lastCalibrated:"上次校準",stable:"穩定",settling:"穩定中...",firmware:"韌體",scale:"磅秤",noDevice:"未找到 SpoolBuddy 裝置",daemonVersion:"守護程式版本",currentVersion:"目前",versionPending:"等待守護程式...",checking:"檢查中...",checkUpdates:"檢查更新",updateAvailable:"有可用更新",updateInstructions:"透過 SSH 更新:執行 SpoolBuddy 安裝腳本進行升級。",upToDate:"已是最新",includeBeta:"包含測試版本"},writeTag:{tabExisting:"現有耗材",tabNew:"新耗材",tabReplace:"替換標籤",searchPlaceholder:"按材料、顏色、品牌搜尋...",noUntaggedSpools:"沒有無標籤的耗材",noTaggedSpools:"沒有有標籤的耗材",selectSpool:"選擇一個耗材,然後將空白 NTAG 放在讀卡器上",placeTag:"將 NTAG 放在讀卡器上",tagReady:"偵測到標籤 — 準備寫入",writeTag:"寫入標籤",replaceTag:"替換標籤",writing:"寫入標籤中...",waiting:"等待 SpoolBuddy...",writeSuccess:"標籤寫入成功!",writeFailed:"寫入失敗",queueFailed:"佇列寫入命令失敗",tryAgain:"重試",cancel:"取消",replaceWarning:"舊標籤將被取消連結。新標籤將替換它。",deviceOffline:"SpoolBuddy 離線",material:"材料",colorName:"顏色名稱",color:"顏色",brand:"品牌",weight:"重量 (g)",createSpool:"建立耗材",creating:"建立中...",spoolCreated:"耗材已建立!準備寫入。",createFailed:"建立耗材失敗"},quickMenu:{printerPower:"印表機電源",systemControls:"系統",restartDaemon:"重新啟動守護程式",restartBrowser:"重新啟動瀏覽器",reboot:"重新開機",shutdown:"關機",swipeToClose:"向下滑動關閉",confirmTitle:"確認",confirmShutdown:"確定要關閉 SpoolBuddy 嗎?您需要實體存取才能重新開啟。",confirmReboot:"確定要重新開機 SpoolBuddy 嗎?",confirmRestartDaemon:"重新啟動 SpoolBuddy 守護程式?NFC 和磅秤將暫時不可用。",confirmRestartBrowser:"重新啟動kiosk瀏覽器?螢幕將短暫變黑。",confirm:"確認",confirmPlugOn:"開啟 {{name}}?",confirmPlugOff:"關閉 {{name}}?",turnOn:"開啟",turnOff:"關閉"}},bugReport:{title:"報告錯誤",description:"描述",descriptionPlaceholder:"出了什麼問題?請描述問題...",email:"信箱(可選)",emailPlaceholder:"your@email.com",emailPrivacy:"如果提供,您的信箱將包含在GitHub Issue的摺疊部分中,以便維護者後續跟進。",screenshot:"截圖",uploadOrPaste:"上傳、貼上或拖曳圖片",dataCollectedSummary:"報告中包含哪些資料?",dataIncluded:"包含:",dataIncludedList:"應用程式版本、作業系統、架構、Python版本、資料庫統計(僅計數)、印表機型號、噴嘴數量、韌體版本、連線狀態、整合狀態(Spoolman、MQTT、HA)、非敏感設定、網路介面數量、Docker詳情、依賴版本。",dataNeverIncluded:"絕不包含:",dataNeverIncludedList:"印表機名稱、序列號、存取碼、密碼、IP 位址、信箱地址、API金鑰、權杖、Webhook URL、主機名稱或使用者名稱。",submit:"提交",startLogging:"開始偵錯日誌",stepEnableLogging:"偵錯日誌已啟用",stepReproduce:"請現在重現問題",stepStopLogging:"停止並提交報告",stopAndSubmit:"停止並提交",maxDuration:"{{minutes}} 分鐘後自動停止",stoppingLogs:"正在收集日誌並提交...",submitting:"正在提交錯誤報告...",submitSuccess:"錯誤報告提交成功!",submitFailed:"提交錯誤報告失敗",thankYou:"謝謝!",submitted:"您的錯誤報告已提交。",viewIssue:"檢視 Issue",unexpectedError:"發生了意外錯誤"},failureDetection:{title:"AI 故障檢測",description:"透過自託管的 Obico ML API 監控列印,並對偵測到的故障自動採取行動。",mlUrl:"Obico ML API 地址",mlUrlHint:"您自託管的 Obico ml_api 容器的基礎 URL(例如 http://192.168.1.10:3333)。",test:"測試",testSuccess:"ML API 可存取且正常。",testFailed:"無法存取 ML API。",sensitivity:"靈敏度",sensitivityLow:"低(減少誤報)",sensitivityMedium:"中(平衡)",sensitivityHigh:"高(更早檢測,更多誤報)",sensitivityHint:"調整觸發警告和故障的置信度閾值。",action:"偵測到故障時的操作",actionNotify:"僅通知",actionPause:"暫停列印",actionPauseOff:"暫停並切斷電源",pollInterval:"檢查間隔(秒)",pollIntervalHint:"列印過程中每臺印表機的檢查頻率。最小 5 秒,最大 120 秒。",externalUrlMissing:"尚未設定外部 URL。",externalUrlHint:"ML API 透過 URL 擷取攝影機快照。請在一般設定中設定外部 URL,讓 ML API 容器可以連線到 Bambuddy。",perPrinterTitle:"監控的印表機",perPrinterHint:"選擇檢測服務要監視哪些印表機。",monitorAll:"監控所有已連線的印表機",statusTitle:"狀態",serviceRunning:"服務執行中",thresholds:"低 / 高閾值",activePrinters:"活動列印",noActivePrints:"目前沒有正在進行的列印。",historyTitle:"最近檢測",noHistory:"尚無檢測紀錄。"}},Zue={en:{translation:$ue},de:{translation:Vue},fr:{translation:Gue},ja:{translation:Wue},it:{translation:Kue},"pt-BR":{translation:Xue},"zh-CN":{translation:Yue},"zh-TW":{translation:Que}};xo.use(YY).use(Sue).init({resources:Zue,fallbackLng:"en",supportedLngs:["en","de","fr","ja","it","pt-BR","zh-CN","zh-TW"],detection:{order:["localStorage","navigator","htmlTag"],lookupLocalStorage:"bambutrack_language",caches:["localStorage"]},interpolation:{escapeValue:!1},react:{useSuspense:!1}});const iH=[{code:"en",name:"English",nativeName:"English"},{code:"de",name:"German",nativeName:"Deutsch"},{code:"fr",name:"French",nativeName:"Français"},{code:"ja",name:"Japanese",nativeName:"日本語"},{code:"it",name:"Italian",nativeName:"Italiano"},{code:"pt-BR",name:"Portuguese (Brazil)",nativeName:"Português (Brasil)"},{code:"zh-CN",name:"Chinese (Simplified)",nativeName:"简体中文"},{code:"zh-TW",name:"Chinese (Traditional)",nativeName:"繁體中文"}];var sH="popstate";function Jue(t={}){function e(r,i){let{pathname:s,search:o,hash:l}=r.location;return H3("",{pathname:s,search:o,hash:l},i.state&&i.state.usr||null,i.state&&i.state.key||"default")}function n(r,i){return typeof i=="string"?i:Q0(i)}return tme(e,n,null,t)}function Aa(t,e){if(t===!1||t===null||typeof t>"u")throw new Error(e)}function lc(t,e){if(!t){typeof console<"u"&&console.warn(e);try{throw new Error(e)}catch{}}}function eme(){return Math.random().toString(36).substring(2,10)}function oH(t,e){return{usr:t.state,key:t.key,idx:e}}function H3(t,e,n=null,r){return{pathname:typeof t=="string"?t:t.pathname,search:"",hash:"",...typeof e=="string"?by(e):e,state:n,key:e&&e.key||r||eme()}}function Q0({pathname:t="/",search:e="",hash:n=""}){return e&&e!=="?"&&(t+=e.charAt(0)==="?"?e:"?"+e),n&&n!=="#"&&(t+=n.charAt(0)==="#"?n:"#"+n),t}function by(t){let e={};if(t){let n=t.indexOf("#");n>=0&&(e.hash=t.substring(n),t=t.substring(0,n));let r=t.indexOf("?");r>=0&&(e.search=t.substring(r),t=t.substring(0,r)),t&&(e.pathname=t)}return e}function tme(t,e,n,r={}){let{window:i=document.defaultView,v5Compat:s=!1}=r,o=i.history,l="POP",c=null,d=u();d==null&&(d=0,o.replaceState({...o.state,idx:d},""));function u(){return(o.state||{idx:null}).idx}function m(){l="POP";let b=u(),g=b==null?null:b-d;d=b,c&&c({action:l,location:v.location,delta:g})}function p(b,g){l="PUSH";let _=H3(v.location,b,g);d=u()+1;let C=oH(_,d),P=v.createHref(_);try{o.pushState(C,"",P)}catch(N){if(N instanceof DOMException&&N.name==="DataCloneError")throw N;i.location.assign(P)}s&&c&&c({action:l,location:v.location,delta:1})}function f(b,g){l="REPLACE";let _=H3(v.location,b,g);d=u();let C=oH(_,d),P=v.createHref(_);o.replaceState(C,"",P),s&&c&&c({action:l,location:v.location,delta:0})}function x(b){return nme(b)}let v={get action(){return l},get location(){return t(i,o)},listen(b){if(c)throw new Error("A history only accepts one active listener");return i.addEventListener(sH,m),c=b,()=>{i.removeEventListener(sH,m),c=null}},createHref(b){return e(i,b)},createURL:x,encodeLocation(b){let g=x(b);return{pathname:g.pathname,search:g.search,hash:g.hash}},push:p,replace:f,go(b){return o.go(b)}};return v}function nme(t,e=!1){let n="http://localhost";typeof window<"u"&&(n=window.location.origin!=="null"?window.location.origin:window.location.href),Aa(n,"No window.location.(origin|href) available to create URL");let r=typeof t=="string"?t:Q0(t);return r=r.replace(/ $/,"%20"),!e&&r.startsWith("//")&&(r=n+r),new URL(r,n)}function QY(t,e,n="/"){return rme(t,e,n,!1)}function rme(t,e,n,r){let i=typeof e=="string"?by(e):e,s=pm(i.pathname||"/",n);if(s==null)return null;let o=ZY(t);ame(o);let l=null;for(let c=0;l==null&&c{let u={relativePath:d===void 0?o.path||"":d,caseSensitive:o.caseSensitive===!0,childrenIndex:l,route:o};if(u.relativePath.startsWith("/")){if(!u.relativePath.startsWith(r)&&c)return;Aa(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 m=am([r,u.relativePath]),p=n.concat(u);o.children&&o.children.length>0&&(Aa(o.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${m}".`),ZY(o.children,e,p,m,c)),!(o.path==null&&!o.index)&&e.push({path:m,score:ume(m,o.index),routesMeta:p})};return t.forEach((o,l)=>{if(o.path===""||!o.path?.includes("?"))s(o,l);else for(let c of JY(o.path))s(o,l,!0,c)}),e}function JY(t){let e=t.split("/");if(e.length===0)return[];let[n,...r]=e,i=n.endsWith("?"),s=n.replace(/\?$/,"");if(r.length===0)return i?[s,""]:[s];let o=JY(r.join("/")),l=[];return l.push(...o.map(c=>c===""?s:[s,c].join("/"))),i&&l.push(...o),l.map(c=>t.startsWith("/")&&c===""?"/":c)}function ame(t){t.sort((e,n)=>e.score!==n.score?n.score-e.score:mme(e.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}var ime=/^:[\w-]+$/,sme=3,ome=2,lme=1,cme=10,dme=-2,lH=t=>t==="*";function ume(t,e){let n=t.split("/"),r=n.length;return n.some(lH)&&(r+=dme),e&&(r+=ome),n.filter(i=>!lH(i)).reduce((i,s)=>i+(ime.test(s)?sme:s===""?lme:cme),r)}function mme(t,e){return t.length===e.length&&t.slice(0,-1).every((r,i)=>r===e[i])?t[t.length-1]-e[e.length-1]:0}function hme(t,e,n=!1){let{routesMeta:r}=t,i={},s="/",o=[];for(let l=0;l{if(u==="*"){let x=l[p]||"";o=s.slice(0,s.length-x.length).replace(/(.)\/+$/,"$1")}const f=l[p];return m&&!f?d[u]=void 0:d[u]=(f||"").replace(/%2F/g,"/"),d},{}),pathname:s,pathnameBase:o,pattern:t}}function pme(t,e=!1,n=!0){lc(t==="*"||!t.endsWith("*")||t.endsWith("/*"),`Route path "${t}" will be treated as if it were "${t.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${t.replace(/\*$/,"/*")}".`);let r=[],i="^"+t.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(o,l,c)=>(r.push({paramName:l,isOptional:c!=null}),c?"/?([^\\/]+)?":"/([^\\/]+)")).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return t.endsWith("*")?(r.push({paramName:"*"}),i+=t==="*"||t==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?i+="\\/*$":t!==""&&t!=="/"&&(i+="(?:(?=\\/|$))"),[new RegExp(i,e?void 0:"i"),r]}function fme(t){try{return t.split("/").map(e=>decodeURIComponent(e).replace(/\//g,"%2F")).join("/")}catch(e){return lc(!1,`The URL path "${t}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${e}).`),t}}function pm(t,e){if(e==="/")return t;if(!t.toLowerCase().startsWith(e.toLowerCase()))return null;let n=e.endsWith("/")?e.length-1:e.length,r=t.charAt(n);return r&&r!=="/"?null:t.slice(n)||"/"}var gme=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;function bme(t,e="/"){let{pathname:n,search:r="",hash:i=""}=typeof t=="string"?by(t):t,s;return n?(n=n.replace(/\/\/+/g,"/"),n.startsWith("/")?s=cH(n.substring(1),"/"):s=cH(n,e)):s=e,{pathname:s,search:vme(r),hash:wme(i)}}function cH(t,e){let n=e.replace(/\/+$/,"").split("/");return t.split("/").forEach(i=>{i===".."?n.length>1&&n.pop():i!=="."&&n.push(i)}),n.length>1?n.join("/"):"/"}function SM(t,e,n,r){return`Cannot include a '${t}' character in a manually specified \`to.${e}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${n}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function xme(t){return t.filter((e,n)=>n===0||e.route.path&&e.route.path.length>0)}function dO(t){let e=xme(t);return e.map((n,r)=>r===e.length-1?n.pathname:n.pathnameBase)}function uO(t,e,n,r=!1){let i;typeof t=="string"?i=by(t):(i={...t},Aa(!i.pathname||!i.pathname.includes("?"),SM("?","pathname","search",i)),Aa(!i.pathname||!i.pathname.includes("#"),SM("#","pathname","hash",i)),Aa(!i.search||!i.search.includes("#"),SM("#","search","hash",i)));let s=t===""||i.pathname==="",o=s?"/":i.pathname,l;if(o==null)l=n;else{let m=e.length-1;if(!r&&o.startsWith("..")){let p=o.split("/");for(;p[0]==="..";)p.shift(),m-=1;i.pathname=p.join("/")}l=m>=0?e[m]:"/"}let c=bme(i,l),d=o&&o!=="/"&&o.endsWith("/"),u=(s||o===".")&&n.endsWith("/");return!c.pathname.endsWith("/")&&(d||u)&&(c.pathname+="/"),c}var am=t=>t.join("/").replace(/\/\/+/g,"/"),yme=t=>t.replace(/\/+$/,"").replace(/^\/*/,"/"),vme=t=>!t||t==="?"?"":t.startsWith("?")?t:"?"+t,wme=t=>!t||t==="#"?"":t.startsWith("#")?t:"#"+t,Sme=class{constructor(t,e,n,r=!1){this.status=t,this.statusText=e||"",this.internal=r,n instanceof Error?(this.data=n.toString(),this.error=n):this.data=n}};function _me(t){return t!=null&&typeof t.status=="number"&&typeof t.statusText=="string"&&typeof t.internal=="boolean"&&"data"in t}function kme(t){return t.map(e=>e.route.path).filter(Boolean).join("/").replace(/\/\/*/g,"/")||"/"}var eQ=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function tQ(t,e){let n=t;if(typeof n!="string"||!gme.test(n))return{absoluteURL:void 0,isExternal:!1,to:n};let r=n,i=!1;if(eQ)try{let s=new URL(window.location.href),o=n.startsWith("//")?new URL(s.protocol+n):new URL(n),l=pm(o.pathname,e);o.origin===s.origin&&l!=null?n=l+o.search+o.hash:i=!0}catch{lc(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:i,to:n}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var nQ=["POST","PUT","PATCH","DELETE"];new Set(nQ);var Nme=["GET",...nQ];new Set(Nme);var xy=w.createContext(null);xy.displayName="DataRouter";var OP=w.createContext(null);OP.displayName="DataRouterState";var Cme=w.createContext(!1),rQ=w.createContext({isTransitioning:!1});rQ.displayName="ViewTransition";var Pme=w.createContext(new Map);Pme.displayName="Fetchers";var Tme=w.createContext(null);Tme.displayName="Await";var Sl=w.createContext(null);Sl.displayName="Navigation";var Vw=w.createContext(null);Vw.displayName="Location";var xc=w.createContext({outlet:null,matches:[],isDataRoute:!1});xc.displayName="Route";var mO=w.createContext(null);mO.displayName="RouteError";var aQ="REACT_ROUTER_ERROR",Ame="REDIRECT",jme="ROUTE_ERROR_RESPONSE";function Mme(t){if(t.startsWith(`${aQ}:${Ame}:{`))try{let e=JSON.parse(t.slice(28));if(typeof e=="object"&&e&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.location=="string"&&typeof e.reloadDocument=="boolean"&&typeof e.replace=="boolean")return e}catch{}}function Eme(t){if(t.startsWith(`${aQ}:${jme}:{`))try{let e=JSON.parse(t.slice(40));if(typeof e=="object"&&e&&typeof e.status=="number"&&typeof e.statusText=="string")return new Sme(e.status,e.statusText,e.data)}catch{}}function Dme(t,{relative:e}={}){Aa(yy(),"useHref() may be used only in the context of a component.");let{basename:n,navigator:r}=w.useContext(Sl),{hash:i,pathname:s,search:o}=Ww(t,{relative:e}),l=s;return n!=="/"&&(l=s==="/"?n:am([n,s])),r.createHref({pathname:l,search:o,hash:i})}function yy(){return w.useContext(Vw)!=null}function ed(){return Aa(yy(),"useLocation() may be used only in the context of a component."),w.useContext(Vw).location}var iQ="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function sQ(t){w.useContext(Sl).static||w.useLayoutEffect(t)}function Uo(){let{isDataRoute:t}=w.useContext(xc);return t?Wme():Fme()}function Fme(){Aa(yy(),"useNavigate() may be used only in the context of a component.");let t=w.useContext(xy),{basename:e,navigator:n}=w.useContext(Sl),{matches:r}=w.useContext(xc),{pathname:i}=ed(),s=JSON.stringify(dO(r)),o=w.useRef(!1);return sQ(()=>{o.current=!0}),w.useCallback((c,d={})=>{if(lc(o.current,iQ),!o.current)return;if(typeof c=="number"){n.go(c);return}let u=uO(c,JSON.parse(s),i,d.relative==="path");t==null&&e!=="/"&&(u.pathname=u.pathname==="/"?e:am([e,u.pathname])),(d.replace?n.replace:n.push)(u,d.state,d)},[e,n,s,i,t])}var oQ=w.createContext(null);function vy(){return w.useContext(oQ)}function Rme(t){let e=w.useContext(xc).outlet;return w.useMemo(()=>e&&w.createElement(oQ.Provider,{value:t},e),[e,t])}function Gw(){let{matches:t}=w.useContext(xc),e=t[t.length-1];return e?e.params:{}}function Ww(t,{relative:e}={}){let{matches:n}=w.useContext(xc),{pathname:r}=ed(),i=JSON.stringify(dO(n));return w.useMemo(()=>uO(t,JSON.parse(i),r,e==="path"),[t,i,r,e])}function Lme(t,e){return lQ(t,e)}function lQ(t,e,n,r,i){Aa(yy(),"useRoutes() may be used only in the context of a component.");let{navigator:s}=w.useContext(Sl),{matches:o}=w.useContext(xc),l=o[o.length-1],c=l?l.params:{},d=l?l.pathname:"/",u=l?l.pathnameBase:"/",m=l&&l.route;{let _=m&&m.path||"";dQ(d,!m||_.endsWith("*")||_.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${d}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. -Please change the parent to .`)}let p=ed(),f;if(e){let _=typeof e=="string"?by(e):e;Aa(u==="/"||_.pathname?.startsWith(u),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${u}" but pathname "${_.pathname}" was given in the \`location\` prop.`),f=_}else f=p;let x=f.pathname||"/",v=x;if(u!=="/"){let _=u.replace(/^\//,"").split("/");v="/"+x.replace(/^\//,"").split("/").slice(_.length).join("/")}let b=QY(t,{pathname:v});lc(m||b!=null,`No routes matched location "${f.pathname}${f.search}${f.hash}" `),lc(b==null||b[b.length-1].route.element!==void 0||b[b.length-1].route.Component!==void 0||b[b.length-1].route.lazy!==void 0,`Matched leaf route at location "${f.pathname}${f.search}${f.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let g=Bme(b&&b.map(_=>Object.assign({},_,{params:Object.assign({},c,_.params),pathname:am([u,s.encodeLocation?s.encodeLocation(_.pathname.replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:_.pathname]),pathnameBase:_.pathnameBase==="/"?u:am([u,s.encodeLocation?s.encodeLocation(_.pathnameBase.replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:_.pathnameBase])})),o,n,r,i);return e&&g?w.createElement(Vw.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",...f},navigationType:"POP"}},g):g}function Ome(){let t=Gme(),e=_me(t)?`${t.status} ${t.statusText}`:t instanceof Error?t.message:JSON.stringify(t),n=t instanceof Error?t.stack:null,r="rgba(200,200,200, 0.5)",i={padding:"0.5rem",backgroundColor:r},s={padding:"2px 4px",backgroundColor:r},o=null;return console.error("Error handled by React Router default ErrorBoundary:",t),o=w.createElement(w.Fragment,null,w.createElement("p",null,"💿 Hey developer 👋"),w.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",w.createElement("code",{style:s},"ErrorBoundary")," or"," ",w.createElement("code",{style:s},"errorElement")," prop on your route.")),w.createElement(w.Fragment,null,w.createElement("h2",null,"Unexpected Application Error!"),w.createElement("h3",{style:{fontStyle:"italic"}},e),n?w.createElement("pre",{style:i},n):null,o)}var Ime=w.createElement(Ome,null),cQ=class extends w.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,e){return e.location!==t.location||e.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error!==void 0?t.error:e.error,location:e.location,revalidation:t.revalidation||e.revalidation}}componentDidCatch(t,e){this.props.onError?this.props.onError(t,e):console.error("React Router caught the following error during render",t)}render(){let t=this.state.error;if(this.context&&typeof t=="object"&&t&&"digest"in t&&typeof t.digest=="string"){const n=Eme(t.digest);n&&(t=n)}let e=t!==void 0?w.createElement(xc.Provider,{value:this.props.routeContext},w.createElement(mO.Provider,{value:t,children:this.props.component})):this.props.children;return this.context?w.createElement(zme,{error:t},e):e}};cQ.contextType=Cme;var _M=new WeakMap;function zme({children:t,error:e}){let{basename:n}=w.useContext(Sl);if(typeof e=="object"&&e&&"digest"in e&&typeof e.digest=="string"){let r=Mme(e.digest);if(r){let i=_M.get(e);if(i)throw i;let s=tQ(r.location,n);if(eQ&&!_M.get(e))if(s.isExternal||r.reloadDocument)window.location.href=s.absoluteURL||s.to;else{const o=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(s.to,{replace:r.replace}));throw _M.set(e,o),o}return w.createElement("meta",{httpEquiv:"refresh",content:`0;url=${s.absoluteURL||s.to}`})}}return t}function Ume({routeContext:t,match:e,children:n}){let r=w.useContext(xy);return r&&r.static&&r.staticContext&&(e.route.errorElement||e.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=e.route.id),w.createElement(xc.Provider,{value:t},n)}function Bme(t,e=[],n=null,r=null,i=null){if(t==null){if(!n)return null;if(n.errors)t=n.matches;else if(e.length===0&&!n.initialized&&n.matches.length>0)t=n.matches;else return null}let s=t,o=n?.errors;if(o!=null){let u=s.findIndex(m=>m.route.id&&o?.[m.route.id]!==void 0);Aa(u>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(o).join(",")}`),s=s.slice(0,Math.min(s.length,u+1))}let l=!1,c=-1;if(n)for(let u=0;u=0?s=s.slice(0,c+1):s=[s[0]];break}}}let d=n&&r?(u,m)=>{r(u,{location:n.location,params:n.matches?.[0]?.params??{},unstable_pattern:kme(n.matches),errorInfo:m})}:void 0;return s.reduceRight((u,m,p)=>{let f,x=!1,v=null,b=null;n&&(f=o&&m.route.id?o[m.route.id]:void 0,v=m.route.errorElement||Ime,l&&(c<0&&p===0?(dQ("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),x=!0,b=null):c===p&&(x=!0,b=m.route.hydrateFallbackElement||null)));let g=e.concat(s.slice(0,p+1)),_=()=>{let C;return f?C=v:x?C=b:m.route.Component?C=w.createElement(m.route.Component,null):m.route.element?C=m.route.element:C=u,w.createElement(Ume,{match:m,routeContext:{outlet:u,matches:g,isDataRoute:n!=null},children:C})};return n&&(m.route.ErrorBoundary||m.route.errorElement||p===0)?w.createElement(cQ,{location:n.location,revalidation:n.revalidation,component:v,error:f,children:_(),routeContext:{outlet:null,matches:g,isDataRoute:!0},onError:d}):_()},null)}function hO(t){return`${t} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function Hme(t){let e=w.useContext(xy);return Aa(e,hO(t)),e}function qme(t){let e=w.useContext(OP);return Aa(e,hO(t)),e}function $me(t){let e=w.useContext(xc);return Aa(e,hO(t)),e}function pO(t){let e=$me(t),n=e.matches[e.matches.length-1];return Aa(n.route.id,`${t} can only be used on routes that contain a unique "id"`),n.route.id}function Vme(){return pO("useRouteId")}function Gme(){let t=w.useContext(mO),e=qme("useRouteError"),n=pO("useRouteError");return t!==void 0?t:e.errors?.[n]}function Wme(){let{router:t}=Hme("useNavigate"),e=pO("useNavigate"),n=w.useRef(!1);return sQ(()=>{n.current=!0}),w.useCallback(async(i,s={})=>{lc(n.current,iQ),n.current&&(typeof i=="number"?await t.navigate(i):await t.navigate(i,{fromRouteId:e,...s}))},[t,e])}var dH={};function dQ(t,e,n){!e&&!dH[t]&&(dH[t]=!0,lc(!1,n))}w.memo(Kme);function Kme({routes:t,future:e,state:n,onError:r}){return lQ(t,void 0,n,r,e)}function Bx({to:t,replace:e,state:n,relative:r}){Aa(yy()," may be used only in the context of a component.");let{static:i}=w.useContext(Sl);lc(!i," must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.");let{matches:s}=w.useContext(xc),{pathname:o}=ed(),l=Uo(),c=uO(t,dO(s),o,r==="path"),d=JSON.stringify(c);return w.useEffect(()=>{l(JSON.parse(d),{replace:e,state:n,relative:r})},[l,d,r,e,n]),null}function uQ(t){return Rme(t.context)}function Rr(t){Aa(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function Xme({basename:t="/",children:e=null,location:n,navigationType:r="POP",navigator:i,static:s=!1,unstable_useTransitions:o}){Aa(!yy(),"You cannot render a inside another . You should never have more than one in your app.");let l=t.replace(/^\/*/,"/"),c=w.useMemo(()=>({basename:l,navigator:i,static:s,unstable_useTransitions:o,future:{}}),[l,i,s,o]);typeof n=="string"&&(n=by(n));let{pathname:d="/",search:u="",hash:m="",state:p=null,key:f="default"}=n,x=w.useMemo(()=>{let v=pm(d,l);return v==null?null:{location:{pathname:v,search:u,hash:m,state:p,key:f},navigationType:r}},[l,d,u,m,p,f,r]);return lc(x!=null,` is not able to match the URL "${d}${u}${m}" because it does not start with the basename, so the won't render anything.`),x==null?null:w.createElement(Sl.Provider,{value:c},w.createElement(Vw.Provider,{children:e,value:x}))}function Yme({children:t,location:e}){return Lme(q3(t),e)}function q3(t,e=[]){let n=[];return w.Children.forEach(t,(r,i)=>{if(!w.isValidElement(r))return;let s=[...e,i];if(r.type===w.Fragment){n.push.apply(n,q3(r.props.children,s));return}Aa(r.type===Rr,`[${typeof r.type=="string"?r.type:r.type.name}] is not a component. All component children of must be a or `),Aa(!r.props.index||!r.props.children,"An index route cannot have child routes.");let o={id:r.props.id||s.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,middleware:r.props.middleware,loader:r.props.loader,action:r.props.action,hydrateFallbackElement:r.props.hydrateFallbackElement,HydrateFallback:r.props.HydrateFallback,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.hasErrorBoundary===!0||r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(o.children=q3(r.props.children,s)),n.push(o)}),n}var Rk="get",Lk="application/x-www-form-urlencoded";function IP(t){return typeof HTMLElement<"u"&&t instanceof HTMLElement}function Qme(t){return IP(t)&&t.tagName.toLowerCase()==="button"}function Zme(t){return IP(t)&&t.tagName.toLowerCase()==="form"}function Jme(t){return IP(t)&&t.tagName.toLowerCase()==="input"}function ehe(t){return!!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)}function the(t,e){return t.button===0&&(!e||e==="_self")&&!ehe(t)}function $3(t=""){return new URLSearchParams(typeof t=="string"||Array.isArray(t)||t instanceof URLSearchParams?t:Object.keys(t).reduce((e,n)=>{let r=t[n];return e.concat(Array.isArray(r)?r.map(i=>[n,i]):[[n,r]])},[]))}function nhe(t,e){let n=$3(t);return e&&e.forEach((r,i)=>{n.has(i)||e.getAll(i).forEach(s=>{n.append(i,s)})}),n}var G_=null;function rhe(){if(G_===null)try{new FormData(document.createElement("form"),0),G_=!1}catch{G_=!0}return G_}var ahe=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function kM(t){return t!=null&&!ahe.has(t)?(lc(!1,`"${t}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${Lk}"`),null):t}function ihe(t,e){let n,r,i,s,o;if(Zme(t)){let l=t.getAttribute("action");r=l?pm(l,e):null,n=t.getAttribute("method")||Rk,i=kM(t.getAttribute("enctype"))||Lk,s=new FormData(t)}else if(Qme(t)||Jme(t)&&(t.type==="submit"||t.type==="image")){let l=t.form;if(l==null)throw new Error('Cannot submit a