diff --git a/frontend/dist/assets/index-B7wEvRdc.js b/frontend/dist/assets/index-B7wEvRdc.js new file mode 100644 index 0000000..d9d4b12 --- /dev/null +++ b/frontend/dist/assets/index-B7wEvRdc.js @@ -0,0 +1,40 @@ +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const l of document.querySelectorAll('link[rel="modulepreload"]'))r(l);new MutationObserver(l=>{for(const u of l)if(u.type==="childList")for(const o of u.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&r(o)}).observe(document,{childList:!0,subtree:!0});function n(l){const u={};return l.integrity&&(u.integrity=l.integrity),l.referrerPolicy&&(u.referrerPolicy=l.referrerPolicy),l.crossOrigin==="use-credentials"?u.credentials="include":l.crossOrigin==="anonymous"?u.credentials="omit":u.credentials="same-origin",u}function r(l){if(l.ep)return;l.ep=!0;const u=n(l);fetch(l.href,u)}})();var qi={exports:{}},ol={},bi={exports:{}},O={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var nr=Symbol.for("react.element"),dc=Symbol.for("react.portal"),pc=Symbol.for("react.fragment"),mc=Symbol.for("react.strict_mode"),hc=Symbol.for("react.profiler"),vc=Symbol.for("react.provider"),yc=Symbol.for("react.context"),gc=Symbol.for("react.forward_ref"),wc=Symbol.for("react.suspense"),kc=Symbol.for("react.memo"),Sc=Symbol.for("react.lazy"),Io=Symbol.iterator;function xc(e){return e===null||typeof e!="object"?null:(e=Io&&e[Io]||e["@@iterator"],typeof e=="function"?e:null)}var es={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},ts=Object.assign,ns={};function pn(e,t,n){this.props=e,this.context=t,this.refs=ns,this.updater=n||es}pn.prototype.isReactComponent={};pn.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};pn.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function rs(){}rs.prototype=pn.prototype;function Wu(e,t,n){this.props=e,this.context=t,this.refs=ns,this.updater=n||es}var Bu=Wu.prototype=new rs;Bu.constructor=Wu;ts(Bu,pn.prototype);Bu.isPureReactComponent=!0;var Uo=Array.isArray,ls=Object.prototype.hasOwnProperty,Hu={current:null},us={key:!0,ref:!0,__self:!0,__source:!0};function os(e,t,n){var r,l={},u=null,o=null;if(t!=null)for(r in t.ref!==void 0&&(o=t.ref),t.key!==void 0&&(u=""+t.key),t)ls.call(t,r)&&!us.hasOwnProperty(r)&&(l[r]=t[r]);var i=arguments.length-2;if(i===1)l.children=n;else if(1>>1,_=C[w];if(0>>1;wl(we,R))pe<_&&0>l(Qe,we)?(C[w]=Qe,C[pe]=R,w=pe):(C[w]=we,C[G]=R,w=G);else if(pe<_&&0>l(Qe,R))C[w]=Qe,C[pe]=R,w=pe;else break e}}return j}function l(C,j){var R=C.sortIndex-j.sortIndex;return R!==0?R:C.id-j.id}if(typeof performance=="object"&&typeof performance.now=="function"){var u=performance;e.unstable_now=function(){return u.now()}}else{var o=Date,i=o.now();e.unstable_now=function(){return o.now()-i}}var s=[],f=[],y=1,h=null,p=3,g=!1,v=!1,S=!1,T=typeof setTimeout=="function"?setTimeout:null,c=typeof clearTimeout=="function"?clearTimeout:null,a=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function d(C){for(var j=n(f);j!==null;){if(j.callback===null)r(f);else if(j.startTime<=C)r(f),j.sortIndex=j.expirationTime,t(s,j);else break;j=n(f)}}function m(C){if(S=!1,d(C),!v)if(n(s)!==null)v=!0,At(E);else{var j=n(f);j!==null&&vn(m,j.startTime-C)}}function E(C,j){v=!1,S&&(S=!1,c(L),L=-1),g=!0;var R=p;try{for(d(j),h=n(s);h!==null&&(!(h.expirationTime>j)||C&&!le());){var w=h.callback;if(typeof w=="function"){h.callback=null,p=h.priorityLevel;var _=w(h.expirationTime<=j);j=e.unstable_now(),typeof _=="function"?h.callback=_:h===n(s)&&r(s),d(j)}else r(s);h=n(s)}if(h!==null)var B=!0;else{var G=n(f);G!==null&&vn(m,G.startTime-j),B=!1}return B}finally{h=null,p=R,g=!1}}var P=!1,z=null,L=-1,D=5,M=-1;function le(){return!(e.unstable_now()-MC||125w?(C.sortIndex=R,t(f,C),n(s)===null&&C===n(f)&&(S?(c(L),L=-1):S=!0,vn(m,R-w))):(C.sortIndex=_,t(s,C),v||g||(v=!0,At(E))),C},e.unstable_shouldYield=le,e.unstable_wrapCallback=function(C){var j=p;return function(){var R=p;p=j;try{return C.apply(this,arguments)}finally{p=R}}}})(fs);cs.exports=fs;var Mc=cs.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Oc=I,Ee=Mc;function x(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Zl=Object.prototype.hasOwnProperty,Dc=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,$o={},Vo={};function Fc(e){return Zl.call(Vo,e)?!0:Zl.call($o,e)?!1:Dc.test(e)?Vo[e]=!0:($o[e]=!0,!1)}function Ic(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function Uc(e,t,n,r){if(t===null||typeof t>"u"||Ic(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function de(e,t,n,r,l,u,o){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=u,this.removeEmptyString=o}var re={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){re[e]=new de(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];re[t]=new de(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){re[e]=new de(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){re[e]=new de(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){re[e]=new de(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){re[e]=new de(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){re[e]=new de(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){re[e]=new de(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){re[e]=new de(e,5,!1,e.toLowerCase(),null,!1,!1)});var Ku=/[\-:]([a-z])/g;function Xu(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Ku,Xu);re[t]=new de(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Ku,Xu);re[t]=new de(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Ku,Xu);re[t]=new de(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){re[e]=new de(e,1,!1,e.toLowerCase(),null,!1,!1)});re.xlinkHref=new de("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){re[e]=new de(e,1,!1,e.toLowerCase(),null,!0,!0)});function Yu(e,t,n,r){var l=re.hasOwnProperty(t)?re[t]:null;(l!==null?l.type!==0:r||!(2i||l[o]!==u[i]){var s=` +`+l[o].replace(" at new "," at ");return e.displayName&&s.includes("")&&(s=s.replace("",e.displayName)),s}while(1<=o&&0<=i);break}}}finally{Nl=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?_n(e):""}function Ac(e){switch(e.tag){case 5:return _n(e.type);case 16:return _n("Lazy");case 13:return _n("Suspense");case 19:return _n("SuspenseList");case 0:case 2:case 15:return e=_l(e.type,!1),e;case 11:return e=_l(e.type.render,!1),e;case 1:return e=_l(e.type,!0),e;default:return""}}function eu(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Wt:return"Fragment";case Vt:return"Portal";case Jl:return"Profiler";case Gu:return"StrictMode";case ql:return"Suspense";case bl:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case ms:return(e.displayName||"Context")+".Consumer";case ps:return(e._context.displayName||"Context")+".Provider";case Zu:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Ju:return t=e.displayName||null,t!==null?t:eu(e.type)||"Memo";case lt:t=e._payload,e=e._init;try{return eu(e(t))}catch{}}return null}function $c(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return eu(t);case 8:return t===Gu?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function gt(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function vs(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Vc(e){var t=vs(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,u=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(o){r=""+o,u.call(this,o)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(o){r=""+o},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function ar(e){e._valueTracker||(e._valueTracker=Vc(e))}function ys(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=vs(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Fr(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function tu(e,t){var n=t.checked;return K({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Bo(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=gt(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function gs(e,t){t=t.checked,t!=null&&Yu(e,"checked",t,!1)}function nu(e,t){gs(e,t);var n=gt(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?ru(e,t.type,n):t.hasOwnProperty("defaultValue")&&ru(e,t.type,gt(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Ho(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function ru(e,t,n){(t!=="number"||Fr(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Pn=Array.isArray;function bt(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=cr.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function $n(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var jn={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Wc=["Webkit","ms","Moz","O"];Object.keys(jn).forEach(function(e){Wc.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),jn[t]=jn[e]})});function xs(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||jn.hasOwnProperty(e)&&jn[e]?(""+t).trim():t+"px"}function Es(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,l=xs(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,l):e[n]=l}}var Bc=K({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function ou(e,t){if(t){if(Bc[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(x(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(x(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(x(61))}if(t.style!=null&&typeof t.style!="object")throw Error(x(62))}}function iu(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var su=null;function qu(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var au=null,en=null,tn=null;function Xo(e){if(e=ur(e)){if(typeof au!="function")throw Error(x(280));var t=e.stateNode;t&&(t=fl(t),au(e.stateNode,e.type,t))}}function Cs(e){en?tn?tn.push(e):tn=[e]:en=e}function Ns(){if(en){var e=en,t=tn;if(tn=en=null,Xo(e),t)for(e=0;e>>=0,e===0?32:31-(ef(e)/tf|0)|0}var fr=64,dr=4194304;function zn(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function $r(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,l=e.suspendedLanes,u=e.pingedLanes,o=n&268435455;if(o!==0){var i=o&~l;i!==0?r=zn(i):(u&=o,u!==0&&(r=zn(u)))}else o=n&~l,o!==0?r=zn(o):u!==0&&(r=zn(u));if(r===0)return 0;if(t!==0&&t!==r&&!(t&l)&&(l=r&-r,u=t&-t,l>=u||l===16&&(u&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function rr(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Fe(t),e[t]=n}function uf(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Rn),ni=" ",ri=!1;function Qs(e,t){switch(e){case"keyup":return Of.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Ks(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Bt=!1;function Ff(e,t){switch(e){case"compositionend":return Ks(t);case"keypress":return t.which!==32?null:(ri=!0,ni);case"textInput":return e=t.data,e===ni&&ri?null:e;default:return null}}function If(e,t){if(Bt)return e==="compositionend"||!oo&&Qs(e,t)?(e=Bs(),Pr=ro=st=null,Bt=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=ii(n)}}function Zs(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Zs(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Js(){for(var e=window,t=Fr();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Fr(e.document)}return t}function io(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Kf(e){var t=Js(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&Zs(n.ownerDocument.documentElement,n)){if(r!==null&&io(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,u=Math.min(r.start,l);r=r.end===void 0?u:Math.min(r.end,l),!e.extend&&u>r&&(l=r,r=u,u=l),l=si(n,u);var o=si(n,r);l&&o&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==o.node||e.focusOffset!==o.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),u>r?(e.addRange(t),e.extend(o.node,o.offset)):(t.setEnd(o.node,o.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Ht=null,hu=null,On=null,vu=!1;function ai(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;vu||Ht==null||Ht!==Fr(r)||(r=Ht,"selectionStart"in r&&io(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),On&&Kn(On,r)||(On=r,r=Br(hu,"onSelect"),0Xt||(e.current=xu[Xt],xu[Xt]=null,Xt--)}function A(e,t){Xt++,xu[Xt]=e.current,e.current=t}var wt={},se=St(wt),ve=St(!1),Tt=wt;function on(e,t){var n=e.type.contextTypes;if(!n)return wt;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var l={},u;for(u in n)l[u]=t[u];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function ye(e){return e=e.childContextTypes,e!=null}function Qr(){V(ve),V(se)}function vi(e,t,n){if(se.current!==wt)throw Error(x(168));A(se,t),A(ve,n)}function oa(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var l in r)if(!(l in t))throw Error(x(108,$c(e)||"Unknown",l));return K({},n,r)}function Kr(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||wt,Tt=se.current,A(se,e),A(ve,ve.current),!0}function yi(e,t,n){var r=e.stateNode;if(!r)throw Error(x(169));n?(e=oa(e,t,Tt),r.__reactInternalMemoizedMergedChildContext=e,V(ve),V(se),A(se,e)):V(ve),A(ve,n)}var Xe=null,dl=!1,$l=!1;function ia(e){Xe===null?Xe=[e]:Xe.push(e)}function ld(e){dl=!0,ia(e)}function xt(){if(!$l&&Xe!==null){$l=!0;var e=0,t=U;try{var n=Xe;for(U=1;e>=o,l-=o,Ye=1<<32-Fe(t)+l|n<L?(D=z,z=null):D=z.sibling;var M=p(c,z,d[L],m);if(M===null){z===null&&(z=D);break}e&&z&&M.alternate===null&&t(c,z),a=u(M,a,L),P===null?E=M:P.sibling=M,P=M,z=D}if(L===d.length)return n(c,z),W&&Et(c,L),E;if(z===null){for(;LL?(D=z,z=null):D=z.sibling;var le=p(c,z,M.value,m);if(le===null){z===null&&(z=D);break}e&&z&&le.alternate===null&&t(c,z),a=u(le,a,L),P===null?E=le:P.sibling=le,P=le,z=D}if(M.done)return n(c,z),W&&Et(c,L),E;if(z===null){for(;!M.done;L++,M=d.next())M=h(c,M.value,m),M!==null&&(a=u(M,a,L),P===null?E=M:P.sibling=M,P=M);return W&&Et(c,L),E}for(z=r(c,z);!M.done;L++,M=d.next())M=g(z,c,L,M.value,m),M!==null&&(e&&M.alternate!==null&&z.delete(M.key===null?L:M.key),a=u(M,a,L),P===null?E=M:P.sibling=M,P=M);return e&&z.forEach(function(nt){return t(c,nt)}),W&&Et(c,L),E}function T(c,a,d,m){if(typeof d=="object"&&d!==null&&d.type===Wt&&d.key===null&&(d=d.props.children),typeof d=="object"&&d!==null){switch(d.$$typeof){case sr:e:{for(var E=d.key,P=a;P!==null;){if(P.key===E){if(E=d.type,E===Wt){if(P.tag===7){n(c,P.sibling),a=l(P,d.props.children),a.return=c,c=a;break e}}else if(P.elementType===E||typeof E=="object"&&E!==null&&E.$$typeof===lt&&ki(E)===P.type){n(c,P.sibling),a=l(P,d.props),a.ref=xn(c,P,d),a.return=c,c=a;break e}n(c,P);break}else t(c,P);P=P.sibling}d.type===Wt?(a=jt(d.props.children,c.mode,m,d.key),a.return=c,c=a):(m=Dr(d.type,d.key,d.props,null,c.mode,m),m.ref=xn(c,a,d),m.return=c,c=m)}return o(c);case Vt:e:{for(P=d.key;a!==null;){if(a.key===P)if(a.tag===4&&a.stateNode.containerInfo===d.containerInfo&&a.stateNode.implementation===d.implementation){n(c,a.sibling),a=l(a,d.children||[]),a.return=c,c=a;break e}else{n(c,a);break}else t(c,a);a=a.sibling}a=Yl(d,c.mode,m),a.return=c,c=a}return o(c);case lt:return P=d._init,T(c,a,P(d._payload),m)}if(Pn(d))return v(c,a,d,m);if(yn(d))return S(c,a,d,m);wr(c,d)}return typeof d=="string"&&d!==""||typeof d=="number"?(d=""+d,a!==null&&a.tag===6?(n(c,a.sibling),a=l(a,d),a.return=c,c=a):(n(c,a),a=Xl(d,c.mode,m),a.return=c,c=a),o(c)):n(c,a)}return T}var an=fa(!0),da=fa(!1),Gr=St(null),Zr=null,Zt=null,fo=null;function po(){fo=Zt=Zr=null}function mo(e){var t=Gr.current;V(Gr),e._currentValue=t}function Nu(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function rn(e,t){Zr=e,fo=Zt=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(he=!0),e.firstContext=null)}function je(e){var t=e._currentValue;if(fo!==e)if(e={context:e,memoizedValue:t,next:null},Zt===null){if(Zr===null)throw Error(x(308));Zt=e,Zr.dependencies={lanes:0,firstContext:e}}else Zt=Zt.next=e;return t}var Pt=null;function ho(e){Pt===null?Pt=[e]:Pt.push(e)}function pa(e,t,n,r){var l=t.interleaved;return l===null?(n.next=n,ho(t)):(n.next=l.next,l.next=n),t.interleaved=n,be(e,r)}function be(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var ut=!1;function vo(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function ma(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Ze(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function mt(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,F&2){var l=r.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),r.pending=t,be(e,n)}return l=r.interleaved,l===null?(t.next=t,ho(r)):(t.next=l.next,l.next=t),r.interleaved=t,be(e,n)}function Lr(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,eo(e,n)}}function Si(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var l=null,u=null;if(n=n.firstBaseUpdate,n!==null){do{var o={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};u===null?l=u=o:u=u.next=o,n=n.next}while(n!==null);u===null?l=u=t:u=u.next=t}else l=u=t;n={baseState:r.baseState,firstBaseUpdate:l,lastBaseUpdate:u,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function Jr(e,t,n,r){var l=e.updateQueue;ut=!1;var u=l.firstBaseUpdate,o=l.lastBaseUpdate,i=l.shared.pending;if(i!==null){l.shared.pending=null;var s=i,f=s.next;s.next=null,o===null?u=f:o.next=f,o=s;var y=e.alternate;y!==null&&(y=y.updateQueue,i=y.lastBaseUpdate,i!==o&&(i===null?y.firstBaseUpdate=f:i.next=f,y.lastBaseUpdate=s))}if(u!==null){var h=l.baseState;o=0,y=f=s=null,i=u;do{var p=i.lane,g=i.eventTime;if((r&p)===p){y!==null&&(y=y.next={eventTime:g,lane:0,tag:i.tag,payload:i.payload,callback:i.callback,next:null});e:{var v=e,S=i;switch(p=t,g=n,S.tag){case 1:if(v=S.payload,typeof v=="function"){h=v.call(g,h,p);break e}h=v;break e;case 3:v.flags=v.flags&-65537|128;case 0:if(v=S.payload,p=typeof v=="function"?v.call(g,h,p):v,p==null)break e;h=K({},h,p);break e;case 2:ut=!0}}i.callback!==null&&i.lane!==0&&(e.flags|=64,p=l.effects,p===null?l.effects=[i]:p.push(i))}else g={eventTime:g,lane:p,tag:i.tag,payload:i.payload,callback:i.callback,next:null},y===null?(f=y=g,s=h):y=y.next=g,o|=p;if(i=i.next,i===null){if(i=l.shared.pending,i===null)break;p=i,i=p.next,p.next=null,l.lastBaseUpdate=p,l.shared.pending=null}}while(!0);if(y===null&&(s=h),l.baseState=s,l.firstBaseUpdate=f,l.lastBaseUpdate=y,t=l.shared.interleaved,t!==null){l=t;do o|=l.lane,l=l.next;while(l!==t)}else u===null&&(l.shared.lanes=0);Ot|=o,e.lanes=o,e.memoizedState=h}}function xi(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=Wl.transition;Wl.transition={};try{e(!1),t()}finally{U=n,Wl.transition=r}}function Ta(){return Te().memoizedState}function sd(e,t,n){var r=vt(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Ra(e))Ma(t,n);else if(n=pa(e,t,n,r),n!==null){var l=ce();Ie(n,e,r,l),Oa(n,t,r)}}function ad(e,t,n){var r=vt(e),l={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Ra(e))Ma(t,l);else{var u=e.alternate;if(e.lanes===0&&(u===null||u.lanes===0)&&(u=t.lastRenderedReducer,u!==null))try{var o=t.lastRenderedState,i=u(o,n);if(l.hasEagerState=!0,l.eagerState=i,Ue(i,o)){var s=t.interleaved;s===null?(l.next=l,ho(t)):(l.next=s.next,s.next=l),t.interleaved=l;return}}catch{}finally{}n=pa(e,t,l,r),n!==null&&(l=ce(),Ie(n,e,r,l),Oa(n,t,r))}}function Ra(e){var t=e.alternate;return e===Q||t!==null&&t===Q}function Ma(e,t){Dn=br=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Oa(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,eo(e,n)}}var el={readContext:je,useCallback:ue,useContext:ue,useEffect:ue,useImperativeHandle:ue,useInsertionEffect:ue,useLayoutEffect:ue,useMemo:ue,useReducer:ue,useRef:ue,useState:ue,useDebugValue:ue,useDeferredValue:ue,useTransition:ue,useMutableSource:ue,useSyncExternalStore:ue,useId:ue,unstable_isNewReconciler:!1},cd={readContext:je,useCallback:function(e,t){return $e().memoizedState=[e,t===void 0?null:t],e},useContext:je,useEffect:Ci,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Tr(4194308,4,_a.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Tr(4194308,4,e,t)},useInsertionEffect:function(e,t){return Tr(4,2,e,t)},useMemo:function(e,t){var n=$e();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=$e();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=sd.bind(null,Q,e),[r.memoizedState,e]},useRef:function(e){var t=$e();return e={current:e},t.memoizedState=e},useState:Ei,useDebugValue:Co,useDeferredValue:function(e){return $e().memoizedState=e},useTransition:function(){var e=Ei(!1),t=e[0];return e=id.bind(null,e[1]),$e().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=Q,l=$e();if(W){if(n===void 0)throw Error(x(407));n=n()}else{if(n=t(),ee===null)throw Error(x(349));Mt&30||ga(r,t,n)}l.memoizedState=n;var u={value:n,getSnapshot:t};return l.queue=u,Ci(ka.bind(null,r,u,e),[e]),r.flags|=2048,er(9,wa.bind(null,r,u,n,t),void 0,null),n},useId:function(){var e=$e(),t=ee.identifierPrefix;if(W){var n=Ge,r=Ye;n=(r&~(1<<32-Fe(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=qn++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=o.createElement(n,{is:r.is}):(e=o.createElement(n),n==="select"&&(o=e,r.multiple?o.multiple=!0:r.size&&(o.size=r.size))):e=o.createElementNS(e,n),e[Ve]=t,e[Gn]=r,Ha(e,t,!1,!1),t.stateNode=e;e:{switch(o=iu(n,r),n){case"dialog":$("cancel",e),$("close",e),l=r;break;case"iframe":case"object":case"embed":$("load",e),l=r;break;case"video":case"audio":for(l=0;ldn&&(t.flags|=128,r=!0,En(u,!1),t.lanes=4194304)}else{if(!r)if(e=qr(o),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),En(u,!0),u.tail===null&&u.tailMode==="hidden"&&!o.alternate&&!W)return oe(t),null}else 2*Y()-u.renderingStartTime>dn&&n!==1073741824&&(t.flags|=128,r=!0,En(u,!1),t.lanes=4194304);u.isBackwards?(o.sibling=t.child,t.child=o):(n=u.last,n!==null?n.sibling=o:t.child=o,u.last=o)}return u.tail!==null?(t=u.tail,u.rendering=t,u.tail=t.sibling,u.renderingStartTime=Y(),t.sibling=null,n=H.current,A(H,r?n&1|2:n&1),t):(oe(t),null);case 22:case 23:return jo(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?ke&1073741824&&(oe(t),t.subtreeFlags&6&&(t.flags|=8192)):oe(t),null;case 24:return null;case 25:return null}throw Error(x(156,t.tag))}function gd(e,t){switch(ao(t),t.tag){case 1:return ye(t.type)&&Qr(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return cn(),V(ve),V(se),wo(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return go(t),null;case 13:if(V(H),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(x(340));sn()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return V(H),null;case 4:return cn(),null;case 10:return mo(t.type._context),null;case 22:case 23:return jo(),null;case 24:return null;default:return null}}var Sr=!1,ie=!1,wd=typeof WeakSet=="function"?WeakSet:Set,N=null;function Jt(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){X(e,t,r)}else n.current=null}function Ou(e,t,n){try{n()}catch(r){X(e,t,r)}}var Di=!1;function kd(e,t){if(yu=Vr,e=Js(),io(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,u=r.focusNode;r=r.focusOffset;try{n.nodeType,u.nodeType}catch{n=null;break e}var o=0,i=-1,s=-1,f=0,y=0,h=e,p=null;t:for(;;){for(var g;h!==n||l!==0&&h.nodeType!==3||(i=o+l),h!==u||r!==0&&h.nodeType!==3||(s=o+r),h.nodeType===3&&(o+=h.nodeValue.length),(g=h.firstChild)!==null;)p=h,h=g;for(;;){if(h===e)break t;if(p===n&&++f===l&&(i=o),p===u&&++y===r&&(s=o),(g=h.nextSibling)!==null)break;h=p,p=h.parentNode}h=g}n=i===-1||s===-1?null:{start:i,end:s}}else n=null}n=n||{start:0,end:0}}else n=null;for(gu={focusedElem:e,selectionRange:n},Vr=!1,N=t;N!==null;)if(t=N,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,N=e;else for(;N!==null;){t=N;try{var v=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(v!==null){var S=v.memoizedProps,T=v.memoizedState,c=t.stateNode,a=c.getSnapshotBeforeUpdate(t.elementType===t.type?S:Me(t.type,S),T);c.__reactInternalSnapshotBeforeUpdate=a}break;case 3:var d=t.stateNode.containerInfo;d.nodeType===1?d.textContent="":d.nodeType===9&&d.documentElement&&d.removeChild(d.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(x(163))}}catch(m){X(t,t.return,m)}if(e=t.sibling,e!==null){e.return=t.return,N=e;break}N=t.return}return v=Di,Di=!1,v}function Fn(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var u=l.destroy;l.destroy=void 0,u!==void 0&&Ou(t,n,u)}l=l.next}while(l!==r)}}function hl(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Du(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Xa(e){var t=e.alternate;t!==null&&(e.alternate=null,Xa(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Ve],delete t[Gn],delete t[Su],delete t[nd],delete t[rd])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Ya(e){return e.tag===5||e.tag===3||e.tag===4}function Fi(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Ya(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Fu(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Hr));else if(r!==4&&(e=e.child,e!==null))for(Fu(e,t,n),e=e.sibling;e!==null;)Fu(e,t,n),e=e.sibling}function Iu(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Iu(e,t,n),e=e.sibling;e!==null;)Iu(e,t,n),e=e.sibling}var te=null,Oe=!1;function rt(e,t,n){for(n=n.child;n!==null;)Ga(e,t,n),n=n.sibling}function Ga(e,t,n){if(We&&typeof We.onCommitFiberUnmount=="function")try{We.onCommitFiberUnmount(il,n)}catch{}switch(n.tag){case 5:ie||Jt(n,t);case 6:var r=te,l=Oe;te=null,rt(e,t,n),te=r,Oe=l,te!==null&&(Oe?(e=te,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):te.removeChild(n.stateNode));break;case 18:te!==null&&(Oe?(e=te,n=n.stateNode,e.nodeType===8?Al(e.parentNode,n):e.nodeType===1&&Al(e,n),Hn(e)):Al(te,n.stateNode));break;case 4:r=te,l=Oe,te=n.stateNode.containerInfo,Oe=!0,rt(e,t,n),te=r,Oe=l;break;case 0:case 11:case 14:case 15:if(!ie&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var u=l,o=u.destroy;u=u.tag,o!==void 0&&(u&2||u&4)&&Ou(n,t,o),l=l.next}while(l!==r)}rt(e,t,n);break;case 1:if(!ie&&(Jt(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(i){X(n,t,i)}rt(e,t,n);break;case 21:rt(e,t,n);break;case 22:n.mode&1?(ie=(r=ie)||n.memoizedState!==null,rt(e,t,n),ie=r):rt(e,t,n);break;default:rt(e,t,n)}}function Ii(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new wd),t.forEach(function(r){var l=Ld.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function Re(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=o),r&=~u}if(r=l,r=Y()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*xd(r/1960))-r,10e?16:e,at===null)var r=!1;else{if(e=at,at=null,rl=0,F&6)throw Error(x(331));var l=F;for(F|=4,N=e.current;N!==null;){var u=N,o=u.child;if(N.flags&16){var i=u.deletions;if(i!==null){for(var s=0;sY()-zo?Lt(e,0):Po|=n),ge(e,t)}function rc(e,t){t===0&&(e.mode&1?(t=dr,dr<<=1,!(dr&130023424)&&(dr=4194304)):t=1);var n=ce();e=be(e,t),e!==null&&(rr(e,t,n),ge(e,n))}function zd(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),rc(e,n)}function Ld(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(x(314))}r!==null&&r.delete(t),rc(e,n)}var lc;lc=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||ve.current)he=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return he=!1,vd(e,t,n);he=!!(e.flags&131072)}else he=!1,W&&t.flags&1048576&&sa(t,Yr,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Rr(e,t),e=t.pendingProps;var l=on(t,se.current);rn(t,n),l=So(null,t,r,e,l,n);var u=xo();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,ye(r)?(u=!0,Kr(t)):u=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,vo(t),l.updater=ml,t.stateNode=l,l._reactInternals=t,Pu(t,r,e,n),t=ju(null,t,r,!0,u,n)):(t.tag=0,W&&u&&so(t),ae(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Rr(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=Td(r),e=Me(r,e),l){case 0:t=Lu(null,t,r,e,n);break e;case 1:t=Ri(null,t,r,e,n);break e;case 11:t=ji(null,t,r,e,n);break e;case 14:t=Ti(null,t,r,Me(r.type,e),n);break e}throw Error(x(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Me(r,l),Lu(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Me(r,l),Ri(e,t,r,l,n);case 3:e:{if(Va(t),e===null)throw Error(x(387));r=t.pendingProps,u=t.memoizedState,l=u.element,ma(e,t),Jr(t,r,null,n);var o=t.memoizedState;if(r=o.element,u.isDehydrated)if(u={element:r,isDehydrated:!1,cache:o.cache,pendingSuspenseBoundaries:o.pendingSuspenseBoundaries,transitions:o.transitions},t.updateQueue.baseState=u,t.memoizedState=u,t.flags&256){l=fn(Error(x(423)),t),t=Mi(e,t,r,n,l);break e}else if(r!==l){l=fn(Error(x(424)),t),t=Mi(e,t,r,n,l);break e}else for(Se=pt(t.stateNode.containerInfo.firstChild),xe=t,W=!0,De=null,n=da(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(sn(),r===l){t=et(e,t,n);break e}ae(e,t,r,n)}t=t.child}return t;case 5:return ha(t),e===null&&Cu(t),r=t.type,l=t.pendingProps,u=e!==null?e.memoizedProps:null,o=l.children,wu(r,l)?o=null:u!==null&&wu(r,u)&&(t.flags|=32),$a(e,t),ae(e,t,o,n),t.child;case 6:return e===null&&Cu(t),null;case 13:return Wa(e,t,n);case 4:return yo(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=an(t,null,r,n):ae(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Me(r,l),ji(e,t,r,l,n);case 7:return ae(e,t,t.pendingProps,n),t.child;case 8:return ae(e,t,t.pendingProps.children,n),t.child;case 12:return ae(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,u=t.memoizedProps,o=l.value,A(Gr,r._currentValue),r._currentValue=o,u!==null)if(Ue(u.value,o)){if(u.children===l.children&&!ve.current){t=et(e,t,n);break e}}else for(u=t.child,u!==null&&(u.return=t);u!==null;){var i=u.dependencies;if(i!==null){o=u.child;for(var s=i.firstContext;s!==null;){if(s.context===r){if(u.tag===1){s=Ze(-1,n&-n),s.tag=2;var f=u.updateQueue;if(f!==null){f=f.shared;var y=f.pending;y===null?s.next=s:(s.next=y.next,y.next=s),f.pending=s}}u.lanes|=n,s=u.alternate,s!==null&&(s.lanes|=n),Nu(u.return,n,t),i.lanes|=n;break}s=s.next}}else if(u.tag===10)o=u.type===t.type?null:u.child;else if(u.tag===18){if(o=u.return,o===null)throw Error(x(341));o.lanes|=n,i=o.alternate,i!==null&&(i.lanes|=n),Nu(o,n,t),o=u.sibling}else o=u.child;if(o!==null)o.return=u;else for(o=u;o!==null;){if(o===t){o=null;break}if(u=o.sibling,u!==null){u.return=o.return,o=u;break}o=o.return}u=o}ae(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,rn(t,n),l=je(l),r=r(l),t.flags|=1,ae(e,t,r,n),t.child;case 14:return r=t.type,l=Me(r,t.pendingProps),l=Me(r.type,l),Ti(e,t,r,l,n);case 15:return Ua(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Me(r,l),Rr(e,t),t.tag=1,ye(r)?(e=!0,Kr(t)):e=!1,rn(t,n),Da(t,r,l),Pu(t,r,l,n),ju(null,t,r,!0,e,n);case 19:return Ba(e,t,n);case 22:return Aa(e,t,n)}throw Error(x(156,t.tag))};function uc(e,t){return Rs(e,t)}function jd(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function ze(e,t,n,r){return new jd(e,t,n,r)}function Ro(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Td(e){if(typeof e=="function")return Ro(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Zu)return 11;if(e===Ju)return 14}return 2}function yt(e,t){var n=e.alternate;return n===null?(n=ze(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Dr(e,t,n,r,l,u){var o=2;if(r=e,typeof e=="function")Ro(e)&&(o=1);else if(typeof e=="string")o=5;else e:switch(e){case Wt:return jt(n.children,l,u,t);case Gu:o=8,l|=8;break;case Jl:return e=ze(12,n,t,l|2),e.elementType=Jl,e.lanes=u,e;case ql:return e=ze(13,n,t,l),e.elementType=ql,e.lanes=u,e;case bl:return e=ze(19,n,t,l),e.elementType=bl,e.lanes=u,e;case hs:return yl(n,l,u,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case ps:o=10;break e;case ms:o=9;break e;case Zu:o=11;break e;case Ju:o=14;break e;case lt:o=16,r=null;break e}throw Error(x(130,e==null?e:typeof e,""))}return t=ze(o,n,t,l),t.elementType=e,t.type=r,t.lanes=u,t}function jt(e,t,n,r){return e=ze(7,e,r,t),e.lanes=n,e}function yl(e,t,n,r){return e=ze(22,e,r,t),e.elementType=hs,e.lanes=n,e.stateNode={isHidden:!1},e}function Xl(e,t,n){return e=ze(6,e,null,t),e.lanes=n,e}function Yl(e,t,n){return t=ze(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Rd(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=zl(0),this.expirationTimes=zl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=zl(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Mo(e,t,n,r,l,u,o,i,s){return e=new Rd(e,t,n,i,s),t===1?(t=1,u===!0&&(t|=8)):t=0,u=ze(3,null,null,t),e.current=u,u.stateNode=e,u.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},vo(u),e}function Md(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(ac)}catch(e){console.error(e)}}ac(),as.exports=Ce;var Ud=as.exports,cc,Qi=Ud;cc=Qi.createRoot,Qi.hydrateRoot;function Ad(e,t){const n=I.useRef(null),r=I.useRef(t);return r.current=t,I.useEffect(()=>{const u=new WebSocket(e);return n.current=u,u.onmessage=o=>{try{r.current(JSON.parse(o.data))}catch{}},u.onerror=o=>console.error("WebSocket error",o),()=>u.close()},[e]),{send:I.useCallback(u=>{var o;(o=n.current)==null||o.send(JSON.stringify(u))},[])}}const $d=/\.(mp4|mov|avi|webm|mkv)$/i;function Vd({onUpload:e}){const[t,n]=I.useState(!1),r=I.useRef(null),l=i=>{$d.test(i.name)&&e(i)},u=i=>{i.preventDefault(),n(!1);const s=i.dataTransfer.files[0];s&&l(s)},o=i=>{var f;const s=(f=i.target.files)==null?void 0:f[0];s&&l(s)};return k.jsxs("div",{className:`upload-zone ${t?"dragging":""}`,onClick:()=>{var i;return(i=r.current)==null?void 0:i.click()},onDragOver:i=>{i.preventDefault(),n(!0)},onDragLeave:()=>n(!1),onDrop:u,children:[k.jsx("div",{className:"upload-icon",children:"↑"}),k.jsx("p",{className:"upload-label",children:"Drop your A-roll clip here"}),k.jsx("p",{className:"upload-sub",children:"or click to browse"}),k.jsx("p",{className:"upload-formats",children:"MP4 · MOV · AVI · WebM · MKV"}),k.jsx("input",{ref:r,type:"file",accept:"video/*",style:{display:"none"},onChange:o})]})}const Ki=80,Nn=60,Xi=120,Yi=68,Gi=.25,Zi=8;function Wd({videoUrl:e,duration:t,segments:n,onToggle:r,disabled:l}){const u=I.useRef(null),o=I.useRef(null),i=I.useRef(null),[s,f]=I.useState([]),[y,h]=I.useState(0),[p,g]=I.useState(!1),[v,S]=I.useState(!1),[T,c]=I.useState(1),[a,d]=I.useState(t),m=t>0?t:a,E=I.useRef(1),P=I.useRef(m);P.current=m,I.useEffect(()=>{const w=u.current;if(!w)return;const _=()=>{isFinite(w.duration)&&d(w.duration)};return w.addEventListener("loadedmetadata",_),isFinite(w.duration)&&w.duration>0&&d(w.duration),()=>w.removeEventListener("loadedmetadata",_)},[]);const z=Math.max(Math.round(m*Ki),1),L=Math.max(Math.ceil(z/80),1),D=Math.max(Math.round(m*Ki*T),1),M=D/L;E.current=D,I.useEffect(()=>{if(!e||m===0)return;f([]);const w=document.createElement("video"),_=document.createElement("canvas");_.width=Xi,_.height=Yi;const B=_.getContext("2d"),G=[];let we=0,pe=!1;const Qe=()=>{pe||we>=L||(w.currentTime=(we+.5)/L*m)};return w.addEventListener("loadedmetadata",()=>{pe||Qe()}),w.addEventListener("seeked",()=>{pe||(B.drawImage(w,0,0,Xi,Yi),G.push(_.toDataURL("image/jpeg",.55)),we++,f([...G]),Qe())}),w.src=e,w.muted=!0,w.preload="auto",()=>{pe=!0,w.src=""}},[e,m,L]),I.useEffect(()=>{const w=u.current;if(!w)return;const _=()=>{v||h(w.currentTime)},B=()=>g(!0),G=()=>g(!1),we=()=>g(!1);return w.addEventListener("timeupdate",_),w.addEventListener("play",B),w.addEventListener("pause",G),w.addEventListener("ended",we),()=>{w.removeEventListener("timeupdate",_),w.removeEventListener("play",B),w.removeEventListener("pause",G),w.removeEventListener("ended",we)}},[v]),I.useEffect(()=>{if(!p||!o.current||m===0)return;const w=o.current,_=y/m*D,{scrollLeft:B,clientWidth:G}=w;(_>B+G-80||_{const w=o.current,_=le.current;!w||!_||m===0||(le.current=null,w.scrollLeft=_.time/m*E.current-_.screenOffset)},[T,m]),I.useEffect(()=>{const w=o.current;if(!w)return;const _=B=>{if(!B.ctrlKey&&!B.metaKey)return;B.preventDefault();const G=w.getBoundingClientRect(),we=B.clientX-G.left,pe=(we+w.scrollLeft)/E.current*P.current;le.current={time:pe,screenOffset:we};const Qe=B.deltaY<0?1.15:1/1.15;c(fc=>Math.max(Gi,Math.min(Zi,fc*Qe)))};return w.addEventListener("wheel",_,{passive:!1}),()=>w.removeEventListener("wheel",_)},[]);const nt=w=>{const _=o.current;if(_&&m>0){const G=(_.scrollLeft+_.clientWidth/2)/E.current*m;le.current={time:G,screenOffset:_.clientWidth/2}}c(w)},He=I.useCallback(w=>{if(!i.current||m===0)return 0;const _=i.current.getBoundingClientRect(),B=w-_.left;return Math.max(0,Math.min(m,B/D*m))},[m,D]),Ut=I.useCallback(w=>{h(w),u.current&&(u.current.currentTime=w)},[]),xl=w=>{var _;w.button===0&&(S(!0),Ut(He(w.clientX)),(_=u.current)==null||_.pause())};I.useEffect(()=>{if(!v)return;const w=B=>Ut(He(B.clientX)),_=()=>S(!1);return window.addEventListener("mousemove",w),window.addEventListener("mouseup",_),()=>{window.removeEventListener("mousemove",w),window.removeEventListener("mouseup",_)}},[v,He,Ut]);const At=()=>{const w=u.current;w&&(p?w.pause():w.play())},vn=Bd(n,m),C=Hd(m,D),j=m>0?y/m*D:0,R=n.filter(w=>w.kept).length;return k.jsxs("div",{className:"vt-root",children:[k.jsxs("div",{className:"vt-preview",children:[k.jsx("video",{ref:u,src:e,className:"vt-video",preload:"metadata",onClick:At}),k.jsxs("div",{className:"vt-controls-bar",children:[k.jsx("button",{className:"vt-play-btn",onClick:At,"aria-label":p?"Pause":"Play",children:p?"⏸":"▶"}),k.jsxs("span",{className:"vt-timecode",children:[Nt(y)," / ",Nt(m)]})]})]}),k.jsxs("div",{className:"vt-zoom-bar",children:[k.jsx("span",{className:"vt-zoom-label",children:"Zoom"}),k.jsx("input",{type:"range",min:Gi,max:Zi,step:.05,value:T,onChange:w=>nt(Number(w.target.value)),className:"vt-zoom-slider",title:"Ctrl+Wheel on the timeline also zooms"}),k.jsxs("span",{className:"vt-zoom-value",children:[T.toFixed(1),"×"]}),Math.abs(T-1)>.01&&k.jsx("button",{className:"vt-zoom-reset",onClick:()=>nt(1),children:"Reset"})]}),k.jsxs("div",{ref:o,className:"vt-scroll",children:[k.jsx("div",{className:"vt-ruler",style:{minWidth:D},children:C.map((w,_)=>k.jsx("span",{className:"vt-tick",style:{left:w.x},children:w.label},_))}),k.jsxs("div",{ref:i,className:"vt-track",style:{width:D},onMouseDown:xl,children:[k.jsx("div",{className:"vt-thumbs",style:{height:Nn},children:Array.from({length:L},(w,_)=>k.jsx("div",{className:"vt-thumb",style:{width:M,height:Nn},children:s[_]?k.jsx("img",{src:s[_],style:{width:"100%",height:"100%",objectFit:"cover",display:"block"},draggable:!1}):k.jsx("div",{className:"vt-thumb-skeleton"})},_))}),vn.map((w,_)=>k.jsx("div",{className:"vt-silence",style:{left:w.start/m*D,width:Math.max(2,(w.end-w.start)/m*D),height:Nn}},_)),n.map((w,_)=>k.jsx("div",{className:`vt-seg ${w.kept?"kept":"skipped"}`,style:{left:w.start/m*D,width:Math.max(2,(w.end-w.start)/m*D),height:Nn},onClick:()=>{l||r(_)},title:w.kept?`Speech ${Nt(w.start)}–${Nt(w.end)} · click to exclude`:`Excluded ${Nt(w.start)}–${Nt(w.end)} · click to include`},_)),k.jsxs("div",{className:"vt-playhead",style:{left:j},children:[k.jsx("div",{className:"vt-playhead-nub"}),k.jsx("div",{className:"vt-playhead-line",style:{height:Nn}})]})]})]}),k.jsxs("div",{className:"vt-legend",children:[k.jsxs("span",{className:"vt-leg vt-leg-kept",children:["■ Speech kept (",R,")"]}),k.jsx("span",{className:"vt-leg vt-leg-skip",children:"■ Toggled off"}),k.jsx("span",{className:"vt-leg vt-leg-sil",children:"▨ Silence — will be removed"}),!l&&k.jsx("span",{className:"vt-leg vt-leg-hint",children:"Click a speech region to include / exclude it"})]})]})}function Bd(e,t){if(t===0)return[];const n=[];let r=0;for(const l of e)l.start>r+.01&&n.push({start:r,end:l.start}),r=l.end;return ro>=r)??600;for(let o=0;o<=e+.001;o+=u)n.push({x:o/e*t,label:Nt(o)});return n}function Nt(e){const t=Math.floor(e/60),n=Math.floor(e%60).toString().padStart(2,"0");return`${t}:${n}`}function Qd({noiseDb:e,minSilence:t,padding:n,disabled:r,onNoiseDb:l,onMinSilence:u,onPadding:o,onReanalyze:i}){return k.jsxs("div",{className:"controls",children:[k.jsxs("div",{className:"control-group",children:[k.jsxs("label",{children:["Noise threshold",k.jsxs("span",{className:"control-value",children:[e," dB"]})]}),k.jsx("input",{type:"range",min:-60,max:-10,step:1,value:e,disabled:r,onChange:s=>l(Number(s.target.value))}),k.jsxs("div",{className:"control-hint",children:[k.jsx("span",{children:"Quiet (−60)"}),k.jsx("span",{children:"Loud (−10)"})]}),k.jsx("p",{className:"control-tip",children:"Lower = only very quiet gaps removed. Raise if pauses are not being caught."})]}),k.jsxs("div",{className:"control-group",children:[k.jsxs("label",{children:["Min silence length",k.jsxs("span",{className:"control-value",children:[t.toFixed(1),"s"]})]}),k.jsx("input",{type:"range",min:.1,max:3,step:.1,value:t,disabled:r,onChange:s=>u(Number(s.target.value))}),k.jsxs("div",{className:"control-hint",children:[k.jsx("span",{children:"0.1s"}),k.jsx("span",{children:"3.0s"})]}),k.jsx("p",{className:"control-tip",children:"Gaps shorter than this are left in."})]}),k.jsxs("div",{className:"control-group",children:[k.jsxs("label",{children:["Speech padding",k.jsxs("span",{className:"control-value",children:[n.toFixed(2),"s"]})]}),k.jsx("input",{type:"range",min:0,max:.5,step:.01,value:n,disabled:r,onChange:s=>o(Number(s.target.value))}),k.jsxs("div",{className:"control-hint",children:[k.jsx("span",{children:"None"}),k.jsx("span",{children:"0.5s"})]}),k.jsx("p",{className:"control-tip",children:"Buffer kept around each speech burst to avoid clipping words."})]}),k.jsx("button",{className:"btn-secondary reanalyze-btn",onClick:i,disabled:r,children:"Re-analyze"})]})}const Kd=`${window.location.protocol==="https:"?"wss:":"ws:"}//${window.location.host}/ws`,Ji={phase:"idle",filename:null,videoUrl:null,duration:0,segments:[],progress:0,outputFile:null,error:null,noiseDb:-30,minSilence:.5,padding:.1};function Xd(){const[e,t]=I.useState(Ji),n=I.useCallback(g=>{const v=g;t(S=>{switch(v.type){case"segments":return{...S,phase:"ready",duration:v.duration,segments:v.segments.map(T=>({...T,kept:!0}))};case"progress":return{...S,progress:v.percent};case"done":return{...S,phase:"done",outputFile:v.message,progress:100};case"error":return{...S,phase:"ready",error:v.message};default:return S}})},[]);Ad(Kd,n);const r=async(g,v,S,T)=>{t(c=>({...c,phase:"analyzing",segments:[],error:null}));try{const c=await fetch("/analyze",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({filename:g,noiseDb:v,minSilence:S,padding:T})});if(!c.ok)throw new Error(await c.text())}catch(c){t(a=>({...a,phase:"ready",error:String(c)}))}},l=async g=>{const v=URL.createObjectURL(g);t(S=>({...S,phase:"uploading",error:null,videoUrl:v}));try{const S=new FormData;S.append("video",g);const T=await fetch("/upload",{method:"POST",body:S});if(!T.ok)throw new Error(await T.text());const{filename:c}=await T.json();t(a=>({...a,filename:c})),await r(c,e.noiseDb,e.minSilence,e.padding)}catch(S){t(T=>({...T,phase:"idle",error:String(S)}))}},u=()=>{e.filename&&r(e.filename,e.noiseDb,e.minSilence,e.padding)},o=g=>{t(v=>({...v,segments:v.segments.map((S,T)=>T===g?{...S,kept:!S.kept}:S)}))},i=async()=>{if(!e.filename)return;const g=e.segments.filter(v=>v.kept).map(({start:v,end:S})=>({start:v,end:S}));t(v=>({...v,phase:"exporting",progress:0,outputFile:null,error:null}));try{const v=await fetch("/export",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({filename:e.filename,segments:g})});if(!v.ok)throw new Error(await v.text())}catch(v){t(S=>({...S,phase:"ready",error:String(v)}))}},s=()=>{e.videoUrl&&URL.revokeObjectURL(e.videoUrl),t(Ji)},f=e.segments.filter(g=>g.kept).reduce((g,v)=>g+(v.end-v.start),0),y=e.duration-f,h=e.segments.filter(g=>g.kept).length,p=e.videoUrl!==null&&e.phase!=="idle";return k.jsxs("div",{className:"app",children:[k.jsxs("header",{className:"app-header",children:[k.jsx("h1",{children:"A-Roll Cutter"}),k.jsx("p",{children:"Automatically removes silence and warm-up from your recordings"})]}),k.jsxs("main",{className:"app-main",children:[e.error&&k.jsxs("div",{className:"error-banner",children:[k.jsx("span",{children:e.error}),k.jsx("button",{onClick:()=>t(g=>({...g,error:null})),children:"✕"})]}),e.phase==="idle"&&k.jsx(Vd,{onUpload:l}),e.phase==="uploading"&&k.jsxs("div",{className:"status-card",children:[k.jsx("div",{className:"spinner"}),k.jsx("p",{children:"Uploading video..."})]}),p&&k.jsx(Wd,{videoUrl:e.videoUrl,duration:e.duration,segments:e.segments,onToggle:o,disabled:e.phase!=="ready"}),e.phase==="analyzing"&&k.jsxs("div",{className:"status-card status-card--inline",children:[k.jsx("div",{className:"spinner"}),k.jsx("p",{children:"Detecting silence..."}),k.jsx("p",{className:"status-sub",children:"FFmpeg is scanning the audio track"})]}),(e.phase==="ready"||e.phase==="exporting"||e.phase==="done")&&k.jsxs(k.Fragment,{children:[k.jsx(Qd,{noiseDb:e.noiseDb,minSilence:e.minSilence,padding:e.padding,disabled:e.phase!=="ready",onNoiseDb:g=>t(v=>({...v,noiseDb:g})),onMinSilence:g=>t(v=>({...v,minSilence:g})),onPadding:g=>t(v=>({...v,padding:g})),onReanalyze:u}),k.jsxs("div",{className:"stats",children:[k.jsxs("span",{className:"stat stat-kept",children:["Keeping ",Gl(f)]}),k.jsxs("span",{className:"stat stat-removed",children:["Removing ",Gl(y)]}),k.jsxs("span",{className:"stat stat-total",children:[h," segments · ",Gl(e.duration)," total"]})]}),e.phase==="ready"&&k.jsxs("div",{className:"actions",children:[k.jsx("button",{className:"btn-secondary",onClick:s,children:"Start Over"}),k.jsx("button",{className:"btn-primary",onClick:i,disabled:h===0,children:"Export"})]}),e.phase==="exporting"&&k.jsxs("div",{className:"progress-section",children:[k.jsxs("p",{className:"progress-label",children:["Exporting... ",Math.round(e.progress),"%"]}),k.jsx("div",{className:"progress-track",children:k.jsx("div",{className:"progress-fill",style:{width:`${e.progress}%`}})})]}),e.phase==="done"&&e.outputFile&&k.jsxs("div",{className:"done-panel",children:[k.jsx("span",{className:"done-check",children:"✓"}),k.jsx("p",{children:"Export complete!"}),k.jsx("a",{href:`/download/${e.outputFile}`,download:!0,className:"btn-primary",children:"Download"}),k.jsx("button",{className:"btn-secondary",onClick:s,children:"Process Another"})]})]})]})]})}function Gl(e){const t=Math.floor(e/60),n=Math.floor(e%60);return t>0?`${t}m ${n}s`:`${n}s`}cc(document.getElementById("root")).render(k.jsx(I.StrictMode,{children:k.jsx(Xd,{})})); diff --git a/frontend/dist/assets/index-C-b2ubsn.css b/frontend/dist/assets/index-C-b2ubsn.css new file mode 100644 index 0000000..92c4174 --- /dev/null +++ b/frontend/dist/assets/index-C-b2ubsn.css @@ -0,0 +1 @@ +*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}:root{--bg: #111111;--surface: #1c1c1c;--surface-2: #252525;--border: #2e2e2e;--border-2: #3a3a3a;--text: #e2e2e2;--text-muted: #777;--text-dim: #555;--green: #22c55e;--green-dim: #14532d;--red: #ef4444;--blue: #3b82f6;--blue-hover: #2563eb}html,body{height:100%}body{background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,system-ui,sans-serif;font-size:14px;line-height:1.55;-webkit-font-smoothing:antialiased}.app{max-width:860px;margin:0 auto;padding:32px 20px 64px}.app-header{margin-bottom:36px}.app-header h1{font-size:22px;font-weight:600;letter-spacing:-.4px;color:#fff}.app-header p{margin-top:4px;color:var(--text-muted);font-size:13px}.app-main{display:flex;flex-direction:column;gap:14px}.upload-zone{border:2px dashed var(--border-2);border-radius:12px;padding:72px 40px;text-align:center;cursor:pointer;transition:border-color .18s,background .18s;-webkit-user-select:none;user-select:none}.upload-zone:hover,.upload-zone.dragging{border-color:var(--blue);background:#3b82f60a}.upload-icon{font-size:36px;opacity:.35;margin-bottom:14px;line-height:1}.upload-label{font-size:17px;font-weight:500;color:#fff;margin-bottom:6px}.upload-sub{color:var(--text-muted);margin-bottom:16px}.upload-formats{display:inline-block;padding:4px 14px;border-radius:20px;background:var(--surface);border:1px solid var(--border);font-size:12px;color:var(--text-muted);letter-spacing:.5px}.status-card{display:flex;flex-direction:column;align-items:center;gap:14px;padding:64px 40px;background:var(--surface);border:1px solid var(--border);border-radius:12px;color:var(--text-muted)}.status-sub{font-size:12px;color:var(--text-dim)}.spinner{width:28px;height:28px;border:2px solid var(--border-2);border-top-color:var(--blue);border-radius:50%;animation:spin .75s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.controls{display:grid;grid-template-columns:1fr 1fr 1fr auto;gap:20px;align-items:end;background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px}.control-group{display:flex;flex-direction:column;gap:8px}.control-group label{display:flex;justify-content:space-between;font-size:12px;font-weight:500;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px}.control-value{color:var(--text);font-variant-numeric:tabular-nums;text-transform:none;letter-spacing:0;font-weight:400}.control-group input[type=range]{width:100%;height:4px;accent-color:var(--blue);cursor:pointer}.control-group input[type=range]:disabled{opacity:.35;cursor:not-allowed}.control-hint{display:flex;justify-content:space-between;font-size:11px;color:var(--text-dim)}.control-tip{font-size:11px;color:var(--text-dim);line-height:1.4}.reanalyze-btn{white-space:nowrap;align-self:end}.timeline-container{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px}.timeline-header{display:flex;align-items:baseline;gap:12px;margin-bottom:14px}.timeline-title{font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.6px;color:var(--text-muted)}.timeline-subtitle{font-size:12px;color:var(--text-dim)}.timeline-bar{display:flex;height:56px;border-radius:6px;overflow:hidden;background:var(--border);gap:1px}.timeline-block{height:100%;min-width:1px;transition:filter .12s;flex-shrink:0}.timeline-block.kept{background:var(--green);cursor:pointer}.timeline-block.kept:hover{filter:brightness(1.2)}.timeline-block.skipped{background:var(--green-dim);cursor:pointer;opacity:.6}.timeline-block.skipped:hover{opacity:.8}.timeline-block.silence{background:#ef4444bf;cursor:default;position:relative}.timeline-block.silence:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background:repeating-linear-gradient(-45deg,transparent,transparent 4px,rgba(0,0,0,.25) 4px,rgba(0,0,0,.25) 8px)}.timeline-labels{display:flex;justify-content:space-between;margin-top:7px;font-size:11px;color:var(--text-dim);font-variant-numeric:tabular-nums}.timeline-legend{display:flex;gap:20px;margin-top:12px;font-size:12px}.legend-kept{color:var(--green)}.legend-skipped{color:#2d6a42}.legend-silence{color:var(--red)}.stats{display:flex;gap:10px;flex-wrap:wrap}.stat{padding:6px 14px;border-radius:6px;font-size:13px;font-variant-numeric:tabular-nums}.stat-kept{background:#22c55e14;color:var(--green)}.stat-removed{background:#ef444414;color:var(--red)}.stat-total{background:var(--surface);color:var(--text-muted);border:1px solid var(--border)}.actions{display:flex;gap:10px;justify-content:flex-end}.btn-primary,.btn-secondary{display:inline-flex;align-items:center;justify-content:center;padding:9px 22px;border-radius:8px;border:none;font-size:14px;font-weight:500;cursor:pointer;transition:background .15s,opacity .15s;text-decoration:none}.btn-primary{background:var(--blue);color:#fff}.btn-primary:hover{background:var(--blue-hover)}.btn-primary:disabled{opacity:.4;cursor:not-allowed}.btn-secondary{background:var(--surface-2);color:var(--text);border:1px solid var(--border-2)}.btn-secondary:hover:not(:disabled){background:var(--border)}.btn-secondary:disabled{opacity:.4;cursor:not-allowed}.progress-section{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px;display:flex;flex-direction:column;gap:10px}.progress-label{font-size:13px;color:var(--text-muted);font-variant-numeric:tabular-nums}.progress-track{height:6px;background:var(--border-2);border-radius:3px;overflow:hidden}.progress-fill{height:100%;background:var(--blue);border-radius:3px;transition:width .3s ease}.done-panel{display:flex;align-items:center;gap:14px;flex-wrap:wrap;background:var(--surface);border:1px solid rgba(34,197,94,.3);border-radius:12px;padding:20px 24px}.done-check{font-size:20px;color:var(--green)}.done-panel p{flex:1;font-weight:500;color:var(--green)}.error-banner{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border-radius:8px;background:#ef444414;border:1px solid rgba(239,68,68,.3);color:var(--red);font-size:13px}.error-banner button{background:none;border:none;color:var(--red);cursor:pointer;font-size:16px;line-height:1;padding:0 4px;opacity:.7}.error-banner button:hover{opacity:1}.status-card--inline{flex-direction:row;padding:16px 20px;gap:12px;justify-content:flex-start}.vt-root{background:var(--surface);border:1px solid var(--border);border-radius:12px;overflow:hidden;display:flex;flex-direction:column}.vt-preview{position:relative;background:#000;display:flex;justify-content:center;align-items:center;min-height:120px;max-height:320px;overflow:hidden;border-bottom:1px solid var(--border)}.vt-video{max-width:100%;max-height:320px;display:block;cursor:pointer}.vt-controls-bar{position:absolute;bottom:10px;left:10px;display:flex;align-items:center;gap:10px;background:#0000008c;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);border-radius:20px;padding:5px 14px}.vt-play-btn{background:none;border:none;color:#fff;font-size:15px;cursor:pointer;line-height:1;padding:0;opacity:.9}.vt-play-btn:hover{opacity:1}.vt-timecode{font-size:12px;color:#ffffffd9;font-variant-numeric:tabular-nums;font-family:ui-monospace,monospace}.vt-zoom-bar{display:flex;align-items:center;gap:10px;padding:7px 16px;border-bottom:1px solid var(--border);background:var(--surface)}.vt-zoom-label{font-size:11px;color:var(--text-dim);text-transform:uppercase;letter-spacing:.5px;flex-shrink:0}.vt-zoom-slider{flex:1;height:4px;accent-color:var(--blue);cursor:pointer}.vt-zoom-value{font-size:11px;color:var(--text-muted);font-variant-numeric:tabular-nums;font-family:ui-monospace,monospace;min-width:3.5ch;text-align:right;flex-shrink:0}.vt-zoom-reset{background:none;border:1px solid var(--border-2);border-radius:4px;color:var(--text-muted);font-size:11px;padding:2px 8px;cursor:pointer;flex-shrink:0}.vt-zoom-reset:hover{background:var(--surface-2);color:var(--text)}.vt-scroll{overflow-x:auto;overflow-y:hidden;background:#141414;scrollbar-width:thin;scrollbar-color:var(--border-2) transparent;padding-bottom:4px}.vt-scroll::-webkit-scrollbar{height:5px}.vt-scroll::-webkit-scrollbar-track{background:transparent}.vt-scroll::-webkit-scrollbar-thumb{background:var(--border-2);border-radius:3px}.vt-ruler{position:relative;height:22px;border-bottom:1px solid var(--border)}.vt-tick{position:absolute;top:5px;font-size:10px;color:var(--text-dim);transform:translate(-50%);white-space:nowrap;font-variant-numeric:tabular-nums;pointer-events:none}.vt-tick:before{content:"";position:absolute;top:-5px;left:50%;width:1px;height:4px;background:var(--border-2)}.vt-track{position:relative;cursor:crosshair;-webkit-user-select:none;user-select:none}.vt-thumbs{display:flex}.vt-thumb{flex-shrink:0;overflow:hidden;border-right:1px solid rgba(0,0,0,.4)}.vt-thumb img{display:block;width:100%;height:100%;object-fit:cover}.vt-thumb-skeleton{width:100%;height:100%;background:var(--surface-2);animation:pulse 1.4s ease-in-out infinite}@keyframes pulse{0%,to{opacity:.35}50%{opacity:.65}}.vt-silence{position:absolute;top:0;pointer-events:none;z-index:2;background:#ef444485}.vt-silence:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background:repeating-linear-gradient(-45deg,transparent,transparent 5px,rgba(0,0,0,.28) 5px,rgba(0,0,0,.28) 10px)}.vt-seg{position:absolute;top:0;z-index:3;pointer-events:auto;cursor:pointer;box-sizing:border-box;transition:background .12s}.vt-seg.kept{border-top:3px solid var(--green);border-bottom:3px solid var(--green);background:#22c55e12}.vt-seg.kept:hover{background:#22c55e38}.vt-seg.skipped{border-top:3px solid #444;border-bottom:3px solid #444;background:#00000073}.vt-seg.skipped:hover{background:#00000040}.vt-playhead{position:absolute;top:-8px;transform:translate(-50%);z-index:10;pointer-events:none;display:flex;flex-direction:column;align-items:center}.vt-playhead-nub{width:10px;height:7px;background:#fff;clip-path:polygon(0 0,100% 0,50% 100%)}.vt-playhead-line{width:1.5px;background:#ffffffe6}.vt-legend{display:flex;flex-wrap:wrap;gap:16px;padding:10px 16px;border-top:1px solid var(--border);font-size:12px;background:var(--surface)}.vt-leg{color:var(--text-muted)}.vt-leg-kept{color:var(--green)}.vt-leg-skip{color:#2d6a42}.vt-leg-sil{color:var(--red)}.vt-leg-hint{margin-left:auto;color:var(--text-dim);font-style:italic} diff --git a/frontend/dist/index.html b/frontend/dist/index.html new file mode 100644 index 0000000..5595959 --- /dev/null +++ b/frontend/dist/index.html @@ -0,0 +1,13 @@ + + + + + + A-Roll Cutter + + + + +
+ + diff --git a/frontend/src/components/VideoTimeline.tsx b/frontend/src/components/VideoTimeline.tsx index 91d5fa8..7ea2041 100644 --- a/frontend/src/components/VideoTimeline.tsx +++ b/frontend/src/components/VideoTimeline.tsx @@ -1,10 +1,12 @@ import { useRef, useState, useEffect, useCallback } from 'react' import type { Segment } from './Timeline' -const PX_PER_SEC = 80 // timeline scale: 80px = 1 second +const PX_PER_SEC = 80 // timeline scale: 80px = 1 second at 1× zoom const THUMB_H = 60 // rendered thumbnail strip height const CAP_W = 120 // canvas capture width const CAP_H = 68 // canvas capture height (16:9 ≈ 120×68) +const MIN_ZOOM = 0.25 +const MAX_ZOOM = 8 interface Props { videoUrl: string @@ -23,12 +25,18 @@ export default function VideoTimeline({ videoUrl, duration, segments, onToggle, const [currentTime, setCurrentTime] = useState(0) const [playing, setPlaying] = useState(false) const [scrubbing, setScrubbing] = useState(false) + const [zoom, setZoom] = useState(1) // Get intrinsic duration from the video element itself so we can show thumbnails // even before the server responds with the segments message. const [intrinsicDuration, setIntrinsicDuration] = useState(duration) const effectiveDuration = duration > 0 ? duration : intrinsicDuration + // Always-current refs so event handlers don't need to be re-registered on every render. + const trackWidthRef = useRef(1) + const effectiveDurationRef = useRef(effectiveDuration) + effectiveDurationRef.current = effectiveDuration + useEffect(() => { const v = videoRef.current if (!v) return @@ -38,9 +46,13 @@ export default function VideoTimeline({ videoUrl, duration, segments, onToggle, return () => v.removeEventListener('loadedmetadata', onMeta) }, []) - const trackWidth = Math.max(Math.round(effectiveDuration * PX_PER_SEC), 1) - const thumbCount = Math.max(Math.ceil(trackWidth / 80), 1) + // thumbCount is fixed to the base (1×) track width so thumbnails are not + // re-extracted on every zoom change — only on video/duration changes. + const baseTrackWidth = Math.max(Math.round(effectiveDuration * PX_PER_SEC), 1) + const thumbCount = Math.max(Math.ceil(baseTrackWidth / 80), 1) + const trackWidth = Math.max(Math.round(effectiveDuration * PX_PER_SEC * zoom), 1) const thumbW = trackWidth / thumbCount + trackWidthRef.current = trackWidth // Extract frames client-side — no server round-trip needed for thumbnails useEffect(() => { @@ -113,6 +125,46 @@ export default function VideoTimeline({ videoUrl, duration, segments, onToggle, } }, [currentTime, playing, effectiveDuration, trackWidth]) + // After a zoom change, scroll so that a specific time stays at a specific screen offset. + // Set by both handleSliderZoom (keeps viewport center) and the wheel handler (keeps cursor). + const scrollAdjustRef = useRef<{ time: number; screenOffset: number } | null>(null) + + useEffect(() => { + const el = scrollRef.current + const adj = scrollAdjustRef.current + if (!el || !adj || effectiveDuration === 0) return + scrollAdjustRef.current = null + el.scrollLeft = (adj.time / effectiveDuration) * trackWidthRef.current - adj.screenOffset + }, [zoom, effectiveDuration]) + + // Ctrl/Cmd+Wheel on the scroll area to zoom, keeping the cursor's time position fixed. + useEffect(() => { + const el = scrollRef.current + if (!el) return + const onWheel = (e: WheelEvent) => { + if (!e.ctrlKey && !e.metaKey) return + e.preventDefault() + const rect = el.getBoundingClientRect() + const offsetX = e.clientX - rect.left + const cursorTime = ((offsetX + el.scrollLeft) / trackWidthRef.current) * effectiveDurationRef.current + scrollAdjustRef.current = { time: cursorTime, screenOffset: offsetX } + const factor = e.deltaY < 0 ? 1.15 : 1 / 1.15 + setZoom(prev => Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, prev * factor))) + } + el.addEventListener('wheel', onWheel, { passive: false }) + return () => el.removeEventListener('wheel', onWheel) + }, []) + + const handleSliderZoom = (newZoom: number) => { + const el = scrollRef.current + if (el && effectiveDuration > 0) { + const centerX = el.scrollLeft + el.clientWidth / 2 + const centerTime = (centerX / trackWidthRef.current) * effectiveDuration + scrollAdjustRef.current = { time: centerTime, screenOffset: el.clientWidth / 2 } + } + setZoom(newZoom) + } + // Map a clientX position to a video timestamp const getTimeAt = useCallback((clientX: number): number => { if (!trackRef.current || effectiveDuration === 0) return 0 @@ -178,6 +230,25 @@ export default function VideoTimeline({ videoUrl, duration, segments, onToggle, + {/* ── Zoom control bar ── */} +
+ Zoom + handleSliderZoom(Number(e.target.value))} + className="vt-zoom-slider" + title="Ctrl+Wheel on the timeline also zooms" + /> + {zoom.toFixed(1)}× + {Math.abs(zoom - 1) > 0.01 && ( + + )} +
+ {/* ── Scrollable timeline ── */}
{/* Ruler sits inside scroll so it tracks with the track */} diff --git a/frontend/src/index.css b/frontend/src/index.css index e2ce75a..a57df95 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -574,6 +574,58 @@ body { font-family: ui-monospace, monospace; } +/* ── Zoom control bar ── */ + +.vt-zoom-bar { + display: flex; + align-items: center; + gap: 10px; + padding: 7px 16px; + border-bottom: 1px solid var(--border); + background: var(--surface); +} + +.vt-zoom-label { + font-size: 11px; + color: var(--text-dim); + text-transform: uppercase; + letter-spacing: 0.5px; + flex-shrink: 0; +} + +.vt-zoom-slider { + flex: 1; + height: 4px; + accent-color: var(--blue); + cursor: pointer; +} + +.vt-zoom-value { + font-size: 11px; + color: var(--text-muted); + font-variant-numeric: tabular-nums; + font-family: ui-monospace, monospace; + min-width: 3.5ch; + text-align: right; + flex-shrink: 0; +} + +.vt-zoom-reset { + background: none; + border: 1px solid var(--border-2); + border-radius: 4px; + color: var(--text-muted); + font-size: 11px; + padding: 2px 8px; + cursor: pointer; + flex-shrink: 0; +} + +.vt-zoom-reset:hover { + background: var(--surface-2); + color: var(--text); +} + /* ── Scrollable area ── */ .vt-scroll { diff --git a/handlers/analyze.go b/handlers/analyze.go index c8abc25..7cb95e5 100644 --- a/handlers/analyze.go +++ b/handlers/analyze.go @@ -2,6 +2,7 @@ package handlers import ( "encoding/json" + "log" "net/http" "aroll/store" @@ -49,6 +50,8 @@ func AnalyzeHandler(st *store.Store, hub *ws.Hub) http.HandlerFunc { }() w.WriteHeader(http.StatusAccepted) + + log.Println("Analyze handler works") } } diff --git a/handlers/download.go b/handlers/download.go index fdf9f38..b753ec8 100644 --- a/handlers/download.go +++ b/handlers/download.go @@ -1,6 +1,7 @@ package handlers import ( + "log" "net/http" "os" "strings" @@ -34,5 +35,7 @@ func DownloadHandler(st *store.Store) http.HandlerFunc { fi, _ := f.Stat() w.Header().Set("Content-Disposition", `attachment; filename="aroll-cut.mp4"`) http.ServeContent(w, r, "aroll-cut.mp4", fi.ModTime(), f) + + log.Println("Download handler works") } } diff --git a/handlers/export.go b/handlers/export.go index a91e51c..ff51a00 100644 --- a/handlers/export.go +++ b/handlers/export.go @@ -2,6 +2,7 @@ package handlers import ( "encoding/json" + "log" "net/http" "os" @@ -57,5 +58,7 @@ func ExportHandler(st *store.Store, hub *ws.Hub) http.HandlerFunc { }() w.WriteHeader(http.StatusAccepted) + + log.Println("Export handler works") } } diff --git a/handlers/upload.go b/handlers/upload.go index f7adff4..dbba1c8 100644 --- a/handlers/upload.go +++ b/handlers/upload.go @@ -2,6 +2,7 @@ package handlers import ( "encoding/json" + "log" "net/http" "path/filepath" @@ -42,5 +43,7 @@ func UploadHandler(st *store.Store) http.HandlerFunc { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{"filename": key}) + + log.Println("Upload handler works") } } diff --git a/handlers/zoom.go b/handlers/zoom.go new file mode 100644 index 0000000..3e5b686 --- /dev/null +++ b/handlers/zoom.go @@ -0,0 +1,38 @@ +package handlers + +import ( + "encoding/json" + "net/http" + + "aroll/transcode" + "aroll/ws" +) + +type zoomRequest struct { + Zoom float64 `json:"zoom"` // 1–100, percentage of total duration to show + Center float64 `json:"center"` // scroll center in seconds + Duration float64 `json:"duration"` // total video duration in seconds +} + +func ZoomHandler(hub *ws.Hub) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + + var req zoomRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "bad JSON: "+err.Error(), http.StatusBadRequest) + return + } + + h := transcode.HandlerZoom{Center: req.Center} + result := h.TimelineZoom(req.Zoom, req.Duration) + + data, _ := json.Marshal(result) + hub.Broadcast(data) + + w.WriteHeader(http.StatusAccepted) + } +} diff --git a/main.go b/main.go index 38e8318..c0bdc35 100644 --- a/main.go +++ b/main.go @@ -26,6 +26,7 @@ func main() { mux.HandleFunc("/upload", handlers.UploadHandler(st)) mux.HandleFunc("/analyze", handlers.AnalyzeHandler(st, hub)) mux.HandleFunc("/export", handlers.ExportHandler(st, hub)) + mux.HandleFunc("/zoom", handlers.ZoomHandler(hub)) mux.Handle("/download/", http.StripPrefix("/download/", handlers.DownloadHandler(st))) if _, err := os.Stat("frontend/dist"); err == nil { diff --git a/transcode/transcode.go b/transcode/encode.go similarity index 97% rename from transcode/transcode.go rename to transcode/encode.go index 2cd9ef3..1260821 100644 --- a/transcode/transcode.go +++ b/transcode/encode.go @@ -63,7 +63,7 @@ func ExportSegments( "-map", "[outv]", "-map", "[outa]", // around 80% compression - "-c:v", "libx264", "-crf", "28", "-preset", "fast", + "-c:v", "libx264", "-crf", "28", "-preset", "veryfast", "-c:a", "aac", "-b:a", "128k", "-progress", "pipe:1", "-y", diff --git a/transcode/timeline.go b/transcode/timeline.go new file mode 100644 index 0000000..7a7f51d --- /dev/null +++ b/transcode/timeline.go @@ -0,0 +1,45 @@ +package transcode + +// HandlerZoom holds the current scroll center for timeline zoom calculations. +type HandlerZoom struct { + Center float64 // center of the visible window in seconds +} + +// ZoomResult is the result of a TimelineZoom calculation. +type ZoomResult struct { + Type string `json:"type"` + Percent float64 `json:"percent"` + ViewStart float64 `json:"viewStart"` + ViewEnd float64 `json:"viewEnd"` +} + +// TimelineZoom computes the visible time window for the given zoomPercentage +// (1–100, where 100 = full duration visible) centered on h.Center. +func (h *HandlerZoom) TimelineZoom(zoomPercentage, duration float64) *ZoomResult { + visibleDuration := duration * (zoomPercentage / 100) + half := visibleDuration / 2 + + viewStart := h.Center - half + viewEnd := h.Center + half + + // Clamp to [0, duration], shifting the window rather than just truncating + // so the visible span stays the same size when near the edges. + if viewStart < 0 { + viewEnd -= viewStart + viewStart = 0 + } + if viewEnd > duration { + viewStart -= viewEnd - duration + viewEnd = duration + } + if viewStart < 0 { + viewStart = 0 + } + + return &ZoomResult{ + Type: "zoom", + Percent: zoomPercentage, + ViewStart: viewStart, + ViewEnd: viewEnd, + } +}