From d777e3a48e74ba28e3b20dc387e4ca3eff7d5068 Mon Sep 17 00:00:00 2001 From: legop3 Date: Fri, 10 Jul 2026 23:20:09 -0400 Subject: [PATCH] ptzwawa --- server/config.example.yaml | 13 + server/index.js | 1 + server/package.json | 2 + server/public/assets/index-BFbU1lYU.js | 148 ++++ server/public/assets/index-BFbU1lYU.js.map | 1 + server/public/assets/index-BfZ_TWsb.css | 1 - server/public/assets/index-DwpUkSbG.css | 1 + server/public/assets/index-htN8tzuK.js | 148 ---- server/public/assets/index-htN8tzuK.js.map | 1 - server/public/index.html | 4 +- server/src/helpers/features.js | 7 + server/src/services/ptzCameraService/index.js | 665 ++++++++++++++++++ .../services/replayEngineV2/replaySources.js | 11 +- .../services/replayEngineV2/segmentStore.js | 3 + server/src/services/replayEngineV2/sources.js | 3 + server/src/services/roverManager/index.js | 2 + .../services/roverManager/roverLifecycle.js | 25 +- server/src/services/sessionService/index.js | 7 + server/src/services/videoAuthService/index.js | 2 + .../src/services/videoAuthService/policy.js | 5 + .../videoAuthService/streamParsing.js | 4 + .../src/services/videoSocketService/index.js | 13 + webui/src/components/VipPanel/index.jsx | 2 + webui/src/components/vip/VipPtzCameraCard.jsx | 369 ++++++++++ webui/src/context/SessionContext.jsx | 6 + webui/src/hooks/usePtzCameraSnapshot.js | 74 ++ webui/src/hooks/useVideoRequests.js | 7 +- 27 files changed, 1363 insertions(+), 162 deletions(-) create mode 100644 server/public/assets/index-BFbU1lYU.js create mode 100644 server/public/assets/index-BFbU1lYU.js.map delete mode 100644 server/public/assets/index-BfZ_TWsb.css create mode 100644 server/public/assets/index-DwpUkSbG.css delete mode 100644 server/public/assets/index-htN8tzuK.js delete mode 100644 server/public/assets/index-htN8tzuK.js.map create mode 100644 server/src/services/ptzCameraService/index.js create mode 100644 webui/src/components/vip/VipPtzCameraCard.jsx create mode 100644 webui/src/hooks/usePtzCameraSnapshot.js diff --git a/server/config.example.yaml b/server/config.example.yaml index fefc2631..1abe162f 100644 --- a/server/config.example.yaml +++ b/server/config.example.yaml @@ -128,6 +128,19 @@ roomCameras: url: "http://192.168.0.51/snapshot.jpg" streamUrl: "http://192.168.0.51/stream.mjpg" +ptzCamera: + enabled: false + name: "PTZ Camera" + host: "192.168.0.8" + onvifPort: 8000 + username: "admin" + password: "REPLACE_WITH_CAMERA_PASSWORD" + # The Reolink TrackMix autotrack profile was token 003 during commissioning. + # Keeping this configurable lets firmware/profile resets be fixed without code + # changes while the integration still remains a single-camera feature. + profileToken: "003" + turnDurationMs: 300000 + kinect: enabled: false # Capture requests are global across 3d/color so one person cannot spam room diff --git a/server/index.js b/server/index.js index e2f8a7ec..a3926ce2 100644 --- a/server/index.js +++ b/server/index.js @@ -26,6 +26,7 @@ require('./src/services/overseerControlService'); require('./src/services/globalObjectiveService'); require('./src/services/serverControlService'); require('./src/services/videoSessions'); +require('./src/services/ptzCameraService'); require('./src/services/videoAuthService'); require('./src/services/videoSocketService'); require('./src/services/roomCameraService'); diff --git a/server/package.json b/server/package.json index 77f129c9..056c60fd 100644 --- a/server/package.json +++ b/server/package.json @@ -19,6 +19,8 @@ "morgan": "^1.10.0", "obscenity": "^0.4.6", "ollama": "^0.6.3", + "onvif": "^0.8.1", + "reolink-nvr-api": "^0.3.0", "sharp": "^0.33.5", "socket.io": "^4.7.5", "uuid": "^9.0.1", diff --git a/server/public/assets/index-BFbU1lYU.js b/server/public/assets/index-BFbU1lYU.js new file mode 100644 index 00000000..3e472324 --- /dev/null +++ b/server/public/assets/index-BFbU1lYU.js @@ -0,0 +1,148 @@ +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/OrbitControls-BJ-UXxdt.js","assets/three.module--MGUDD-H.js"])))=>i.map(i=>d[i]); +(function(){const c=document.createElement("link").relList;if(c&&c.supports&&c.supports("modulepreload"))return;for(const u of document.querySelectorAll('link[rel="modulepreload"]'))i(u);new MutationObserver(u=>{for(const h of u)if(h.type==="childList")for(const d of h.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&i(d)}).observe(document,{childList:!0,subtree:!0});function n(u){const h={};return u.integrity&&(h.integrity=u.integrity),u.referrerPolicy&&(h.referrerPolicy=u.referrerPolicy),u.crossOrigin==="use-credentials"?h.credentials="include":u.crossOrigin==="anonymous"?h.credentials="omit":h.credentials="same-origin",h}function i(u){if(u.ep)return;u.ep=!0;const h=n(u);fetch(u.href,h)}})();function yv(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var J9={exports:{}},j8={};var rs;function Mv(){if(rs)return j8;rs=1;var t=Symbol.for("react.transitional.element"),c=Symbol.for("react.fragment");function n(i,u,h){var d=null;if(h!==void 0&&(d=""+h),u.key!==void 0&&(d=""+u.key),"key"in u){h={};for(var v in u)v!=="key"&&(h[v]=u[v])}else h=u;return u=h.ref,{$$typeof:t,type:i,key:d,ref:u!==void 0?u:null,props:h}}return j8.Fragment=c,j8.jsx=n,j8.jsxs=n,j8}var ls;function wv(){return ls||(ls=1,J9.exports=Mv()),J9.exports}var r=wv(),tc={exports:{}},$1={};var is;function Cv(){if(is)return $1;is=1;var t=Symbol.for("react.transitional.element"),c=Symbol.for("react.portal"),n=Symbol.for("react.fragment"),i=Symbol.for("react.strict_mode"),u=Symbol.for("react.profiler"),h=Symbol.for("react.consumer"),d=Symbol.for("react.context"),v=Symbol.for("react.forward_ref"),p=Symbol.for("react.suspense"),x=Symbol.for("react.memo"),g=Symbol.for("react.lazy"),b=Symbol.for("react.activity"),y=Symbol.iterator;function M(R){return R===null||typeof R!="object"?null:(R=y&&R[y]||R["@@iterator"],typeof R=="function"?R:null)}var L={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},S=Object.assign,C={};function V(R,D,Q){this.props=R,this.context=D,this.refs=C,this.updater=Q||L}V.prototype.isReactComponent={},V.prototype.setState=function(R,D){if(typeof R!="object"&&typeof R!="function"&&R!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,R,D,"setState")},V.prototype.forceUpdate=function(R){this.updater.enqueueForceUpdate(this,R,"forceUpdate")};function A(){}A.prototype=V.prototype;function H(R,D,Q){this.props=R,this.context=D,this.refs=C,this.updater=Q||L}var j=H.prototype=new A;j.constructor=H,S(j,V.prototype),j.isPureReactComponent=!0;var T=Array.isArray;function N(){}var E={H:null,A:null,T:null,S:null},B=Object.prototype.hasOwnProperty;function F(R,D,Q){var s1=Q.ref;return{$$typeof:t,type:R,key:D,ref:s1!==void 0?s1:null,props:Q}}function q(R,D){return F(R.type,D,R.props)}function Z(R){return typeof R=="object"&&R!==null&&R.$$typeof===t}function O(R){var D={"=":"=0",":":"=2"};return"$"+R.replace(/[=:]/g,function(Q){return D[Q]})}var e1=/\/+/g;function l1(R,D){return typeof R=="object"&&R!==null&&R.key!=null?O(""+R.key):D.toString(36)}function Y(R){switch(R.status){case"fulfilled":return R.value;case"rejected":throw R.reason;default:switch(typeof R.status=="string"?R.then(N,N):(R.status="pending",R.then(function(D){R.status==="pending"&&(R.status="fulfilled",R.value=D)},function(D){R.status==="pending"&&(R.status="rejected",R.reason=D)})),R.status){case"fulfilled":return R.value;case"rejected":throw R.reason}}throw R}function _(R,D,Q,s1,m1){var v1=typeof R;(v1==="undefined"||v1==="boolean")&&(R=null);var H1=!1;if(R===null)H1=!0;else switch(v1){case"bigint":case"string":case"number":H1=!0;break;case"object":switch(R.$$typeof){case t:case c:H1=!0;break;case g:return H1=R._init,_(H1(R._payload),D,Q,s1,m1)}}if(H1)return m1=m1(R),H1=s1===""?"."+l1(R,0):s1,T(m1)?(Q="",H1!=null&&(Q=H1.replace(e1,"$&/")+"/"),_(m1,D,Q,"",function(T1){return T1})):m1!=null&&(Z(m1)&&(m1=q(m1,Q+(m1.key==null||R&&R.key===m1.key?"":(""+m1.key).replace(e1,"$&/")+"/")+H1)),D.push(m1)),1;H1=0;var N1=s1===""?".":s1+":";if(T(R))for(var F1=0;F1>>1,K=_[X];if(0>>1;Xu(Q,I))s1u(m1,Q)?(_[X]=m1,_[s1]=I,X=s1):(_[X]=Q,_[D]=I,X=D);else if(s1u(m1,I))_[X]=m1,_[s1]=I,X=s1;else break t}}return P}function u(_,P){var I=_.sortIndex-P.sortIndex;return I!==0?I:_.id-P.id}if(t.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var h=performance;t.unstable_now=function(){return h.now()}}else{var d=Date,v=d.now();t.unstable_now=function(){return d.now()-v}}var p=[],x=[],g=1,b=null,y=3,M=!1,L=!1,S=!1,C=!1,V=typeof setTimeout=="function"?setTimeout:null,A=typeof clearTimeout=="function"?clearTimeout:null,H=typeof setImmediate<"u"?setImmediate:null;function j(_){for(var P=n(x);P!==null;){if(P.callback===null)i(x);else if(P.startTime<=_)i(x),P.sortIndex=P.expirationTime,c(p,P);else break;P=n(x)}}function T(_){if(S=!1,j(_),!L)if(n(p)!==null)L=!0,N||(N=!0,O());else{var P=n(x);P!==null&&Y(T,P.startTime-_)}}var N=!1,E=-1,B=5,F=-1;function q(){return C?!0:!(t.unstable_now()-F_&&q());){var X=b.callback;if(typeof X=="function"){b.callback=null,y=b.priorityLevel;var K=X(b.expirationTime<=_);if(_=t.unstable_now(),typeof K=="function"){b.callback=K,j(_),P=!0;break e}b===n(p)&&i(p),j(_)}else i(p);b=n(p)}if(b!==null)P=!0;else{var R=n(x);R!==null&&Y(T,R.startTime-_),P=!1}}break t}finally{b=null,y=I,M=!1}P=void 0}}finally{P?O():N=!1}}}var O;if(typeof H=="function")O=function(){H(Z)};else if(typeof MessageChannel<"u"){var e1=new MessageChannel,l1=e1.port2;e1.port1.onmessage=Z,O=function(){l1.postMessage(null)}}else O=function(){V(Z,0)};function Y(_,P){E=V(function(){_(t.unstable_now())},P)}t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(_){_.callback=null},t.unstable_forceFrameRate=function(_){0>_||125<_?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):B=0<_?Math.floor(1e3/_):5},t.unstable_getCurrentPriorityLevel=function(){return y},t.unstable_next=function(_){switch(y){case 1:case 2:case 3:var P=3;break;default:P=y}var I=y;y=P;try{return _()}finally{y=I}},t.unstable_requestPaint=function(){C=!0},t.unstable_runWithPriority=function(_,P){switch(_){case 1:case 2:case 3:case 4:case 5:break;default:_=3}var I=y;y=_;try{return P()}finally{y=I}},t.unstable_scheduleCallback=function(_,P,I){var X=t.unstable_now();switch(typeof I=="object"&&I!==null?(I=I.delay,I=typeof I=="number"&&0X?(_.sortIndex=I,c(x,_),n(p)===null&&_===n(x)&&(S?(A(E),E=-1):S=!0,Y(T,I-X))):(_.sortIndex=K,c(p,_),L||M||(L=!0,N||(N=!0,O()))),_},t.unstable_shouldYield=q,t.unstable_wrapCallback=function(_){var P=y;return function(){var I=y;y=P;try{return _.apply(this,arguments)}finally{y=I}}}})(ac)),ac}var us;function Hv(){return us||(us=1,cc.exports=Sv()),cc.exports}var nc={exports:{}},J2={};var hs;function Av(){if(hs)return J2;hs=1;var t=ya();function c(p){var x="https://react.dev/errors/"+p;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(c){console.error(c)}}return t(),nc.exports=Av(),nc.exports}var fs;function Lv(){if(fs)return N8;fs=1;var t=Hv(),c=ya(),n=pu();function i(e){var a="https://react.dev/errors/"+e;if(1K||(e.current=X[K],X[K]=null,K--)}function Q(e,a){K++,X[K]=e.current,e.current=a}var s1=R(null),m1=R(null),v1=R(null),H1=R(null);function N1(e,a){switch(Q(v1,a),Q(m1,e),Q(s1,null),a.nodeType){case 9:case 11:e=(e=a.documentElement)&&(e=e.namespaceURI)?Li(e):0;break;default:if(e=a.tagName,a=a.namespaceURI)a=Li(a),e=Vi(a,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}D(s1),Q(s1,e)}function F1(){D(s1),D(m1),D(v1)}function T1(e){e.memoizedState!==null&&Q(H1,e);var a=s1.current,l=Vi(a,e.type);a!==l&&(Q(m1,e),Q(s1,l))}function Q1(e){m1.current===e&&(D(s1),D(m1)),H1.current===e&&(D(H1),A8._currentValue=I)}var I1,r2;function i1(e){if(I1===void 0)try{throw Error()}catch(l){var a=l.stack.trim().match(/\n( *(at )?)/);I1=a&&a[1]||"",r2=-1)":-1m||U[o]!==J[m]){var o1=` +`+U[o].replace(" at new "," at ");return e.displayName&&o1.includes("")&&(o1=o1.replace("",e.displayName)),o1}while(1<=o&&0<=m);break}}}finally{A1=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?i1(l):""}function _1(e,a){switch(e.tag){case 26:case 27:case 5:return i1(e.type);case 16:return i1("Lazy");case 13:return e.child!==a&&a!==null?i1("Suspense Fallback"):i1("Suspense");case 19:return i1("SuspenseList");case 0:case 15:return P1(e.type,!1);case 11:return P1(e.type.render,!1);case 1:return P1(e.type,!0);case 31:return i1("Activity");default:return""}}function z1(e){try{var a="",l=null;do a+=_1(e,l),l=e,e=e.return;while(e);return a}catch(o){return` +Error generating stack: `+o.message+` +`+o.stack}}var C1=Object.prototype.hasOwnProperty,x1=t.unstable_scheduleCallback,S1=t.unstable_cancelCallback,g1=t.unstable_shouldYield,R1=t.unstable_requestPaint,n1=t.unstable_now,y1=t.unstable_getCurrentPriorityLevel,M1=t.unstable_ImmediatePriority,j1=t.unstable_UserBlockingPriority,K1=t.unstable_NormalPriority,N2=t.unstable_LowPriority,J1=t.unstable_IdlePriority,p1=t.log,c1=t.unstable_setDisableYieldValue,d1=null,w1=null;function D1(e){if(typeof p1=="function"&&c1(e),w1&&typeof w1.setStrictMode=="function")try{w1.setStrictMode(d1,e)}catch{}}var b1=Math.clz32?Math.clz32:t2,O1=Math.log,o2=Math.LN2;function t2(e){return e>>>=0,e===0?32:31-(O1(e)/o2|0)|0}var e2=256,I2=262144,W2=4194304;function P2(e){var a=e&42;if(a!==0)return a;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64: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 e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function w2(e,a,l){var o=e.pendingLanes;if(o===0)return 0;var m=0,z=e.suspendedLanes,w=e.pingedLanes;e=e.warmLanes;var k=o&134217727;return k!==0?(o=k&~z,o!==0?m=P2(o):(w&=k,w!==0?m=P2(w):l||(l=k&~e,l!==0&&(m=P2(l))))):(k=o&~z,k!==0?m=P2(k):w!==0?m=P2(w):l||(l=o&~e,l!==0&&(m=P2(l)))),m===0?0:a!==0&&a!==m&&(a&z)===0&&(z=m&-m,l=a&-a,z>=l||z===32&&(l&4194048)!==0)?a:m}function R4(e,a){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&a)===0}function sf(e,a){switch(e){case 1:case 2:case 4:case 8:case 64:return a+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 a+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 on(){var e=W2;return W2<<=1,(W2&62914560)===0&&(W2=4194304),e}function Oe(e){for(var a=[],l=0;31>l;l++)a.push(e);return a}function O0(e,a){e.pendingLanes|=a,a!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function of(e,a,l,o,m,z){var w=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var k=e.entanglements,U=e.expirationTimes,J=e.hiddenUpdates;for(l=w&~l;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var vf=/[\n"\\]/g;function z4(e){return e.replace(vf,function(a){return"\\"+a.charCodeAt(0).toString(16)+" "})}function Ge(e,a,l,o,m,z,w,k){e.name="",w!=null&&typeof w!="function"&&typeof w!="symbol"&&typeof w!="boolean"?e.type=w:e.removeAttribute("type"),a!=null?w==="number"?(a===0&&e.value===""||e.value!=a)&&(e.value=""+x4(a)):e.value!==""+x4(a)&&(e.value=""+x4(a)):w!=="submit"&&w!=="reset"||e.removeAttribute("value"),a!=null?Ye(e,w,x4(a)):l!=null?Ye(e,w,x4(l)):o!=null&&e.removeAttribute("value"),m==null&&z!=null&&(e.defaultChecked=!!z),m!=null&&(e.checked=m&&typeof m!="function"&&typeof m!="symbol"),k!=null&&typeof k!="function"&&typeof k!="symbol"&&typeof k!="boolean"?e.name=""+x4(k):e.removeAttribute("name")}function Mn(e,a,l,o,m,z,w,k){if(z!=null&&typeof z!="function"&&typeof z!="symbol"&&typeof z!="boolean"&&(e.type=z),a!=null||l!=null){if(!(z!=="submit"&&z!=="reset"||a!=null)){Ze(e);return}l=l!=null?""+x4(l):"",a=a!=null?""+x4(a):l,k||a===e.value||(e.value=a),e.defaultValue=a}o=o??m,o=typeof o!="function"&&typeof o!="symbol"&&!!o,e.checked=k?e.checked:!!o,e.defaultChecked=!!o,w!=null&&typeof w!="function"&&typeof w!="symbol"&&typeof w!="boolean"&&(e.name=w),Ze(e)}function Ye(e,a,l){a==="number"&&p5(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function E6(e,a,l,o){if(e=e.options,a){a={};for(var m=0;m"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Je=!1;if(J4)try{var $0={};Object.defineProperty($0,"passive",{get:function(){Je=!0}}),window.addEventListener("test",$0,$0),window.removeEventListener("test",$0,$0)}catch{Je=!1}var w3=null,t7=null,x5=null;function Vn(){if(x5)return x5;var e,a=t7,l=a.length,o,m="value"in w3?w3.value:w3.textContent,z=m.length;for(e=0;e=Y0),Rn=" ",En=!1;function Tn(e,a){switch(e){case"keyup":return If.indexOf(a.keyCode)!==-1;case"keydown":return a.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function _n(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var D6=!1;function $f(e,a){switch(e){case"compositionend":return _n(a);case"keypress":return a.which!==32?null:(En=!0,Rn);case"textInput":return e=a.data,e===Rn&&En?null:e;default:return null}}function Zf(e,a){if(D6)return e==="compositionend"||!r7&&Tn(e,a)?(e=Vn(),x5=t7=w3=null,D6=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(a.ctrlKey||a.altKey||a.metaKey)||a.ctrlKey&&a.altKey){if(a.char&&1=a)return{node:l,offset:a-e};e=o}t:{for(;l;){if(l.nextSibling){l=l.nextSibling;break t}l=l.parentNode}l=void 0}l=Zn(l)}}function Yn(e,a){return e&&a?e===a?!0:e&&e.nodeType===3?!1:a&&a.nodeType===3?Yn(e,a.parentNode):"contains"in e?e.contains(a):e.compareDocumentPosition?!!(e.compareDocumentPosition(a)&16):!1:!1}function Kn(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var a=p5(e.document);a instanceof e.HTMLIFrameElement;){try{var l=typeof a.contentWindow.location.href=="string"}catch{l=!1}if(l)e=a.contentWindow;else break;a=p5(e.document)}return a}function s7(e){var a=e&&e.nodeName&&e.nodeName.toLowerCase();return a&&(a==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||a==="textarea"||e.contentEditable==="true")}var tm=J4&&"documentMode"in document&&11>=document.documentMode,O6=null,o7=null,W0=null,u7=!1;function Qn(e,a,l){var o=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;u7||O6==null||O6!==p5(o)||(o=O6,"selectionStart"in o&&s7(o)?o={start:o.selectionStart,end:o.selectionEnd}:(o=(o.ownerDocument&&o.ownerDocument.defaultView||window).getSelection(),o={anchorNode:o.anchorNode,anchorOffset:o.anchorOffset,focusNode:o.focusNode,focusOffset:o.focusOffset}),W0&&X0(W0,o)||(W0=o,o=ht(o7,"onSelect"),0>=w,m-=w,I4=1<<32-b1(a)+m|l<G1?(a2=B1,B1=null):a2=B1.sibling;var i2=t1(G,B1,W[G1],u1);if(i2===null){B1===null&&(B1=a2);break}e&&B1&&i2.alternate===null&&a(G,B1),$=z(i2,$,G1),l2===null?k1=i2:l2.sibling=i2,l2=i2,B1=a2}if(G1===W.length)return l(G,B1),n2&&e3(G,G1),k1;if(B1===null){for(;G1G1?(a2=B1,B1=null):a2=B1.sibling;var $3=t1(G,B1,i2.value,u1);if($3===null){B1===null&&(B1=a2);break}e&&B1&&$3.alternate===null&&a(G,B1),$=z($3,$,G1),l2===null?k1=$3:l2.sibling=$3,l2=$3,B1=a2}if(i2.done)return l(G,B1),n2&&e3(G,G1),k1;if(B1===null){for(;!i2.done;G1++,i2=W.next())i2=h1(G,i2.value,u1),i2!==null&&($=z(i2,$,G1),l2===null?k1=i2:l2.sibling=i2,l2=i2);return n2&&e3(G,G1),k1}for(B1=o(B1);!i2.done;G1++,i2=W.next())i2=a1(B1,G,G1,i2.value,u1),i2!==null&&(e&&i2.alternate!==null&&B1.delete(i2.key===null?G1:i2.key),$=z(i2,$,G1),l2===null?k1=i2:l2.sibling=i2,l2=i2);return e&&B1.forEach(function(bv){return a(G,bv)}),n2&&e3(G,G1),k1}function v2(G,$,W,u1){if(typeof W=="object"&&W!==null&&W.type===S&&W.key===null&&(W=W.props.children),typeof W=="object"&&W!==null){switch(W.$$typeof){case M:t:{for(var k1=W.key;$!==null;){if($.key===k1){if(k1=W.type,k1===S){if($.tag===7){l(G,$.sibling),u1=m($,W.props.children),u1.return=G,G=u1;break t}}else if($.elementType===k1||typeof k1=="object"&&k1!==null&&k1.$$typeof===B&&s6(k1)===$.type){l(G,$.sibling),u1=m($,W.props),n8(u1,W),u1.return=G,G=u1;break t}l(G,$);break}else a(G,$);$=$.sibling}W.type===S?(u1=a6(W.props.children,G.mode,u1,W.key),u1.return=G,G=u1):(u1=L5(W.type,W.key,W.props,null,G.mode,u1),n8(u1,W),u1.return=G,G=u1)}return w(G);case L:t:{for(k1=W.key;$!==null;){if($.key===k1)if($.tag===4&&$.stateNode.containerInfo===W.containerInfo&&$.stateNode.implementation===W.implementation){l(G,$.sibling),u1=m($,W.children||[]),u1.return=G,G=u1;break t}else{l(G,$);break}else a(G,$);$=$.sibling}u1=g7(W,G.mode,u1),u1.return=G,G=u1}return w(G);case B:return W=s6(W),v2(G,$,W,u1)}if(Y(W))return L1(G,$,W,u1);if(O(W)){if(k1=O(W),typeof k1!="function")throw Error(i(150));return W=k1.call(W),E1(G,$,W,u1)}if(typeof W.then=="function")return v2(G,$,R5(W),u1);if(W.$$typeof===H)return v2(G,$,j5(G,W),u1);E5(G,W)}return typeof W=="string"&&W!==""||typeof W=="number"||typeof W=="bigint"?(W=""+W,$!==null&&$.tag===6?(l(G,$.sibling),u1=m($,W),u1.return=G,G=u1):(l(G,$),u1=p7(W,G.mode,u1),u1.return=G,G=u1),w(G)):l(G,$)}return function(G,$,W,u1){try{a8=0;var k1=v2(G,$,W,u1);return W6=null,k1}catch(B1){if(B1===X6||B1===k5)throw B1;var l2=h4(29,B1,null,G.mode);return l2.lanes=u1,l2.return=G,l2}finally{}}}var u6=zr(!0),br=zr(!1),L3=!1;function V7(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function B7(e,a){e=e.updateQueue,a.updateQueue===e&&(a.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function V3(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function B3(e,a,l){var o=e.updateQueue;if(o===null)return null;if(o=o.shared,(u2&2)!==0){var m=o.pending;return m===null?a.next=a:(a.next=m.next,m.next=a),o.pending=a,a=A5(e),ar(e,null,l),a}return H5(e,o,a,l),A5(e)}function r8(e,a,l){if(a=a.updateQueue,a!==null&&(a=a.shared,(l&4194048)!==0)){var o=a.lanes;o&=e.pendingLanes,l|=o,a.lanes=l,hn(e,l)}}function j7(e,a){var l=e.updateQueue,o=e.alternate;if(o!==null&&(o=o.updateQueue,l===o)){var m=null,z=null;if(l=l.firstBaseUpdate,l!==null){do{var w={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};z===null?m=z=w:z=z.next=w,l=l.next}while(l!==null);z===null?m=z=a:z=z.next=a}else m=z=a;l={baseState:o.baseState,firstBaseUpdate:m,lastBaseUpdate:z,shared:o.shared,callbacks:o.callbacks},e.updateQueue=l;return}e=l.lastBaseUpdate,e===null?l.firstBaseUpdate=a:e.next=a,l.lastBaseUpdate=a}var N7=!1;function l8(){if(N7){var e=Q6;if(e!==null)throw e}}function i8(e,a,l,o){N7=!1;var m=e.updateQueue;L3=!1;var z=m.firstBaseUpdate,w=m.lastBaseUpdate,k=m.shared.pending;if(k!==null){m.shared.pending=null;var U=k,J=U.next;U.next=null,w===null?z=J:w.next=J,w=U;var o1=e.alternate;o1!==null&&(o1=o1.updateQueue,k=o1.lastBaseUpdate,k!==w&&(k===null?o1.firstBaseUpdate=J:k.next=J,o1.lastBaseUpdate=U))}if(z!==null){var h1=m.baseState;w=0,o1=J=U=null,k=z;do{var t1=k.lane&-536870913,a1=t1!==k.lane;if(a1?(c2&t1)===t1:(o&t1)===t1){t1!==0&&t1===K6&&(N7=!0),o1!==null&&(o1=o1.next={lane:0,tag:k.tag,payload:k.payload,callback:null,next:null});t:{var L1=e,E1=k;t1=a;var v2=l;switch(E1.tag){case 1:if(L1=E1.payload,typeof L1=="function"){h1=L1.call(v2,h1,t1);break t}h1=L1;break t;case 3:L1.flags=L1.flags&-65537|128;case 0:if(L1=E1.payload,t1=typeof L1=="function"?L1.call(v2,h1,t1):L1,t1==null)break t;h1=b({},h1,t1);break t;case 2:L3=!0}}t1=k.callback,t1!==null&&(e.flags|=64,a1&&(e.flags|=8192),a1=m.callbacks,a1===null?m.callbacks=[t1]:a1.push(t1))}else a1={lane:t1,tag:k.tag,payload:k.payload,callback:k.callback,next:null},o1===null?(J=o1=a1,U=h1):o1=o1.next=a1,w|=t1;if(k=k.next,k===null){if(k=m.shared.pending,k===null)break;a1=k,k=a1.next,a1.next=null,m.lastBaseUpdate=a1,m.shared.pending=null}}while(!0);o1===null&&(U=h1),m.baseState=U,m.firstBaseUpdate=J,m.lastBaseUpdate=o1,z===null&&(m.shared.lanes=0),R3|=w,e.lanes=w,e.memoizedState=h1}}function yr(e,a){if(typeof e!="function")throw Error(i(191,e));e.call(a)}function Mr(e,a){var l=e.callbacks;if(l!==null)for(e.callbacks=null,e=0;ez?z:8;var w=_.T,k={};_.T=k,X7(e,!1,a,l);try{var U=m(),J=_.S;if(J!==null&&J(k,U),U!==null&&typeof U=="object"&&typeof U.then=="function"){var o1=om(U,o);u8(e,a,o1,p4(e))}else u8(e,a,o,p4(e))}catch(h1){u8(e,a,{then:function(){},status:"rejected",reason:h1},p4())}finally{P.p=z,w!==null&&k.types!==null&&(w.types=k.types),_.T=w}}function vm(){}function K7(e,a,l,o){if(e.tag!==5)throw Error(i(476));var m=tl(e).queue;Jr(e,m,a,I,l===null?vm:function(){return el(e),l(o)})}function tl(e){var a=e.memoizedState;if(a!==null)return a;a={memoizedState:I,baseState:I,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:r3,lastRenderedState:I},next:null};var l={};return a.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:r3,lastRenderedState:l},next:null},e.memoizedState=a,e=e.alternate,e!==null&&(e.memoizedState=a),a}function el(e){var a=tl(e);a.next===null&&(a=e.alternate.memoizedState),u8(e,a.next.queue,{},p4())}function Q7(){return K2(A8)}function cl(){return B2().memoizedState}function al(){return B2().memoizedState}function pm(e){for(var a=e.return;a!==null;){switch(a.tag){case 24:case 3:var l=p4();e=V3(l);var o=B3(a,e,l);o!==null&&(s4(o,a,l),r8(o,a,l)),a={cache:S7()},e.payload=a;return}a=a.return}}function gm(e,a,l){var o=p4();l={lane:o,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},Z5(e)?rl(a,l):(l=m7(e,a,l,o),l!==null&&(s4(l,e,o),ll(l,a,o)))}function nl(e,a,l){var o=p4();u8(e,a,l,o)}function u8(e,a,l,o){var m={lane:o,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(Z5(e))rl(a,m);else{var z=e.alternate;if(e.lanes===0&&(z===null||z.lanes===0)&&(z=a.lastRenderedReducer,z!==null))try{var w=a.lastRenderedState,k=z(w,l);if(m.hasEagerState=!0,m.eagerState=k,u4(k,w))return H5(e,a,m,0),p2===null&&S5(),!1}catch{}finally{}if(l=m7(e,a,m,o),l!==null)return s4(l,e,o),ll(l,a,o),!0}return!1}function X7(e,a,l,o){if(o={lane:2,revertLane:V9(),gesture:null,action:o,hasEagerState:!1,eagerState:null,next:null},Z5(e)){if(a)throw Error(i(479))}else a=m7(e,l,o,2),a!==null&&s4(a,e,2)}function Z5(e){var a=e.alternate;return e===Z1||a!==null&&a===Z1}function rl(e,a){t0=q5=!0;var l=e.pending;l===null?a.next=a:(a.next=l.next,l.next=a),e.pending=a}function ll(e,a,l){if((l&4194048)!==0){var o=a.lanes;o&=e.pendingLanes,l|=o,a.lanes=l,hn(e,l)}}var h8={readContext:K2,use:U5,useCallback:C2,useContext:C2,useEffect:C2,useImperativeHandle:C2,useLayoutEffect:C2,useInsertionEffect:C2,useMemo:C2,useReducer:C2,useRef:C2,useState:C2,useDebugValue:C2,useDeferredValue:C2,useTransition:C2,useSyncExternalStore:C2,useId:C2,useHostTransitionStatus:C2,useFormState:C2,useActionState:C2,useOptimistic:C2,useMemoCache:C2,useCacheRefresh:C2};h8.useEffectEvent=C2;var il={readContext:K2,use:U5,useCallback:function(e,a){return e4().memoizedState=[e,a===void 0?null:a],e},useContext:K2,useEffect:Pr,useImperativeHandle:function(e,a,l){l=l!=null?l.concat([e]):null,P5(4194308,4,Yr.bind(null,a,e),l)},useLayoutEffect:function(e,a){return P5(4194308,4,e,a)},useInsertionEffect:function(e,a){P5(4,2,e,a)},useMemo:function(e,a){var l=e4();a=a===void 0?null:a;var o=e();if(h6){D1(!0);try{e()}finally{D1(!1)}}return l.memoizedState=[o,a],o},useReducer:function(e,a,l){var o=e4();if(l!==void 0){var m=l(a);if(h6){D1(!0);try{l(a)}finally{D1(!1)}}}else m=a;return o.memoizedState=o.baseState=m,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:m},o.queue=e,e=e.dispatch=gm.bind(null,Z1,e),[o.memoizedState,e]},useRef:function(e){var a=e4();return e={current:e},a.memoizedState=e},useState:function(e){e=P7(e);var a=e.queue,l=nl.bind(null,Z1,a);return a.dispatch=l,[e.memoizedState,l]},useDebugValue:G7,useDeferredValue:function(e,a){var l=e4();return Y7(l,e,a)},useTransition:function(){var e=P7(!1);return e=Jr.bind(null,Z1,e.queue,!0,!1),e4().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,a,l){var o=Z1,m=e4();if(n2){if(l===void 0)throw Error(i(407));l=l()}else{if(l=a(),p2===null)throw Error(i(349));(c2&127)!==0||Lr(o,a,l)}m.memoizedState=l;var z={value:l,getSnapshot:a};return m.queue=z,Pr(Br.bind(null,o,z,e),[e]),o.flags|=2048,c0(9,{destroy:void 0},Vr.bind(null,o,z,l,a),null),l},useId:function(){var e=e4(),a=p2.identifierPrefix;if(n2){var l=P4,o=I4;l=(o&~(1<<32-b1(o)-1)).toString(32)+l,a="_"+a+"R_"+l,l=D5++,0<\/script>",z=z.removeChild(z.firstChild);break;case"select":z=typeof o.is=="string"?w.createElement("select",{is:o.is}):w.createElement("select"),o.multiple?z.multiple=!0:o.size&&(z.size=o.size);break;default:z=typeof o.is=="string"?w.createElement(m,{is:o.is}):w.createElement(m)}}z[G2]=a,z[c4]=o;t:for(w=a.child;w!==null;){if(w.tag===5||w.tag===6)z.appendChild(w.stateNode);else if(w.tag!==4&&w.tag!==27&&w.child!==null){w.child.return=w,w=w.child;continue}if(w===a)break t;for(;w.sibling===null;){if(w.return===null||w.return===a)break t;w=w.return}w.sibling.return=w.return,w=w.sibling}a.stateNode=z;t:switch(X2(z,m,o),m){case"button":case"input":case"select":case"textarea":o=!!o.autoFocus;break t;case"img":o=!0;break t;default:o=!1}o&&i3(a)}}return x2(a),h9(a,a.type,e===null?null:e.memoizedProps,a.pendingProps,l),null;case 6:if(e&&a.stateNode!=null)e.memoizedProps!==o&&i3(a);else{if(typeof o!="string"&&a.stateNode===null)throw Error(i(166));if(e=v1.current,G6(a)){if(e=a.stateNode,l=a.memoizedProps,o=null,m=Y2,m!==null)switch(m.tag){case 27:case 5:o=m.memoizedProps}e[G2]=a,e=!!(e.nodeValue===l||o!==null&&o.suppressHydrationWarning===!0||Hi(e.nodeValue,l)),e||H3(a,!0)}else e=dt(e).createTextNode(o),e[G2]=a,a.stateNode=e}return x2(a),null;case 31:if(l=a.memoizedState,e===null||e.memoizedState!==null){if(o=G6(a),l!==null){if(e===null){if(!o)throw Error(i(318));if(e=a.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(i(557));e[G2]=a}else n6(),(a.flags&128)===0&&(a.memoizedState=null),a.flags|=4;x2(a),e=!1}else l=y7(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),e=!0;if(!e)return a.flags&256?(f4(a),a):(f4(a),null);if((a.flags&128)!==0)throw Error(i(558))}return x2(a),null;case 13:if(o=a.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(m=G6(a),o!==null&&o.dehydrated!==null){if(e===null){if(!m)throw Error(i(318));if(m=a.memoizedState,m=m!==null?m.dehydrated:null,!m)throw Error(i(317));m[G2]=a}else n6(),(a.flags&128)===0&&(a.memoizedState=null),a.flags|=4;x2(a),m=!1}else m=y7(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=m),m=!0;if(!m)return a.flags&256?(f4(a),a):(f4(a),null)}return f4(a),(a.flags&128)!==0?(a.lanes=l,a):(l=o!==null,e=e!==null&&e.memoizedState!==null,l&&(o=a.child,m=null,o.alternate!==null&&o.alternate.memoizedState!==null&&o.alternate.memoizedState.cachePool!==null&&(m=o.alternate.memoizedState.cachePool.pool),z=null,o.memoizedState!==null&&o.memoizedState.cachePool!==null&&(z=o.memoizedState.cachePool.pool),z!==m&&(o.flags|=2048)),l!==e&&l&&(a.child.flags|=8192),X5(a,a.updateQueue),x2(a),null);case 4:return F1(),e===null&&k9(a.stateNode.containerInfo),x2(a),null;case 10:return a3(a.type),x2(a),null;case 19:if(D(V2),o=a.memoizedState,o===null)return x2(a),null;if(m=(a.flags&128)!==0,z=o.rendering,z===null)if(m)f8(o,!1);else{if(S2!==0||e!==null&&(e.flags&128)!==0)for(e=a.child;e!==null;){if(z=_5(e),z!==null){for(a.flags|=128,f8(o,!1),e=z.updateQueue,a.updateQueue=e,X5(a,e),a.subtreeFlags=0,e=l,l=a.child;l!==null;)nr(l,e),l=l.sibling;return Q(V2,V2.current&1|2),n2&&e3(a,o.treeForkCount),a.child}e=e.sibling}o.tail!==null&&n1()>ct&&(a.flags|=128,m=!0,f8(o,!1),a.lanes=4194304)}else{if(!m)if(e=_5(z),e!==null){if(a.flags|=128,m=!0,e=e.updateQueue,a.updateQueue=e,X5(a,e),f8(o,!0),o.tail===null&&o.tailMode==="hidden"&&!z.alternate&&!n2)return x2(a),null}else 2*n1()-o.renderingStartTime>ct&&l!==536870912&&(a.flags|=128,m=!0,f8(o,!1),a.lanes=4194304);o.isBackwards?(z.sibling=a.child,a.child=z):(e=o.last,e!==null?e.sibling=z:a.child=z,o.last=z)}return o.tail!==null?(e=o.tail,o.rendering=e,o.tail=e.sibling,o.renderingStartTime=n1(),e.sibling=null,l=V2.current,Q(V2,m?l&1|2:l&1),n2&&e3(a,o.treeForkCount),e):(x2(a),null);case 22:case 23:return f4(a),F7(),o=a.memoizedState!==null,e!==null?e.memoizedState!==null!==o&&(a.flags|=8192):o&&(a.flags|=8192),o?(l&536870912)!==0&&(a.flags&128)===0&&(x2(a),a.subtreeFlags&6&&(a.flags|=8192)):x2(a),l=a.updateQueue,l!==null&&X5(a,l.retryQueue),l=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(l=e.memoizedState.cachePool.pool),o=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(o=a.memoizedState.cachePool.pool),o!==l&&(a.flags|=2048),e!==null&&D(i6),null;case 24:return l=null,e!==null&&(l=e.memoizedState.cache),a.memoizedState.cache!==l&&(a.flags|=2048),a3(k2),x2(a),null;case 25:return null;case 30:return null}throw Error(i(156,a.tag))}function Mm(e,a){switch(z7(a),a.tag){case 1:return e=a.flags,e&65536?(a.flags=e&-65537|128,a):null;case 3:return a3(k2),F1(),e=a.flags,(e&65536)!==0&&(e&128)===0?(a.flags=e&-65537|128,a):null;case 26:case 27:case 5:return Q1(a),null;case 31:if(a.memoizedState!==null){if(f4(a),a.alternate===null)throw Error(i(340));n6()}return e=a.flags,e&65536?(a.flags=e&-65537|128,a):null;case 13:if(f4(a),e=a.memoizedState,e!==null&&e.dehydrated!==null){if(a.alternate===null)throw Error(i(340));n6()}return e=a.flags,e&65536?(a.flags=e&-65537|128,a):null;case 19:return D(V2),null;case 4:return F1(),null;case 10:return a3(a.type),null;case 22:case 23:return f4(a),F7(),e!==null&&D(i6),e=a.flags,e&65536?(a.flags=e&-65537|128,a):null;case 24:return a3(k2),null;case 25:return null;default:return null}}function jl(e,a){switch(z7(a),a.tag){case 3:a3(k2),F1();break;case 26:case 27:case 5:Q1(a);break;case 4:F1();break;case 31:a.memoizedState!==null&&f4(a);break;case 13:f4(a);break;case 19:D(V2);break;case 10:a3(a.type);break;case 22:case 23:f4(a),F7(),e!==null&&D(i6);break;case 24:a3(k2)}}function m8(e,a){try{var l=a.updateQueue,o=l!==null?l.lastEffect:null;if(o!==null){var m=o.next;l=m;do{if((l.tag&e)===e){o=void 0;var z=l.create,w=l.inst;o=z(),w.destroy=o}l=l.next}while(l!==m)}}catch(k){d2(a,a.return,k)}}function k3(e,a,l){try{var o=a.updateQueue,m=o!==null?o.lastEffect:null;if(m!==null){var z=m.next;o=z;do{if((o.tag&e)===e){var w=o.inst,k=w.destroy;if(k!==void 0){w.destroy=void 0,m=a;var U=l,J=k;try{J()}catch(o1){d2(m,U,o1)}}}o=o.next}while(o!==z)}}catch(o1){d2(a,a.return,o1)}}function Nl(e){var a=e.updateQueue;if(a!==null){var l=e.stateNode;try{Mr(a,l)}catch(o){d2(e,e.return,o)}}}function kl(e,a,l){l.props=d6(e.type,e.memoizedProps),l.state=e.memoizedState;try{l.componentWillUnmount()}catch(o){d2(e,a,o)}}function v8(e,a){try{var l=e.ref;if(l!==null){switch(e.tag){case 26:case 27:case 5:var o=e.stateNode;break;case 30:o=e.stateNode;break;default:o=e.stateNode}typeof l=="function"?e.refCleanup=l(o):l.current=o}}catch(m){d2(e,a,m)}}function $4(e,a){var l=e.ref,o=e.refCleanup;if(l!==null)if(typeof o=="function")try{o()}catch(m){d2(e,a,m)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(m){d2(e,a,m)}else l.current=null}function Fl(e){var a=e.type,l=e.memoizedProps,o=e.stateNode;try{t:switch(a){case"button":case"input":case"select":case"textarea":l.autoFocus&&o.focus();break t;case"img":l.src?o.src=l.src:l.srcSet&&(o.srcset=l.srcSet)}}catch(m){d2(e,e.return,m)}}function d9(e,a,l){try{var o=e.stateNode;Pm(o,e.type,l,a),o[c4]=a}catch(m){d2(e,e.return,m)}}function Rl(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&D3(e.type)||e.tag===4}function f9(e){t:for(;;){for(;e.sibling===null;){if(e.return===null||Rl(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&D3(e.type)||e.flags&2||e.child===null||e.tag===4)continue t;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function m9(e,a,l){var o=e.tag;if(o===5||o===6)e=e.stateNode,a?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(e,a):(a=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,a.appendChild(e),l=l._reactRootContainer,l!=null||a.onclick!==null||(a.onclick=W4));else if(o!==4&&(o===27&&D3(e.type)&&(l=e.stateNode,a=null),e=e.child,e!==null))for(m9(e,a,l),e=e.sibling;e!==null;)m9(e,a,l),e=e.sibling}function W5(e,a,l){var o=e.tag;if(o===5||o===6)e=e.stateNode,a?l.insertBefore(e,a):l.appendChild(e);else if(o!==4&&(o===27&&D3(e.type)&&(l=e.stateNode),e=e.child,e!==null))for(W5(e,a,l),e=e.sibling;e!==null;)W5(e,a,l),e=e.sibling}function El(e){var a=e.stateNode,l=e.memoizedProps;try{for(var o=e.type,m=a.attributes;m.length;)a.removeAttributeNode(m[0]);X2(a,o,l),a[G2]=e,a[c4]=l}catch(z){d2(e,e.return,z)}}var s3=!1,E2=!1,v9=!1,Tl=typeof WeakSet=="function"?WeakSet:Set,Z2=null;function wm(e,a){if(e=e.containerInfo,E9=zt,e=Kn(e),s7(e)){if("selectionStart"in e)var l={start:e.selectionStart,end:e.selectionEnd};else t:{l=(l=e.ownerDocument)&&l.defaultView||window;var o=l.getSelection&&l.getSelection();if(o&&o.rangeCount!==0){l=o.anchorNode;var m=o.anchorOffset,z=o.focusNode;o=o.focusOffset;try{l.nodeType,z.nodeType}catch{l=null;break t}var w=0,k=-1,U=-1,J=0,o1=0,h1=e,t1=null;e:for(;;){for(var a1;h1!==l||m!==0&&h1.nodeType!==3||(k=w+m),h1!==z||o!==0&&h1.nodeType!==3||(U=w+o),h1.nodeType===3&&(w+=h1.nodeValue.length),(a1=h1.firstChild)!==null;)t1=h1,h1=a1;for(;;){if(h1===e)break e;if(t1===l&&++J===m&&(k=w),t1===z&&++o1===o&&(U=w),(a1=h1.nextSibling)!==null)break;h1=t1,t1=h1.parentNode}h1=a1}l=k===-1||U===-1?null:{start:k,end:U}}else l=null}l=l||{start:0,end:0}}else l=null;for(T9={focusedElem:e,selectionRange:l},zt=!1,Z2=a;Z2!==null;)if(a=Z2,e=a.child,(a.subtreeFlags&1028)!==0&&e!==null)e.return=a,Z2=e;else for(;Z2!==null;){switch(a=Z2,z=a.alternate,e=a.flags,a.tag){case 0:if((e&4)!==0&&(e=a.updateQueue,e=e!==null?e.events:null,e!==null))for(l=0;l title"))),X2(z,o,l),z[G2]=e,$2(z),o=z;break t;case"link":var w=Ii("link","href",m).get(o+(l.href||""));if(w){for(var k=0;kv2&&(w=v2,v2=E1,E1=w);var G=Gn(k,E1),$=Gn(k,v2);if(G&&$&&(a1.rangeCount!==1||a1.anchorNode!==G.node||a1.anchorOffset!==G.offset||a1.focusNode!==$.node||a1.focusOffset!==$.offset)){var W=h1.createRange();W.setStart(G.node,G.offset),a1.removeAllRanges(),E1>v2?(a1.addRange(W),a1.extend($.node,$.offset)):(W.setEnd($.node,$.offset),a1.addRange(W))}}}}for(h1=[],a1=k;a1=a1.parentNode;)a1.nodeType===1&&h1.push({element:a1,left:a1.scrollLeft,top:a1.scrollTop});for(typeof k.focus=="function"&&k.focus(),k=0;kl?32:l,_.T=null,l=M9,M9=null;var z=T3,w=f3;if(q2=0,i0=T3=null,f3=0,(u2&6)!==0)throw Error(i(331));var k=u2;if(u2|=4,Yl(z.current),$l(z,z.current,w,l),u2=k,y8(0,!1),w1&&typeof w1.onPostCommitFiberRoot=="function")try{w1.onPostCommitFiberRoot(d1,z)}catch{}return!0}finally{P.p=m,_.T=o,di(e,a)}}function mi(e,a,l){a=y4(l,a),a=e9(e.stateNode,a,2),e=B3(e,a,2),e!==null&&(O0(e,2),Z4(e))}function d2(e,a,l){if(e.tag===3)mi(e,e,l);else for(;a!==null;){if(a.tag===3){mi(a,e,l);break}else if(a.tag===1){var o=a.stateNode;if(typeof a.type.getDerivedStateFromError=="function"||typeof o.componentDidCatch=="function"&&(E3===null||!E3.has(o))){e=y4(l,e),l=vl(2),o=B3(a,l,2),o!==null&&(pl(l,o,a,e),O0(o,2),Z4(o));break}}a=a.return}}function H9(e,a,l){var o=e.pingCache;if(o===null){o=e.pingCache=new Hm;var m=new Set;o.set(a,m)}else m=o.get(a),m===void 0&&(m=new Set,o.set(a,m));m.has(l)||(x9=!0,m.add(l),e=jm.bind(null,e,a,l),a.then(e,e))}function jm(e,a,l){var o=e.pingCache;o!==null&&o.delete(a),e.pingedLanes|=e.suspendedLanes&l,e.warmLanes&=~l,p2===e&&(c2&l)===l&&(S2===4||S2===3&&(c2&62914560)===c2&&300>n1()-et?(u2&2)===0&&s0(e,0):z9|=l,l0===c2&&(l0=0)),Z4(e)}function vi(e,a){a===0&&(a=on()),e=c6(e,a),e!==null&&(O0(e,a),Z4(e))}function Nm(e){var a=e.memoizedState,l=0;a!==null&&(l=a.retryLane),vi(e,l)}function km(e,a){var l=0;switch(e.tag){case 31:case 13:var o=e.stateNode,m=e.memoizedState;m!==null&&(l=m.retryLane);break;case 19:o=e.stateNode;break;case 22:o=e.stateNode._retryCache;break;default:throw Error(i(314))}o!==null&&o.delete(a),vi(e,l)}function Fm(e,a){return x1(e,a)}var st=null,u0=null,A9=!1,ot=!1,L9=!1,q3=0;function Z4(e){e!==u0&&e.next===null&&(u0===null?st=u0=e:u0=u0.next=e),ot=!0,A9||(A9=!0,Em())}function y8(e,a){if(!L9&&ot){L9=!0;do for(var l=!1,o=st;o!==null;){if(e!==0){var m=o.pendingLanes;if(m===0)var z=0;else{var w=o.suspendedLanes,k=o.pingedLanes;z=(1<<31-b1(42|e)+1)-1,z&=m&~(w&~k),z=z&201326741?z&201326741|1:z?z|2:0}z!==0&&(l=!0,zi(o,z))}else z=c2,z=w2(o,o===p2?z:0,o.cancelPendingCommit!==null||o.timeoutHandle!==-1),(z&3)===0||R4(o,z)||(l=!0,zi(o,z));o=o.next}while(l);L9=!1}}function Rm(){pi()}function pi(){ot=A9=!1;var e=0;q3!==0&&Zm()&&(e=q3);for(var a=n1(),l=null,o=st;o!==null;){var m=o.next,z=gi(o,a);z===0?(o.next=null,l===null?st=m:l.next=m,m===null&&(u0=l)):(l=o,(e!==0||(z&3)!==0)&&(ot=!0)),o=m}q2!==0&&q2!==5||y8(e),q3!==0&&(q3=0)}function gi(e,a){for(var l=e.suspendedLanes,o=e.pingedLanes,m=e.expirationTimes,z=e.pendingLanes&-62914561;0k)break;var o1=U.transferSize,h1=U.initiatorType;o1&&Ai(h1)&&(U=U.responseEnd,w+=o1*(U"u"?null:document;function qi(e,a,l){var o=h0;if(o&&typeof a=="string"&&a){var m=z4(a);m='link[rel="'+e+'"][href="'+m+'"]',typeof l=="string"&&(m+='[crossorigin="'+l+'"]'),_i.has(m)||(_i.add(m),e={rel:e,crossOrigin:l,href:a},o.querySelector(m)===null&&(a=o.createElement("link"),X2(a,"link",e),$2(a),o.head.appendChild(a)))}}function ev(e){m3.D(e),qi("dns-prefetch",e,null)}function cv(e,a){m3.C(e,a),qi("preconnect",e,a)}function av(e,a,l){m3.L(e,a,l);var o=h0;if(o&&e&&a){var m='link[rel="preload"][as="'+z4(a)+'"]';a==="image"&&l&&l.imageSrcSet?(m+='[imagesrcset="'+z4(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(m+='[imagesizes="'+z4(l.imageSizes)+'"]')):m+='[href="'+z4(e)+'"]';var z=m;switch(a){case"style":z=d0(e);break;case"script":z=f0(e)}A4.has(z)||(e=b({rel:"preload",href:a==="image"&&l&&l.imageSrcSet?void 0:e,as:a},l),A4.set(z,e),o.querySelector(m)!==null||a==="style"&&o.querySelector(S8(z))||a==="script"&&o.querySelector(H8(z))||(a=o.createElement("link"),X2(a,"link",e),$2(a),o.head.appendChild(a)))}}function nv(e,a){m3.m(e,a);var l=h0;if(l&&e){var o=a&&typeof a.as=="string"?a.as:"script",m='link[rel="modulepreload"][as="'+z4(o)+'"][href="'+z4(e)+'"]',z=m;switch(o){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":z=f0(e)}if(!A4.has(z)&&(e=b({rel:"modulepreload",href:e},a),A4.set(z,e),l.querySelector(m)===null)){switch(o){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(H8(z)))return}o=l.createElement("link"),X2(o,"link",e),$2(o),l.head.appendChild(o)}}}function rv(e,a,l){m3.S(e,a,l);var o=h0;if(o&&e){var m=F6(o).hoistableStyles,z=d0(e);a=a||"default";var w=m.get(z);if(!w){var k={loading:0,preload:null};if(w=o.querySelector(S8(z)))k.loading=5;else{e=b({rel:"stylesheet",href:e,"data-precedence":a},l),(l=A4.get(z))&&P9(e,l);var U=w=o.createElement("link");$2(U),X2(U,"link",e),U._p=new Promise(function(J,o1){U.onload=J,U.onerror=o1}),U.addEventListener("load",function(){k.loading|=1}),U.addEventListener("error",function(){k.loading|=2}),k.loading|=4,mt(w,a,o)}w={type:"stylesheet",instance:w,count:1,state:k},m.set(z,w)}}}function lv(e,a){m3.X(e,a);var l=h0;if(l&&e){var o=F6(l).hoistableScripts,m=f0(e),z=o.get(m);z||(z=l.querySelector(H8(m)),z||(e=b({src:e,async:!0},a),(a=A4.get(m))&&$9(e,a),z=l.createElement("script"),$2(z),X2(z,"link",e),l.head.appendChild(z)),z={type:"script",instance:z,count:1,state:null},o.set(m,z))}}function iv(e,a){m3.M(e,a);var l=h0;if(l&&e){var o=F6(l).hoistableScripts,m=f0(e),z=o.get(m);z||(z=l.querySelector(H8(m)),z||(e=b({src:e,async:!0,type:"module"},a),(a=A4.get(m))&&$9(e,a),z=l.createElement("script"),$2(z),X2(z,"link",e),l.head.appendChild(z)),z={type:"script",instance:z,count:1,state:null},o.set(m,z))}}function Di(e,a,l,o){var m=(m=v1.current)?ft(m):null;if(!m)throw Error(i(446));switch(e){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(a=d0(l.href),l=F6(m).hoistableStyles,o=l.get(a),o||(o={type:"style",instance:null,count:0,state:null},l.set(a,o)),o):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){e=d0(l.href);var z=F6(m).hoistableStyles,w=z.get(e);if(w||(m=m.ownerDocument||m,w={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},z.set(e,w),(z=m.querySelector(S8(e)))&&!z._p&&(w.instance=z,w.state.loading=5),A4.has(e)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},A4.set(e,l),z||sv(m,e,l,w.state))),a&&o===null)throw Error(i(528,""));return w}if(a&&o!==null)throw Error(i(529,""));return null;case"script":return a=l.async,l=l.src,typeof l=="string"&&a&&typeof a!="function"&&typeof a!="symbol"?(a=f0(l),l=F6(m).hoistableScripts,o=l.get(a),o||(o={type:"script",instance:null,count:0,state:null},l.set(a,o)),o):{type:"void",instance:null,count:0,state:null};default:throw Error(i(444,e))}}function d0(e){return'href="'+z4(e)+'"'}function S8(e){return'link[rel="stylesheet"]['+e+"]"}function Oi(e){return b({},e,{"data-precedence":e.precedence,precedence:null})}function sv(e,a,l,o){e.querySelector('link[rel="preload"][as="style"]['+a+"]")?o.loading=1:(a=e.createElement("link"),o.preload=a,a.addEventListener("load",function(){return o.loading|=1}),a.addEventListener("error",function(){return o.loading|=2}),X2(a,"link",l),$2(a),e.head.appendChild(a))}function f0(e){return'[src="'+z4(e)+'"]'}function H8(e){return"script[async]"+e}function Ui(e,a,l){if(a.count++,a.instance===null)switch(a.type){case"style":var o=e.querySelector('style[data-href~="'+z4(l.href)+'"]');if(o)return a.instance=o,$2(o),o;var m=b({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return o=(e.ownerDocument||e).createElement("style"),$2(o),X2(o,"style",m),mt(o,l.precedence,e),a.instance=o;case"stylesheet":m=d0(l.href);var z=e.querySelector(S8(m));if(z)return a.state.loading|=4,a.instance=z,$2(z),z;o=Oi(l),(m=A4.get(m))&&P9(o,m),z=(e.ownerDocument||e).createElement("link"),$2(z);var w=z;return w._p=new Promise(function(k,U){w.onload=k,w.onerror=U}),X2(z,"link",o),a.state.loading|=4,mt(z,l.precedence,e),a.instance=z;case"script":return z=f0(l.src),(m=e.querySelector(H8(z)))?(a.instance=m,$2(m),m):(o=l,(m=A4.get(z))&&(o=b({},l),$9(o,m)),e=e.ownerDocument||e,m=e.createElement("script"),$2(m),X2(m,"link",o),e.head.appendChild(m),a.instance=m);case"void":return null;default:throw Error(i(443,a.type))}else a.type==="stylesheet"&&(a.state.loading&4)===0&&(o=a.instance,a.state.loading|=4,mt(o,l.precedence,e));return a.instance}function mt(e,a,l){for(var o=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),m=o.length?o[o.length-1]:null,z=m,w=0;w title"):null)}function ov(e,a,l){if(l===1||a.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof a.precedence!="string"||typeof a.href!="string"||a.href==="")break;return!0;case"link":if(typeof a.rel!="string"||typeof a.href!="string"||a.href===""||a.onLoad||a.onError)break;switch(a.rel){case"stylesheet":return e=a.disabled,typeof a.precedence=="string"&&e==null;default:return!0}case"script":if(a.async&&typeof a.async!="function"&&typeof a.async!="symbol"&&!a.onLoad&&!a.onError&&a.src&&typeof a.src=="string")return!0}return!1}function $i(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function uv(e,a,l,o){if(l.type==="stylesheet"&&(typeof o.media!="string"||matchMedia(o.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var m=d0(o.href),z=a.querySelector(S8(m));if(z){a=z._p,a!==null&&typeof a=="object"&&typeof a.then=="function"&&(e.count++,e=pt.bind(e),a.then(e,e)),l.state.loading|=4,l.instance=z,$2(z);return}z=a.ownerDocument||a,o=Oi(o),(m=A4.get(m))&&P9(o,m),z=z.createElement("link"),$2(z);var w=z;w._p=new Promise(function(k,U){w.onload=k,w.onerror=U}),X2(z,"link",o),l.instance=z}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(l,a),(a=l.state.preload)&&(l.state.loading&3)===0&&(e.count++,l=pt.bind(e),a.addEventListener("load",l),a.addEventListener("error",l))}}var Z9=0;function hv(e,a){return e.stylesheets&&e.count===0&&xt(e,e.stylesheets),0Z9?50:800)+a);return e.unsuspend=l,function(){e.unsuspend=null,clearTimeout(o),clearTimeout(m)}}:null}function pt(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)xt(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var gt=null;function xt(e,a){e.stylesheets=null,e.unsuspend!==null&&(e.count++,gt=new Map,a.forEach(dv,e),gt=null,pt.call(e))}function dv(e,a){if(!(a.state.loading&4)){var l=gt.get(e);if(l)var o=l.get(null);else{l=new Map,gt.set(e,l);for(var m=e.querySelectorAll("link[data-precedence],style[data-precedence]"),z=0;z"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(c){console.error(c)}}return t(),ec.exports=Lv(),ec.exports}var Bv=Vv();var vs="popstate";function jv(t={}){function c(i,u){let{pathname:h,search:d,hash:v}=i.location;return Ic("",{pathname:h,search:d,hash:v},u.state&&u.state.usr||null,u.state&&u.state.key||"default")}function n(i,u){return typeof u=="string"?u:Q8(u)}return kv(c,n,null,t)}function y2(t,c){if(t===!1||t===null||typeof t>"u")throw new Error(c)}function U4(t,c){if(!t){typeof console<"u"&&console.warn(c);try{throw new Error(c)}catch{}}}function Nv(){return Math.random().toString(36).substring(2,10)}function ps(t,c){return{usr:t.state,key:t.key,idx:c}}function Ic(t,c,n=null,i){return{pathname:typeof t=="string"?t:t.pathname,search:"",hash:"",...typeof c=="string"?N0(c):c,state:n,key:c&&c.key||i||Nv()}}function Q8({pathname:t="/",search:c="",hash:n=""}){return c&&c!=="?"&&(t+=c.charAt(0)==="?"?c:"?"+c),n&&n!=="#"&&(t+=n.charAt(0)==="#"?n:"#"+n),t}function N0(t){let c={};if(t){let n=t.indexOf("#");n>=0&&(c.hash=t.substring(n),t=t.substring(0,n));let i=t.indexOf("?");i>=0&&(c.search=t.substring(i),t=t.substring(0,i)),t&&(c.pathname=t)}return c}function kv(t,c,n,i={}){let{window:u=document.defaultView,v5Compat:h=!1}=i,d=u.history,v="POP",p=null,x=g();x==null&&(x=0,d.replaceState({...d.state,idx:x},""));function g(){return(d.state||{idx:null}).idx}function b(){v="POP";let C=g(),V=C==null?null:C-x;x=C,p&&p({action:v,location:S.location,delta:V})}function y(C,V){v="PUSH";let A=Ic(S.location,C,V);x=g()+1;let H=ps(A,x),j=S.createHref(A);try{d.pushState(H,"",j)}catch(T){if(T instanceof DOMException&&T.name==="DataCloneError")throw T;u.location.assign(j)}h&&p&&p({action:v,location:S.location,delta:1})}function M(C,V){v="REPLACE";let A=Ic(S.location,C,V);x=g();let H=ps(A,x),j=S.createHref(A);d.replaceState(H,"",j),h&&p&&p({action:v,location:S.location,delta:0})}function L(C){return Fv(C)}let S={get action(){return v},get location(){return t(u,d)},listen(C){if(p)throw new Error("A history only accepts one active listener");return u.addEventListener(vs,b),p=C,()=>{u.removeEventListener(vs,b),p=null}},createHref(C){return c(u,C)},createURL:L,encodeLocation(C){let V=L(C);return{pathname:V.pathname,search:V.search,hash:V.hash}},push:y,replace:M,go(C){return d.go(C)}};return S}function Fv(t,c=!1){let n="http://localhost";typeof window<"u"&&(n=window.location.origin!=="null"?window.location.origin:window.location.href),y2(n,"No window.location.(origin|href) available to create URL");let i=typeof t=="string"?t:Q8(t);return i=i.replace(/ $/,"%20"),!c&&i.startsWith("//")&&(i=n+i),new URL(i,n)}function gu(t,c,n="/"){return Rv(t,c,n,!1)}function Rv(t,c,n,i){let u=typeof c=="string"?N0(c):c,h=b3(u.pathname||"/",n);if(h==null)return null;let d=xu(t);Ev(d);let v=null;for(let p=0;v==null&&p{let g={relativePath:x===void 0?d.path||"":x,caseSensitive:d.caseSensitive===!0,childrenIndex:v,route:d};if(g.relativePath.startsWith("/")){if(!g.relativePath.startsWith(i)&&p)return;y2(g.relativePath.startsWith(i),`Absolute route path "${g.relativePath}" nested under path "${i}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),g.relativePath=g.relativePath.slice(i.length)}let b=x3([i,g.relativePath]),y=n.concat(g);d.children&&d.children.length>0&&(y2(d.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${b}".`),xu(d.children,c,y,b,p)),!(d.path==null&&!d.index)&&c.push({path:b,score:Iv(b,d.index),routesMeta:y})};return t.forEach((d,v)=>{if(d.path===""||!d.path?.includes("?"))h(d,v);else for(let p of zu(d.path))h(d,v,!0,p)}),c}function zu(t){let c=t.split("/");if(c.length===0)return[];let[n,...i]=c,u=n.endsWith("?"),h=n.replace(/\?$/,"");if(i.length===0)return u?[h,""]:[h];let d=zu(i.join("/")),v=[];return v.push(...d.map(p=>p===""?h:[h,p].join("/"))),u&&v.push(...d),v.map(p=>t.startsWith("/")&&p===""?"/":p)}function Ev(t){t.sort((c,n)=>c.score!==n.score?n.score-c.score:Pv(c.routesMeta.map(i=>i.childrenIndex),n.routesMeta.map(i=>i.childrenIndex)))}var Tv=/^:[\w-]+$/,_v=3,qv=2,Dv=1,Ov=10,Uv=-2,gs=t=>t==="*";function Iv(t,c){let n=t.split("/"),i=n.length;return n.some(gs)&&(i+=Uv),c&&(i+=qv),n.filter(u=>!gs(u)).reduce((u,h)=>u+(Tv.test(h)?_v:h===""?Dv:Ov),i)}function Pv(t,c){return t.length===c.length&&t.slice(0,-1).every((i,u)=>i===c[u])?t[t.length-1]-c[c.length-1]:0}function $v(t,c,n=!1){let{routesMeta:i}=t,u={},h="/",d=[];for(let v=0;v{if(g==="*"){let L=v[y]||"";d=h.slice(0,h.length-L.length).replace(/(.)\/+$/,"$1")}const M=v[y];return b&&!M?x[g]=void 0:x[g]=(M||"").replace(/%2F/g,"/"),x},{}),pathname:h,pathnameBase:d,pattern:t}}function Zv(t,c=!1,n=!0){U4(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 i=[],u="^"+t.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(d,v,p)=>(i.push({paramName:v,isOptional:p!=null}),p?"/?([^\\/]+)?":"/([^\\/]+)")).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return t.endsWith("*")?(i.push({paramName:"*"}),u+=t==="*"||t==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?u+="\\/*$":t!==""&&t!=="/"&&(u+="(?:(?=\\/|$))"),[new RegExp(u,c?void 0:"i"),i]}function Gv(t){try{return t.split("/").map(c=>decodeURIComponent(c).replace(/\//g,"%2F")).join("/")}catch(c){return U4(!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 (${c}).`),t}}function b3(t,c){if(c==="/")return t;if(!t.toLowerCase().startsWith(c.toLowerCase()))return null;let n=c.endsWith("/")?c.length-1:c.length,i=t.charAt(n);return i&&i!=="/"?null:t.slice(n)||"/"}var Yv=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,Kv=t=>Yv.test(t);function Qv(t,c="/"){let{pathname:n,search:i="",hash:u=""}=typeof t=="string"?N0(t):t,h;if(n)if(Kv(n))h=n;else{if(n.includes("//")){let d=n;n=n.replace(/\/\/+/g,"/"),U4(!1,`Pathnames cannot have embedded double slashes - normalizing ${d} -> ${n}`)}n.startsWith("/")?h=xs(n.substring(1),"/"):h=xs(n,c)}else h=c;return{pathname:h,search:Jv(i),hash:tp(u)}}function xs(t,c){let n=c.replace(/\/+$/,"").split("/");return t.split("/").forEach(u=>{u===".."?n.length>1&&n.pop():u!=="."&&n.push(u)}),n.length>1?n.join("/"):"/"}function rc(t,c,n,i){return`Cannot include a '${t}' character in a manually specified \`to.${c}\` field [${JSON.stringify(i)}]. 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 Xv(t){return t.filter((c,n)=>n===0||c.route.path&&c.route.path.length>0)}function bu(t){let c=Xv(t);return c.map((n,i)=>i===c.length-1?n.pathname:n.pathnameBase)}function yu(t,c,n,i=!1){let u;typeof t=="string"?u=N0(t):(u={...t},y2(!u.pathname||!u.pathname.includes("?"),rc("?","pathname","search",u)),y2(!u.pathname||!u.pathname.includes("#"),rc("#","pathname","hash",u)),y2(!u.search||!u.search.includes("#"),rc("#","search","hash",u)));let h=t===""||u.pathname==="",d=h?"/":u.pathname,v;if(d==null)v=n;else{let b=c.length-1;if(!i&&d.startsWith("..")){let y=d.split("/");for(;y[0]==="..";)y.shift(),b-=1;u.pathname=y.join("/")}v=b>=0?c[b]:"/"}let p=Qv(u,v),x=d&&d!=="/"&&d.endsWith("/"),g=(h||d===".")&&n.endsWith("/");return!p.pathname.endsWith("/")&&(x||g)&&(p.pathname+="/"),p}var x3=t=>t.join("/").replace(/\/\/+/g,"/"),Wv=t=>t.replace(/\/+$/,"").replace(/^\/*/,"/"),Jv=t=>!t||t==="?"?"":t.startsWith("?")?t:"?"+t,tp=t=>!t||t==="#"?"":t.startsWith("#")?t:"#"+t;function ep(t){return t!=null&&typeof t.status=="number"&&typeof t.statusText=="string"&&typeof t.internal=="boolean"&&"data"in t}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var Mu=["POST","PUT","PATCH","DELETE"];new Set(Mu);var cp=["GET",...Mu];new Set(cp);var k0=f.createContext(null);k0.displayName="DataRouter";var Se=f.createContext(null);Se.displayName="DataRouterState";f.createContext(!1);var wu=f.createContext({isTransitioning:!1});wu.displayName="ViewTransition";var ap=f.createContext(new Map);ap.displayName="Fetchers";var np=f.createContext(null);np.displayName="Await";var K4=f.createContext(null);K4.displayName="Navigation";var l5=f.createContext(null);l5.displayName="Location";var y3=f.createContext({outlet:null,matches:[],isDataRoute:!1});y3.displayName="Route";var Ma=f.createContext(null);Ma.displayName="RouteError";function rp(t,{relative:c}={}){y2(i5(),"useHref() may be used only in the context of a component.");let{basename:n,navigator:i}=f.useContext(K4),{hash:u,pathname:h,search:d}=s5(t,{relative:c}),v=h;return n!=="/"&&(v=h==="/"?n:x3([n,h])),i.createHref({pathname:v,search:d,hash:u})}function i5(){return f.useContext(l5)!=null}function K3(){return y2(i5(),"useLocation() may be used only in the context of a component."),f.useContext(l5).location}var Cu="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function Su(t){f.useContext(K4).static||f.useLayoutEffect(t)}function lp(){let{isDataRoute:t}=f.useContext(y3);return t?zp():ip()}function ip(){y2(i5(),"useNavigate() may be used only in the context of a component.");let t=f.useContext(k0),{basename:c,navigator:n}=f.useContext(K4),{matches:i}=f.useContext(y3),{pathname:u}=K3(),h=JSON.stringify(bu(i)),d=f.useRef(!1);return Su(()=>{d.current=!0}),f.useCallback((p,x={})=>{if(U4(d.current,Cu),!d.current)return;if(typeof p=="number"){n.go(p);return}let g=yu(p,JSON.parse(h),u,x.relative==="path");t==null&&c!=="/"&&(g.pathname=g.pathname==="/"?c:x3([c,g.pathname])),(x.replace?n.replace:n.push)(g,x.state,x)},[c,n,h,u,t])}f.createContext(null);function s5(t,{relative:c}={}){let{matches:n}=f.useContext(y3),{pathname:i}=K3(),u=JSON.stringify(bu(n));return f.useMemo(()=>yu(t,JSON.parse(u),i,c==="path"),[t,u,i,c])}function sp(t,c){return Hu(t,c)}function Hu(t,c,n,i,u){y2(i5(),"useRoutes() may be used only in the context of a component.");let{navigator:h}=f.useContext(K4),{matches:d}=f.useContext(y3),v=d[d.length-1],p=v?v.params:{},x=v?v.pathname:"/",g=v?v.pathnameBase:"/",b=v&&v.route;{let A=b&&b.path||"";Au(x,!b||A.endsWith("*")||A.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${x}" (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 y=K3(),M;if(c){let A=typeof c=="string"?N0(c):c;y2(g==="/"||A.pathname?.startsWith(g),`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 "${g}" but pathname "${A.pathname}" was given in the \`location\` prop.`),M=A}else M=y;let L=M.pathname||"/",S=L;if(g!=="/"){let A=g.replace(/^\//,"").split("/");S="/"+L.replace(/^\//,"").split("/").slice(A.length).join("/")}let C=gu(t,{pathname:S});U4(b||C!=null,`No routes matched location "${M.pathname}${M.search}${M.hash}" `),U4(C==null||C[C.length-1].route.element!==void 0||C[C.length-1].route.Component!==void 0||C[C.length-1].route.lazy!==void 0,`Matched leaf route at location "${M.pathname}${M.search}${M.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 V=fp(C&&C.map(A=>Object.assign({},A,{params:Object.assign({},p,A.params),pathname:x3([g,h.encodeLocation?h.encodeLocation(A.pathname.replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:A.pathname]),pathnameBase:A.pathnameBase==="/"?g:x3([g,h.encodeLocation?h.encodeLocation(A.pathnameBase.replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:A.pathnameBase])})),d,n,i,u);return c&&V?f.createElement(l5.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",...M},navigationType:"POP"}},V):V}function op(){let t=xp(),c=ep(t)?`${t.status} ${t.statusText}`:t instanceof Error?t.message:JSON.stringify(t),n=t instanceof Error?t.stack:null,i="rgba(200,200,200, 0.5)",u={padding:"0.5rem",backgroundColor:i},h={padding:"2px 4px",backgroundColor:i},d=null;return console.error("Error handled by React Router default ErrorBoundary:",t),d=f.createElement(f.Fragment,null,f.createElement("p",null,"💿 Hey developer 👋"),f.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",f.createElement("code",{style:h},"ErrorBoundary")," or"," ",f.createElement("code",{style:h},"errorElement")," prop on your route.")),f.createElement(f.Fragment,null,f.createElement("h2",null,"Unexpected Application Error!"),f.createElement("h3",{style:{fontStyle:"italic"}},c),n?f.createElement("pre",{style:u},n):null,d)}var up=f.createElement(op,null),hp=class extends f.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,c){return c.location!==t.location||c.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error!==void 0?t.error:c.error,location:c.location,revalidation:t.revalidation||c.revalidation}}componentDidCatch(t,c){this.props.onError?this.props.onError(t,c):console.error("React Router caught the following error during render",t)}render(){return this.state.error!==void 0?f.createElement(y3.Provider,{value:this.props.routeContext},f.createElement(Ma.Provider,{value:this.state.error,children:this.props.component})):this.props.children}};function dp({routeContext:t,match:c,children:n}){let i=f.useContext(k0);return i&&i.static&&i.staticContext&&(c.route.errorElement||c.route.ErrorBoundary)&&(i.staticContext._deepestRenderedBoundaryId=c.route.id),f.createElement(y3.Provider,{value:t},n)}function fp(t,c=[],n=null,i=null,u=null){if(t==null){if(!n)return null;if(n.errors)t=n.matches;else if(c.length===0&&!n.initialized&&n.matches.length>0)t=n.matches;else return null}let h=t,d=n?.errors;if(d!=null){let g=h.findIndex(b=>b.route.id&&d?.[b.route.id]!==void 0);y2(g>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(d).join(",")}`),h=h.slice(0,Math.min(h.length,g+1))}let v=!1,p=-1;if(n)for(let g=0;g=0?h=h.slice(0,p+1):h=[h[0]];break}}}let x=n&&i?(g,b)=>{i(g,{location:n.location,params:n.matches?.[0]?.params??{},errorInfo:b})}:void 0;return h.reduceRight((g,b,y)=>{let M,L=!1,S=null,C=null;n&&(M=d&&b.route.id?d[b.route.id]:void 0,S=b.route.errorElement||up,v&&(p<0&&y===0?(Au("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),L=!0,C=null):p===y&&(L=!0,C=b.route.hydrateFallbackElement||null)));let V=c.concat(h.slice(0,y+1)),A=()=>{let H;return M?H=S:L?H=C:b.route.Component?H=f.createElement(b.route.Component,null):b.route.element?H=b.route.element:H=g,f.createElement(dp,{match:b,routeContext:{outlet:g,matches:V,isDataRoute:n!=null},children:H})};return n&&(b.route.ErrorBoundary||b.route.errorElement||y===0)?f.createElement(hp,{location:n.location,revalidation:n.revalidation,component:S,error:M,children:A(),routeContext:{outlet:null,matches:V,isDataRoute:!0},onError:x}):A()},null)}function wa(t){return`${t} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function mp(t){let c=f.useContext(k0);return y2(c,wa(t)),c}function vp(t){let c=f.useContext(Se);return y2(c,wa(t)),c}function pp(t){let c=f.useContext(y3);return y2(c,wa(t)),c}function Ca(t){let c=pp(t),n=c.matches[c.matches.length-1];return y2(n.route.id,`${t} can only be used on routes that contain a unique "id"`),n.route.id}function gp(){return Ca("useRouteId")}function xp(){let t=f.useContext(Ma),c=vp("useRouteError"),n=Ca("useRouteError");return t!==void 0?t:c.errors?.[n]}function zp(){let{router:t}=mp("useNavigate"),c=Ca("useNavigate"),n=f.useRef(!1);return Su(()=>{n.current=!0}),f.useCallback(async(u,h={})=>{U4(n.current,Cu),n.current&&(typeof u=="number"?t.navigate(u):await t.navigate(u,{fromRouteId:c,...h}))},[t,c])}var zs={};function Au(t,c,n){!c&&!zs[t]&&(zs[t]=!0,U4(!1,n))}f.memo(bp);function bp({routes:t,future:c,state:n,unstable_onError:i}){return Hu(t,void 0,n,i,c)}function y6(t){y2(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function yp({basename:t="/",children:c=null,location:n,navigationType:i="POP",navigator:u,static:h=!1}){y2(!i5(),"You cannot render a inside another . You should never have more than one in your app.");let d=t.replace(/^\/*/,"/"),v=f.useMemo(()=>({basename:d,navigator:u,static:h,future:{}}),[d,u,h]);typeof n=="string"&&(n=N0(n));let{pathname:p="/",search:x="",hash:g="",state:b=null,key:y="default"}=n,M=f.useMemo(()=>{let L=b3(p,d);return L==null?null:{location:{pathname:L,search:x,hash:g,state:b,key:y},navigationType:i}},[d,p,x,g,b,y,i]);return U4(M!=null,` is not able to match the URL "${p}${x}${g}" because it does not start with the basename, so the won't render anything.`),M==null?null:f.createElement(K4.Provider,{value:v},f.createElement(l5.Provider,{children:c,value:M}))}function Mp({children:t,location:c}){return sp(Pc(t),c)}function Pc(t,c=[]){let n=[];return f.Children.forEach(t,(i,u)=>{if(!f.isValidElement(i))return;let h=[...c,u];if(i.type===f.Fragment){n.push.apply(n,Pc(i.props.children,h));return}y2(i.type===y6,`[${typeof i.type=="string"?i.type:i.type.name}] is not a component. All component children of must be a or `),y2(!i.props.index||!i.props.children,"An index route cannot have child routes.");let d={id:i.props.id||h.join("-"),caseSensitive:i.props.caseSensitive,element:i.props.element,Component:i.props.Component,index:i.props.index,path:i.props.path,middleware:i.props.middleware,loader:i.props.loader,action:i.props.action,hydrateFallbackElement:i.props.hydrateFallbackElement,HydrateFallback:i.props.HydrateFallback,errorElement:i.props.errorElement,ErrorBoundary:i.props.ErrorBoundary,hasErrorBoundary:i.props.hasErrorBoundary===!0||i.props.ErrorBoundary!=null||i.props.errorElement!=null,shouldRevalidate:i.props.shouldRevalidate,handle:i.props.handle,lazy:i.props.lazy};i.props.children&&(d.children=Pc(i.props.children,h)),n.push(d)}),n}var Zt="get",Gt="application/x-www-form-urlencoded";function He(t){return t!=null&&typeof t.tagName=="string"}function wp(t){return He(t)&&t.tagName.toLowerCase()==="button"}function Cp(t){return He(t)&&t.tagName.toLowerCase()==="form"}function Sp(t){return He(t)&&t.tagName.toLowerCase()==="input"}function Hp(t){return!!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)}function Ap(t,c){return t.button===0&&(!c||c==="_self")&&!Hp(t)}var Ht=null;function Lp(){if(Ht===null)try{new FormData(document.createElement("form"),0),Ht=!1}catch{Ht=!0}return Ht}var Vp=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function lc(t){return t!=null&&!Vp.has(t)?(U4(!1,`"${t}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${Gt}"`),null):t}function Bp(t,c){let n,i,u,h,d;if(Cp(t)){let v=t.getAttribute("action");i=v?b3(v,c):null,n=t.getAttribute("method")||Zt,u=lc(t.getAttribute("enctype"))||Gt,h=new FormData(t)}else if(wp(t)||Sp(t)&&(t.type==="submit"||t.type==="image")){let v=t.form;if(v==null)throw new Error('Cannot submit a + ); +} + +function PtzLiveVideo({ enabled }) { + const videoRef = useRef(null); + const playerRef = useRef(null); + const [status, setStatus] = useState('idle'); + const sources = useVideoRequests( + [{ type: 'ptz', id: PTZ_CAMERA_ID, key: PTZ_CAMERA_ID }], + { enabled }, + ); + const source = sources[PTZ_CAMERA_ID] || null; + + useEffect(() => { + if (!enabled || !source?.url || !videoRef.current) return undefined; + /* + WhepPlayer already owns PeerConnection setup, low-latency hints, auth + headers, and cleanup for rover video. Reusing it keeps PTZ video on the + same MediaMTX browser path as the rest of the app. + */ + const player = new WhepPlayer({ + url: source.url, + token: source.token, + video: videoRef.current, + onStatus: setStatus, + receiveAudio: false, + }); + playerRef.current = player; + player.start().catch((err) => setStatus(err.message || 'error')); + return () => { + player.stop(); + playerRef.current = null; + }; + }, [enabled, source?.token, source?.url]); + + return ( +
+
+ ); +} + +function PtzController({ open, onClose }) { + const ptz = useSessionSelector((state) => state.session?.ptzCamera || null); + const isOperator = Boolean(ptz?.isOperator); + const { ptzMove, ptzStop, ptzSpotlight, ptzIr, ptzRelease } = useSessionActions(); + const snapshot = usePtzCameraSnapshot({ enabled: open && !isOperator }); + const [busy, setBusy] = useState(''); + + const sendMove = useCallback( + (payload) => { + ptzMove(payload).catch(() => {}); + }, + [ptzMove], + ); + + const stopMotion = useCallback(() => { + ptzStop().catch(() => {}); + }, [ptzStop]); + + const holdMove = useCallback( + (payload) => (phase) => { + if (phase === 'start') sendMove(payload); + else stopMotion(); + }, + [sendMove, stopMotion], + ); + + useEffect(() => { + if (!open || !isOperator) return undefined; + /* + Keyboard control is intentionally active only while the fullscreen PTZ + controller is open. Releasing, blurring, or losing operator status sends a + stop command so continuous ONVIF movement cannot be left running. + */ + const pressed = new Set(); + const recompute = () => { + let pan = 0; + let tilt = 0; + let zoom = 0; + if (pressed.has('ArrowLeft') || pressed.has('KeyA')) pan -= 0.55; + if (pressed.has('ArrowRight') || pressed.has('KeyD')) pan += 0.55; + if (pressed.has('ArrowUp') || pressed.has('KeyW')) tilt += 0.55; + if (pressed.has('ArrowDown') || pressed.has('KeyS')) tilt -= 0.55; + if (pressed.has('KeyQ')) zoom += 0.55; + if (pressed.has('KeyE')) zoom -= 0.55; + if (pan || tilt || zoom) sendMove({ pan, tilt, zoom }); + else stopMotion(); + }; + const onKeyDown = (event) => { + if (!['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'KeyA', 'KeyD', 'KeyW', 'KeyS', 'KeyQ', 'KeyE', 'Space'].includes(event.code)) return; + event.preventDefault(); + if (event.code === 'Space') { + pressed.clear(); + stopMotion(); + return; + } + if (!pressed.has(event.code)) { + pressed.add(event.code); + recompute(); + } + }; + const onKeyUp = (event) => { + if (!pressed.delete(event.code)) return; + event.preventDefault(); + recompute(); + }; + const onBlur = () => { + pressed.clear(); + stopMotion(); + }; + window.addEventListener('keydown', onKeyDown); + window.addEventListener('keyup', onKeyUp); + window.addEventListener('blur', onBlur); + return () => { + window.removeEventListener('keydown', onKeyDown); + window.removeEventListener('keyup', onKeyUp); + window.removeEventListener('blur', onBlur); + stopMotion(); + }; + }, [isOperator, open, sendMove, stopMotion]); + + if (!open) return null; + + const toggleSpotlight = async () => { + setBusy('spotlight'); + try { + await ptzSpotlight({ state: ptz?.light?.state ? 0 : 1 }); + } finally { + setBusy(''); + } + }; + + const toggleIr = async () => { + setBusy('ir'); + try { + await ptzIr({ state: ptz?.ir?.state === 'Off' ? 'Auto' : 'Off' }); + } finally { + setBusy(''); + } + }; + + return ( +
+
+ {isOperator ? : } +
+ +
+ ); +} + +export default function VipPtzCameraCard({ onMessage, fullWidth = false }) { + const featureEnabled = useSessionSelector((state) => isFeatureEnabled(state, 'ptzCamera')); + const ptz = useSessionSelector((state) => state.session?.ptzCamera || null); + const isVerified = useSessionSelector((state) => Boolean(state.session?.isVerified)); + const { ptzClaim, ptzRelease } = useSessionActions(); + const snapshot = usePtzCameraSnapshot({ enabled: Boolean(featureEnabled) }); + const [controllerOpen, setControllerOpen] = useState(false); + const [pending, setPending] = useState(false); + + const wrapClass = fullWidth ? 'w-full' : 'mx-auto w-full max-w-xl'; + const queueText = useMemo(() => { + if (ptz?.isOperator) return 'Your turn'; + if (ptz?.queuedPosition) return `Queue position ${ptz.queuedPosition}`; + if (ptz?.operatorLabel) return `${ptz.operatorLabel} operating`; + return 'Available'; + }, [ptz?.isOperator, ptz?.operatorLabel, ptz?.queuedPosition]); + + if (!featureEnabled) return null; + + const handleClaim = async () => { + setPending(true); + onMessage?.(''); + try { + const response = await ptzClaim(); + if (response?.state?.isOperator) onMessage?.('PTZ camera turn active.'); + else if (response?.state?.queuedPosition) onMessage?.(`Joined PTZ queue at position ${response.state.queuedPosition}.`); + } catch (err) { + onMessage?.(err.message || 'PTZ request failed.'); + } finally { + setPending(false); + } + }; + + const handleRelease = async () => { + setPending(true); + try { + await ptzRelease(); + onMessage?.('Left PTZ camera.'); + } catch (err) { + onMessage?.(err.message || 'Failed to leave PTZ camera.'); + } finally { + setPending(false); + } + }; + + return ( + <> + +
+ +
+
+

State

+

{queueText}

+
+
+

Remaining

+

{formatRemaining(ptz?.deadline)}

+
+
+ {ptz?.blocked?.message ? ( +

+ {ptz.blocked.message} +

+ ) : null} +
+ {ptz?.isOperator ? ( + <> + + + + ) : ( + + )} +
+
+
+ setControllerOpen(false)} /> + + ); +} diff --git a/webui/src/context/SessionContext.jsx b/webui/src/context/SessionContext.jsx index c4821484..833f399b 100644 --- a/webui/src/context/SessionContext.jsx +++ b/webui/src/context/SessionContext.jsx @@ -420,6 +420,12 @@ export function SessionProvider({ children }) { setAudioLevels: (levels = {}) => emitWithAck('audioLevels:set', levels), setPrivateSafety: (roverId, safety = {}) => emitWithAck('session:privateSafety:set', { roverId, safety }), + ptzClaim: () => emitWithAck('ptzCamera:claim'), + ptzRelease: () => emitWithAck('ptzCamera:release'), + ptzMove: (payload = {}) => emitWithAck('ptzCamera:move', payload), + ptzStop: () => emitWithAck('ptzCamera:stop'), + ptzSpotlight: (payload = {}) => emitWithAck('ptzCamera:spotlight', payload), + ptzIr: (payload = {}) => emitWithAck('ptzCamera:ir', payload), llmControl: (action, controls = {}) => emitWithAck('llm:control', { controls: { action, ...controls } }), overseerControl: (action, controls = {}) => diff --git a/webui/src/hooks/usePtzCameraSnapshot.js b/webui/src/hooks/usePtzCameraSnapshot.js new file mode 100644 index 00000000..0205a1fe --- /dev/null +++ b/webui/src/hooks/usePtzCameraSnapshot.js @@ -0,0 +1,74 @@ +// Hook: usePtzCameraSnapshot +// Purpose: Subscribes to the server-generated PTZ camera snapshot feed. +// Scope: Mirrors the rover snapshot object-URL lifecycle while using PTZ-specific socket events and authorization. +import { useEffect, useRef, useState } from 'react'; +import { useSocket } from '../context/SocketContext.jsx'; + +export function usePtzCameraSnapshot(options = {}) { + const socket = useSocket(); + const { enabled = true, version = null } = options; + const [feed, setFeed] = useState(null); + const objectUrlRef = useRef(null); + const [connectionNonce, setConnectionNonce] = useState(0); + + useEffect(() => { + if (!socket) return undefined; + const handleConnect = () => setConnectionNonce((prev) => prev + 1); + socket.on('connect', handleConnect); + return () => socket.off('connect', handleConnect); + }, [socket]); + + useEffect(() => { + if (objectUrlRef.current) { + URL.revokeObjectURL(objectUrlRef.current); + objectUrlRef.current = null; + } + setFeed(null); + }, [version]); + + useEffect(() => { + if (!enabled || !socket) return undefined; + let cancelled = false; + + const handleFrame = (meta = {}, buffer) => { + if (cancelled || !buffer) return; + const url = URL.createObjectURL(new Blob([buffer], { type: 'image/jpeg' })); + if (objectUrlRef.current) URL.revokeObjectURL(objectUrlRef.current); + objectUrlRef.current = url; + setFeed({ + status: 'playing', + ts: meta.ts || Date.now(), + error: null, + objectUrl: url, + }); + }; + + const handleStatus = (meta = {}) => { + if (cancelled) return; + setFeed((prev) => ({ + ...(prev || {}), + status: meta.error ? 'error' : prev?.status || 'connecting', + error: meta.error || null, + ts: meta.ts || prev?.ts || null, + objectUrl: prev?.objectUrl || null, + })); + }; + + socket.on('ptzCamera:snapshotFrame', handleFrame); + socket.on('ptzCamera:snapshotStatus', handleStatus); + socket.emit('ptzCamera:snapshotSubscribe', {}, () => {}); + + return () => { + cancelled = true; + socket.emit('ptzCamera:snapshotUnsubscribe'); + socket.off('ptzCamera:snapshotFrame', handleFrame); + socket.off('ptzCamera:snapshotStatus', handleStatus); + if (objectUrlRef.current) { + URL.revokeObjectURL(objectUrlRef.current); + objectUrlRef.current = null; + } + }; + }, [socket, enabled, version, connectionNonce]); + + return feed; +} diff --git a/webui/src/hooks/useVideoRequests.js b/webui/src/hooks/useVideoRequests.js index fa2f2ac3..cb257dd7 100644 --- a/webui/src/hooks/useVideoRequests.js +++ b/webui/src/hooks/useVideoRequests.js @@ -88,7 +88,12 @@ export function useVideoRequests(sourceList = [], options = {}) { let cancelled = false; function requestEntry(entry) { - const payload = entry.type === 'room' ? { roomCameraId: entry.id } : { roverId: entry.id }; + const payload = + entry.type === 'room' + ? { roomCameraId: entry.id } + : entry.type === 'ptz' + ? { type: 'ptz', id: entry.id } + : { roverId: entry.id }; socket.emit('video:request', payload, (resp = {}) => { if (cancelled) return; if (resp?.error) {