Add hop display

This commit is contained in:
Jack Kingsman committed 2026-01-18 15:44:36 -08:00
1 parent 13220c4a8f
commit 05a830d63f
13 files changed
+1732 -553

No files matched your search

+3
View File
@@ -11,3 +11,6 @@ frontend/node_modules/
# reference librarys
references/
# ancillary LLM files
.claude/
+6 -3
View File
@@ -16,7 +16,7 @@ Backend server + browser interface for MeshCore mesh radio networks. Attach your
This is entirely vibecoded slop -- no warranty of fitness for any purpose. It's been lovingly guided by an engineer with a passion for clean code and good tests, but it's still mostly LLM output, so you may find some bugs.
If extending, read the three `CLAUDE.md` files: `./CLAUDE.md`, `./frontend/CLAUDE.md`, and `./app/CLAUDE.md`.
If extending, have your LLM read the three `CLAUDE.md` files: `./CLAUDE.md`, `./frontend/CLAUDE.md`, and `./app/CLAUDE.md`.
## Requirements
@@ -111,9 +111,9 @@ npm run build # Production build to dist/
Run both the backend and `npm run dev` for hot-reloading frontend development.
### Code Quality
### Code Quality & Tests
Please lint, format, and quality check your code before PRing or committing. At the least, run a lint + autoformat + pyright check on the bakend, and a lint + autoformat on the frontend.
Please test, lint, format, and quality check your code before PRing or committing. At the least, run a lint + autoformat + pyright check on the bakend, and a lint + autoformat on the frontend.
<details>
<summary>But how?</summary>
@@ -123,11 +123,14 @@ Please lint, format, and quality check your code before PRing or committing. At
uv run ruff check app/ tests/ --fix # lint + auto-fix
uv run ruff format app/ tests/ # format (always writes)
uv run pyright app/ # type checking
PYTHONPATH=. uv run pytest tests/ -v # backend tests
# frontend
cd frontend
npm run lint:fix # esLint + auto-fix
npm run test:run # run tests
npm run format # prettier (always writes)
npm run build # build the frontend
```
</details>
-542
View File
@@ -1,542 +0,0 @@
var bv=Object.defineProperty;var Cv=(r,a,o)=>a in r?bv(r,a,{enumerable:!0,configurable:!0,writable:!0,value:o}):r[a]=o;var Mo=(r,a,o)=>Cv(r,typeof a!="symbol"?a+"":a,o);function Ev(r,a){for(var o=0;o<a.length;o++){const l=a[o];if(typeof l!="string"&&!Array.isArray(l)){for(const d in l)if(d!=="default"&&!(d in r)){const f=Object.getOwnPropertyDescriptor(l,d);f&&Object.defineProperty(r,d,f.get?f:{enumerable:!0,get:()=>l[d]})}}}return Object.freeze(Object.defineProperty(r,Symbol.toStringTag,{value:"Module"}))}(function(){const a=document.createElement("link").relList;if(a&&a.supports&&a.supports("modulepreload"))return;for(const d of document.querySelectorAll('link[rel="modulepreload"]'))l(d);new MutationObserver(d=>{for(const f of d)if(f.type==="childList")for(const m of f.addedNodes)m.tagName==="LINK"&&m.rel==="modulepreload"&&l(m)}).observe(document,{childList:!0,subtree:!0});function o(d){const f={};return d.integrity&&(f.integrity=d.integrity),d.referrerPolicy&&(f.referrerPolicy=d.referrerPolicy),d.crossOrigin==="use-credentials"?f.credentials="include":d.crossOrigin==="anonymous"?f.credentials="omit":f.credentials="same-origin",f}function l(d){if(d.ep)return;d.ep=!0;const f=o(d);fetch(d.href,f)}})();var yf=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function Qs(r){return r&&r.__esModule&&Object.prototype.hasOwnProperty.call(r,"default")?r.default:r}function kA(r){if(Object.prototype.hasOwnProperty.call(r,"__esModule"))return r;var a=r.default;if(typeof a=="function"){var o=function l(){return this instanceof l?Reflect.construct(a,arguments,this.constructor):a.apply(this,arguments)};o.prototype=a.prototype}else o={};return Object.defineProperty(o,"__esModule",{value:!0}),Object.keys(r).forEach(function(l){var d=Object.getOwnPropertyDescriptor(r,l);Object.defineProperty(o,l,d.get?d:{enumerable:!0,get:function(){return r[l]}})}),o}var _f={exports:{}},Ha={},wf={exports:{}},ut={};/**
* @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 xp;function kv(){if(xp)return ut;xp=1;var r=Symbol.for("react.element"),a=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),l=Symbol.for("react.strict_mode"),d=Symbol.for("react.profiler"),f=Symbol.for("react.provider"),m=Symbol.for("react.context"),h=Symbol.for("react.forward_ref"),x=Symbol.for("react.suspense"),p=Symbol.for("react.memo"),y=Symbol.for("react.lazy"),v=Symbol.iterator;function w(R){return R===null||typeof R!="object"?null:(R=v&&R[v]||R["@@iterator"],typeof R=="function"?R:null)}var k={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},T=Object.assign,C={};function E(R,U,Q){this.props=R,this.context=U,this.refs=C,this.updater=Q||k}E.prototype.isReactComponent={},E.prototype.setState=function(R,U){if(typeof R!="object"&&typeof R!="function"&&R!=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,R,U,"setState")},E.prototype.forceUpdate=function(R){this.updater.enqueueForceUpdate(this,R,"forceUpdate")};function D(){}D.prototype=E.prototype;function P(R,U,Q){this.props=R,this.context=U,this.refs=C,this.updater=Q||k}var S=P.prototype=new D;S.constructor=P,T(S,E.prototype),S.isPureReactComponent=!0;var N=Array.isArray,M=Object.prototype.hasOwnProperty,z={current:null},j={key:!0,ref:!0,__self:!0,__source:!0};function H(R,U,Q){var $,he={},fe=null,ke=null;if(U!=null)for($ in U.ref!==void 0&&(ke=U.ref),U.key!==void 0&&(fe=""+U.key),U)M.call(U,$)&&!j.hasOwnProperty($)&&(he[$]=U[$]);var ge=arguments.length-2;if(ge===1)he.children=Q;else if(1<ge){for(var Ze=Array(ge),$e=0;$e<ge;$e++)Ze[$e]=arguments[$e+2];he.children=Ze}if(R&&R.defaultProps)for($ in ge=R.defaultProps,ge)he[$]===void 0&&(he[$]=ge[$]);return{$$typeof:r,type:R,key:fe,ref:ke,props:he,_owner:z.current}}function te(R,U){return{$$typeof:r,type:R.type,key:U,ref:R.ref,props:R.props,_owner:R._owner}}function Z(R){return typeof R=="object"&&R!==null&&R.$$typeof===r}function V(R){var U={"=":"=0",":":"=2"};return"$"+R.replace(/[=:]/g,function(Q){return U[Q]})}var ne=/\/+/g;function X(R,U){return typeof R=="object"&&R!==null&&R.key!=null?V(""+R.key):U.toString(36)}function ie(R,U,Q,$,he){var fe=typeof R;(fe==="undefined"||fe==="boolean")&&(R=null);var ke=!1;if(R===null)ke=!0;else switch(fe){case"string":case"number":ke=!0;break;case"object":switch(R.$$typeof){case r:case a:ke=!0}}if(ke)return ke=R,he=he(ke),R=$===""?"."+X(ke,0):$,N(he)?(Q="",R!=null&&(Q=R.replace(ne,"$&/")+"/"),ie(he,U,Q,"",function($e){return $e})):he!=null&&(Z(he)&&(he=te(he,Q+(!he.key||ke&&ke.key===he.key?"":(""+he.key).replace(ne,"$&/")+"/")+R)),U.push(he)),1;if(ke=0,$=$===""?".":$+":",N(R))for(var ge=0;ge<R.length;ge++){fe=R[ge];var Ze=$+X(fe,ge);ke+=ie(fe,U,Q,Ze,he)}else if(Ze=w(R),typeof Ze=="function")for(R=Ze.call(R),ge=0;!(fe=R.next()).done;)fe=fe.value,Ze=$+X(fe,ge++),ke+=ie(fe,U,Q,Ze,he);else if(fe==="object")throw U=String(R),Error("Objects are not valid as a React child (found: "+(U==="[object Object]"?"object with keys {"+Object.keys(R).join(", ")+"}":U)+"). If you meant to render a collection of children, use an array instead.");return ke}function de(R,U,Q){if(R==null)return R;var $=[],he=0;return ie(R,$,"","",function(fe){return U.call(Q,fe,he++)}),$}function ae(R){if(R._status===-1){var U=R._result;U=U(),U.then(function(Q){(R._status===0||R._status===-1)&&(R._status=1,R._result=Q)},function(Q){(R._status===0||R._status===-1)&&(R._status=2,R._result=Q)}),R._status===-1&&(R._status=0,R._result=U)}if(R._status===1)return R._result.default;throw R._result}var pe={current:null},G={transition:null},J={ReactCurrentDispatcher:pe,ReactCurrentBatchConfig:G,ReactCurrentOwner:z};function W(){throw Error("act(...) is not supported in production builds of React.")}return ut.Children={map:de,forEach:function(R,U,Q){de(R,function(){U.apply(this,arguments)},Q)},count:function(R){var U=0;return de(R,function(){U++}),U},toArray:function(R){return de(R,function(U){return U})||[]},only:function(R){if(!Z(R))throw Error("React.Children.only expected to receive a single React element child.");return R}},ut.Component=E,ut.Fragment=o,ut.Profiler=d,ut.PureComponent=P,ut.StrictMode=l,ut.Suspense=x,ut.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=J,ut.act=W,ut.cloneElement=function(R,U,Q){if(R==null)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+R+".");var $=T({},R.props),he=R.key,fe=R.ref,ke=R._owner;if(U!=null){if(U.ref!==void 0&&(fe=U.ref,ke=z.current),U.key!==void 0&&(he=""+U.key),R.type&&R.type.defaultProps)var ge=R.type.defaultProps;for(Ze in U)M.call(U,Ze)&&!j.hasOwnProperty(Ze)&&($[Ze]=U[Ze]===void 0&&ge!==void 0?ge[Ze]:U[Ze])}var Ze=arguments.length-2;if(Ze===1)$.children=Q;else if(1<Ze){ge=Array(Ze);for(var $e=0;$e<Ze;$e++)ge[$e]=arguments[$e+2];$.children=ge}return{$$typeof:r,type:R.type,key:he,ref:fe,props:$,_owner:ke}},ut.creLine truncated
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var yp;function Sv(){if(yp)return Ha;yp=1;var r=o0(),a=Symbol.for("react.element"),o=Symbol.for("react.fragment"),l=Object.prototype.hasOwnProperty,d=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,f={key:!0,ref:!0,__self:!0,__source:!0};function m(h,x,p){var y,v={},w=null,k=null;p!==void 0&&(w=""+p),x.key!==void 0&&(w=""+x.key),x.ref!==void 0&&(k=x.ref);for(y in x)l.call(x,y)&&!f.hasOwnProperty(y)&&(v[y]=x[y]);if(h&&h.defaultProps)for(y in x=h.defaultProps,x)v[y]===void 0&&(v[y]=x[y]);return{$$typeof:a,type:h,key:w,ref:k,props:v,_owner:d.current}}return Ha.Fragment=o,Ha.jsx=m,Ha.jsxs=m,Ha}var _p;function Bv(){return _p||(_p=1,_f.exports=Sv()),_f.exports}var B=Bv(),F=o0();const Ce=Qs(F),s0=Ev({__proto__:null,default:Ce},[F]);var ku={},bf={exports:{}},Un={},Cf={exports:{}},Ef={};/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var wp;function Pv(){return wp||(wp=1,(function(r){function a(G,J){var W=G.length;G.push(J);e:for(;0<W;){var R=W-1>>>1,U=G[R];if(0<d(U,J))G[R]=J,G[W]=U,W=R;else break e}}function o(G){return G.length===0?null:G[0]}function l(G){if(G.length===0)return null;var J=G[0],W=G.pop();if(W!==J){G[0]=W;e:for(var R=0,U=G.length,Q=U>>>1;R<Q;){var $=2*(R+1)-1,he=G[$],fe=$+1,ke=G[fe];if(0>d(he,W))fe<U&&0>d(ke,he)?(G[R]=ke,G[fe]=W,R=fe):(G[R]=he,G[$]=W,R=$);else if(fe<U&&0>d(ke,W))G[R]=ke,G[fe]=W,R=fe;else break e}}return J}function d(G,J){var W=G.sortIndex-J.sortIndex;return W!==0?W:G.id-J.id}if(typeof performance=="object"&&typeof performance.now=="function"){var f=performance;r.unstable_now=function(){return f.now()}}else{var m=Date,h=m.now();r.unstable_now=function(){return m.now()-h}}var x=[],p=[],y=1,v=null,w=3,k=!1,T=!1,C=!1,E=typeof setTimeout=="function"?setTimeout:null,D=typeof clearTimeout=="function"?clearTimeout:null,P=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function S(G){for(var J=o(p);J!==null;){if(J.callback===null)l(p);else if(J.startTime<=G)l(p),J.sortIndex=J.expirationTime,a(x,J);else break;J=o(p)}}function N(G){if(C=!1,S(G),!T)if(o(x)!==null)T=!0,ae(M);else{var J=o(p);J!==null&&pe(N,J.startTime-G)}}function M(G,J){T=!1,C&&(C=!1,D(H),H=-1),k=!0;var W=w;try{for(S(J),v=o(x);v!==null&&(!(v.expirationTime>J)||G&&!V());){var R=v.callback;if(typeof R=="function"){v.callback=null,w=v.priorityLevel;var U=R(v.expirationTime<=J);J=r.unstable_now(),typeof U=="function"?v.callback=U:v===o(x)&&l(x),S(J)}else l(x);v=o(x)}if(v!==null)var Q=!0;else{var $=o(p);$!==null&&pe(N,$.startTime-J),Q=!1}return Q}finally{v=null,w=W,k=!1}}var z=!1,j=null,H=-1,te=5,Z=-1;function V(){return!(r.unstable_now()-Z<te)}function ne(){if(j!==null){var G=r.unstable_now();Z=G;var J=!0;try{J=j(!0,G)}finally{J?X():(z=!1,j=null)}}else z=!1}var X;if(typeof P=="function")X=function(){P(ne)};else if(typeof MessageChannel<"u"){var ie=new MessageChannel,de=ie.port2;ie.port1.onmessage=ne,X=function(){de.postMessage(null)}}else X=function(){E(ne,0)};function ae(G){j=G,z||(z=!0,X())}function pe(G,J){H=E(function(){G(r.unstable_now())},J)}r.unstable_IdlePriority=5,r.unstable_ImmediatePriority=1,r.unstable_LowPriority=4,r.unstable_NormalPriority=3,r.unstable_Profiling=null,r.unstable_UserBlockingPriority=2,r.unstable_cancelCallback=function(G){G.callback=null},r.unstable_continueExecution=function(){T||k||(T=!0,ae(M))},r.unstable_forceFrameRate=function(G){0>G||125<G?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):te=0<G?Math.floor(1e3/G):5},r.unstable_getCurrentPriorityLevel=function(){return w},r.unstable_getFirstCallbackNode=function(){return o(x)},r.unstable_next=function(G){switch(w){case 1:case 2:case 3:var J=3;break;default:J=w}var W=w;w=J;try{return G()}finally{w=W}},r.unstable_pauseExecution=function(){},r.unstable_requestPaint=function(){},r.unstable_runWithPriority=function(G,J){switch(G){case 1:case 2:case 3:case 4:case 5:break;default:G=3}var W=w;w=G;try{return J()}finally{w=W}},r.unstable_scheduleCallback=function(G,J,W){var R=r.unstable_now();switch(typeof W=="object"&&W!==null?(W=W.delay,W=typeof W=="number"&&0<W?R+W:R):W=R,G){case 1:var U=-1;break;case 2:U=250;break;case 5:U=1073741823;break;case 4:U=1e4;break;default:U=5e3}return U=W+U,G={id:y++,callback:J,priorityLevel:G,startTime:W,expirationTime:U,sortIndex:-1},W>R?(G.sortIndex=W,a(p,G),o(x)===null&&G===o(p)&&(C?(D(H),H=-1):C=!0,pe(N,W-R))):(G.sortIndex=U,a(x,G),T||k||(T=!0,ae(M))),G},r.unstable_shouldYield=V,r.unstable_wrapCallback=function(G){var J=w;return function(){var W=w;w=J;try{return G.apply(this,arguments)}finally{w=W}}}})(Ef)),Ef}var bp;function Tv(){return bp||(bp=1,Cf.exports=Pv()),Cf.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 Cp;function Dv(){if(Cp)return Un;Cp=1;var r=o0(),a=Tv();function o(e){for(var n="https://reactjs.org/docs/error-decoder.html?invariant="+e,s=1;s<arguments.length;s++)n+="&args[]="+encodeURIComponent(arguments[s]);return"Minified React error #"+e+"; visit "+n+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var l=new Set,d={};function f(e,n){m(e,n),m(e+"Capture",n)}function m(e,n){for(d[e]=n,e=0;e<n.length;e++)l.add(n[e])}var h=!(typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),x=Object.prototype.hasOwnProperty,p=/^[: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]*$/,y={},v={};function w(e){return x.call(v,e)?!0:x.call(y,e)?!1:p.test(e)?v[e]=!0:(y[e]=!0,!1)}function k(e,n,s,c){if(s!==null&&s.type===0)return!1;switch(typeof n){case"function":case"symbol":return!0;case"boolean":return c?!1:s!==null?!s.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function T(e,n,s,c){if(n===null||typeof n>"u"||k(e,n,s,c))return!0;if(c)return!1;if(s!==null)switch(s.type){case 3:return!n;case 4:return n===!1;case 5:return isNaN(n);case 6:return isNaN(n)||1>n}return!1}function C(e,n,s,c,g,_,I){this.acceptsBooleans=n===2||n===3||n===4,this.attributeName=c,this.attributeNamespace=g,this.mustUseProperty=s,this.propertyName=e,this.type=n,this.sanitizeURL=_,this.removeEmptyString=I}var E={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){E[e]=new C(e,0,!1,e,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var n=e[0];E[n]=new C(n,1,!1,e[1],null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){E[e]=new C(e,2,!1,e.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){E[e]=new C(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){E[e]=new C(e,3,!1,e.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(e){E[e]=new C(e,3,!0,e,null,!1,!1)}),["capture","download"].forEach(function(e){E[e]=new C(e,4,!1,e,null,!1,!1)}),["cols","rows","size","span"].forEach(function(e){E[e]=new C(e,6,!1,e,null,!1,!1)}),["rowSpan","start"].forEach(function(e){E[e]=new C(e,5,!1,e.toLowerCase(),null,!1,!1)});var D=/[\-:]([a-z])/g;function P(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 n=e.replace(D,P);E[n]=new C(n,1,!1,e,null,!1,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var n=e.replace(D,P);E[n]=new C(n,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(e){var n=e.replace(D,P);E[n]=new C(n,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(e){E[e]=new C(e,1,!1,e.toLowerCase(),null,!1,!1)}),E.xlinkHref=new C("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(e){E[e]=new C(e,1,!1,e.toLowerCase(),null,!0,!0)});function S(e,n,s,c){var g=E.hasOwnProperty(n)?E[n]:null;(g!==null?g.type!==0:c||!(2<n.length)||n[0]!=="o"&&n[0]!=="O"||n[1]!=="n"&&n[1]!= Line truncated
`+R+e}var Q=!1;function $(e,n){if(!e||Q)return"";Q=!0;var s=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(n)if(n=function(){throw Error()},Object.defineProperty(n.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(n,[])}catch(ce){var c=ce}Reflect.construct(e,[],n)}else{try{n.call()}catch(ce){c=ce}e.call(n.prototype)}else{try{throw Error()}catch(ce){c=ce}e()}}catch(ce){if(ce&&c&&typeof ce.stack=="string"){for(var g=ce.stack.split(`
`),_=c.stack.split(`
`),I=g.length-1,q=_.length-1;1<=I&&0<=q&&g[I]!==_[q];)q--;for(;1<=I&&0<=q;I--,q--)if(g[I]!==_[q]){if(I!==1||q!==1)do if(I--,q--,0>q||g[I]!==_[q]){var Y=`
`+g[I].replace(" at new "," at ");return e.displayName&&Y.includes("<anonymous>")&&(Y=Y.replace("<anonymous>",e.displayName)),Y}while(1<=I&&0<=q);break}}}finally{Q=!1,Error.prepareStackTrace=s}return(e=e?e.displayName||e.name:"")?U(e):""}function he(e){switch(e.tag){case 5:return U(e.type);case 16:return U("Lazy");case 13:return U("Suspense");case 19:return U("SuspenseList");case 0:case 2:case 15:return e=$(e.type,!1),e;case 11:return e=$(e.type.render,!1),e;case 1:return e=$(e.type,!0),e;default:return""}}function fe(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 j:return"Fragment";case z:return"Portal";case te:return"Profiler";case H:return"StrictMode";case X:return"Suspense";case ie:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case V:return(e.displayName||"Context")+".Consumer";case Z:return(e._context.displayName||"Context")+".Provider";case ne:var n=e.render;return e=e.displayName,e||(e=n.displayName||n.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case de:return n=e.displayName||null,n!==null?n:fe(e.type)||"Memo";case ae:n=e._payload,e=e._init;try{return fe(e(n))}catch{}}return null}function ke(e){var n=e.type;switch(e.tag){case 24:return"Cache";case 9:return(n.displayName||"Context")+".Consumer";case 10:return(n._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=n.render,e=e.displayName||e.name||"",n.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return n;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return fe(n);case 8:return n===H?"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 n=="function")return n.displayName||n.name||null;if(typeof n=="string")return n}return null}function ge(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Ze(e){var n=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(n==="checkbox"||n==="radio")}function $e(e){var n=Ze(e)?"checked":"value",s=Object.getOwnPropertyDescriptor(e.constructor.prototype,n),c=""+e[n];if(!e.hasOwnProperty(n)&&typeof s<"u"&&typeof s.get=="function"&&typeof s.set=="function"){var g=s.get,_=s.set;return Object.defineProperty(e,n,{configurable:!0,get:function(){return g.call(this)},set:function(I){c=""+I,_.call(this,I)}}),Object.defineProperty(e,n,{enumerable:s.enumerable}),{getValue:function(){return c},setValue:function(I){c=""+I},stopTracking:function(){e._valueTracker=null,delete e[n]}}}}function wt(e){e._valueTracker||(e._valueTracker=$e(e))}function ft(e){if(!e)return!1;var n=e._valueTracker;if(!n)return!0;var s=n.getValue(),c="";return e&&(c=Ze(e)?e.checked?"true":"false":e.value),e=c,e!==s?(n.setValue(e),!0):!1}function Se(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 Ue(e,n){var s=n.checked;return W({},n,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:s??e._wrapperState.initialChecked})}function lt(e,n){var s=n.defaultValue==null?"":n.defaultValue,c=n.checked!=null?n.checked:n.defaultChecked;s=ge(n.value!=null?n.value:s),e._wrapperState={initialChecked:c,initialValue:s,controlled:n.type==="checkbox"||n.type==="radio"?n.checked!=null:n.value!=null}}function Dt(e,n){n=n.checked,n!=null&&S(e,"checked",n,!1)}function xt(e,n){Dt(e,n);var s=ge(n.value),c=n.type;if(s!=null)c==="number"?(s===0&&e.value===""||e.value!=s)&&(e.value=""+s):e.value!==""+s&&(e.value=""+s);else if(c==="submit"||c==="reset"){e.removeAttribute("value");return}n.hasOwnProperty("value")?Ke(e,n.type,s):n.hasOwnProperty("defaultValue")&&Ke(e,n.type,ge(n.defaultValue)),n.checked==null&&n.defaultChecked!=null&&(e.defaultChecked=!!n.defaultChecked)}function it(e,n,s){if(n.hasOwnProperty("value")||n.hasOwnProperty("defaultValue")){var c=n.type;if(!(c!=="submit"&&c!=="reset"||n.value!==void 0&&n.value!==null))return;n=""+e._wrapperState.initialValue,s||n===e.value||(e.value=n),e.defaultValue=n}s=e.name,s!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,s!==""&&(e.name=s)}function Ke(e,n,s){(n!=="number"||Se(e.ownerDocument)!==e)&&(s==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+s&&(e.defaultValue=""+s))}var Xe=Array.isArray;function xe(e,n,s,c){if(e=e.options,n){n={};for(var g=0;g<s.length;g++)n["$"+s[g]]=!0;for(s=0;s<e.length;s++)g=n.hasOwnProperty("$"+e[s].value),e[s].selected!==g&&(e[s].selected=g),g&&c&&(e[s].defaultSelected=!0)}else{for(s=""+ge(s),n=null,g=0;g<e.length;g++){if(e[g].value===s){e[g].selected=!0,c&&(e[g].defaultSelected=!0);return}n!==null||e[g].disabled||(n=e[g])}n!==null&&(n.selected=!0)}}function Te(e,n){if(n.dangerouslySetInnerHT Line truncated
`).replace(K,"")}function ue(e,n,s){if(n=re(n),re(e)!==n&&s)throw Error(o(425))}function ve(){}var Pe=null,qe=null;function nt(e,n){return e==="textarea"||e==="noscript"||typeof n.children=="string"||typeof n.children=="number"||typeof n.dangerouslySetInnerHTML=="object"&&n.dangerouslySetInnerHTML!==null&&n.dangerouslySetInnerHTML.__html!=null}var rn=typeof setTimeout=="function"?setTimeout:void 0,Xt=typeof clearTimeout=="function"?clearTimeout:void 0,Dn=typeof Promise=="function"?Promise:void 0,wn=typeof queueMicrotask=="function"?queueMicrotask:typeof Dn<"u"?function(e){return Dn.resolve(null).then(e).catch(Zi)}:rn;function Zi(e){setTimeout(function(){throw e})}function ka(e,n){var s=n,c=0;do{var g=s.nextSibling;if(e.removeChild(s),g&&g.nodeType===8)if(s=g.data,s==="/$"){if(c===0){e.removeChild(g),$n(n);return}c--}else s!=="$"&&s!=="$?"&&s!=="$!"||c++;s=g}while(s);$n(n)}function Vr(e){for(;e!=null;e=e.nextSibling){var n=e.nodeType;if(n===1||n===3)break;if(n===8){if(n=e.data,n==="$"||n==="$!"||n==="$?")break;if(n==="/$")return null}}return e}function Hl(e){e=e.previousSibling;for(var n=0;e;){if(e.nodeType===8){var s=e.data;if(s==="$"||s==="$!"||s==="$?"){if(n===0)return e;n--}else s==="/$"&&n++}e=e.previousSibling}return null}var li=Math.random().toString(36).slice(2),dr="__reactFiber$"+li,Wi="__reactProps$"+li,_t="__reactContainer$"+li,qi="__reactEvents$"+li,pd="__reactListeners$"+li,md="__reactHandles$"+li;function ui(e){var n=e[dr];if(n)return n;for(var s=e.parentNode;s;){if(n=s[_t]||s[dr]){if(s=n.alternate,n.child!==null||s!==null&&s.child!==null)for(e=Hl(e);e!==null;){if(s=e[dr])return s;e=Hl(e)}return n}e=s,s=e.parentNode}return null}function ci(e){return e=e[dr]||e[_t],!e||e.tag!==5&&e.tag!==6&&e.tag!==13&&e.tag!==3?null:e}function di(e){if(e.tag===5||e.tag===6)return e.stateNode;throw Error(o(33))}function ys(e){return e[Wi]||null}var Ad=[],_s=-1;function Gi(e){return{current:e}}function Ft(e){0>_s||(e.current=Ad[_s],Ad[_s]=null,_s--)}function Tt(e,n){_s++,Ad[_s]=e.current,e.current=n}var Qi={},bn=Gi(Qi),On=Gi(!1),Eo=Qi;function ws(e,n){var s=e.type.contextTypes;if(!s)return Qi;var c=e.stateNode;if(c&&c.__reactInternalMemoizedUnmaskedChildContext===n)return c.__reactInternalMemoizedMaskedChildContext;var g={},_;for(_ in s)g[_]=n[_];return c&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=n,e.__reactInternalMemoizedMaskedChildContext=g),g}function zn(e){return e=e.childContextTypes,e!=null}function Vl(){Ft(On),Ft(bn)}function j0(e,n,s){if(bn.current!==Qi)throw Error(o(168));Tt(bn,n),Tt(On,s)}function H0(e,n,s){var c=e.stateNode;if(n=n.childContextTypes,typeof c.getChildContext!="function")return s;c=c.getChildContext();for(var g in c)if(!(g in n))throw Error(o(108,ke(e)||"Unknown",g));return W({},s,c)}function Ul(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Qi,Eo=bn.current,Tt(bn,e),Tt(On,On.current),!0}function V0(e,n,s){var c=e.stateNode;if(!c)throw Error(o(169));s?(e=H0(e,n,Eo),c.__reactInternalMemoizedMergedChildContext=e,Ft(On),Ft(bn),Tt(bn,e)):Ft(On),Tt(On,s)}var fi=null,Zl=!1,gd=!1;function U0(e){fi===null?fi=[e]:fi.push(e)}function Vx(e){Zl=!0,U0(e)}function Ki(){if(!gd&&fi!==null){gd=!0;var e=0,n=ht;try{var s=fi;for(ht=1;e<s.length;e++){var c=s[e];do c=c(!0);while(c!==null)}fi=null,Zl=!1}catch(g){throw fi!==null&&(fi=fi.slice(e+1)),gl(ta,Ki),g}finally{ht=n,gd=!1}}return null}var bs=[],Cs=0,Wl=null,ql=0,fr=[],hr=0,ko=null,hi=1,pi="";function So(e,n){bs[Cs++]=ql,bs[Cs++]=Wl,Wl=e,ql=n}function Z0(e,n,s){fr[hr++]=hi,fr[hr++]=pi,fr[hr++]=ko,ko=e;var c=hi;e=pi;var g=32-tt(c)-1;c&=~(1<<g),s+=1;var _=32-tt(n)+g;if(30<_){var I=g-g%5;_=(c&(1<<I)-1).toString(32),c>>=I,g-=I,hi=1<<32-tt(n)+g|s<<g|c,pi=_+e}else hi=1<<_|s<<g|c,pi=e}function xd(e){e.return!==null&&(So(e,1),Z0(e,1,0))}function vd(e){for(;e===Wl;)Wl=bs[--Cs],bs[Cs]=null,ql=bs[--Cs],bs[Cs]=null;for(;e===ko;)ko=fr[--hr],fr[hr]=null,pi=fr[--hr],fr[hr]=null,hi=fr[--hr],fr[hr]=null}var tr=null,nr=null,Mt=!1,Er=null;function W0(e,n){var s=gr(5,null,null,0);s.elementType="DELETED",s.stateNode=n,s.return=e,n=e.deletions,n===null?(e.deletions=[s],e.flags|=16):n.push(s)}function q0(e,n){switch(e.tag){case 5:var s=e.type;return n=n.nodeType!==1||s.toLowerCase()!==n.nodeName.toLowerCase()?null:n,n!==null?(e.stateNode=n,tr=e,nr=Vr(n.firstChild),!0):!1;case 6:return n=e.pendingProps===""||n.nodeType!==3?null:n,n!==null?(e.stateNode=n,tr=e,nr=null,!0):!1;case 13:return n=n.nodeType!==8?null:n,n!==null?(s=ko!==null?{id:hi,overflow:pi}:null,e.memoizedState={dehydrated:n,treeContext:s,retryLane:1073741824},s=gr(18,null,null,0),s.stateNode=n,s.return=e,e.child=s,tr=e,nr=null,!0):!1;default:return!1}}function yd(e){return(e.mode&1)!==0&&(e.flags&128)===0}function _d(e){if(Mt){var n=nr;if(n){var s=n;if(!q0(e,n)){if(yd(e))throw Error(o(418));n=Vr(s.nextSibling);var c=tr;n&&q0(e,n)?W0(c,s):(e.flags=e.flags&-4097|2,Mt=!1,tr=e)}}else{if(yd(e))throw Error(o(418));e.flags=e.flags&-4097|2,Mt=!1,tr=e}}}function G0(e){for(e=e.r Line truncated
Error generating stack: `+_.message+`
`+_.stack}return{value:e,source:n,stack:g,digest:null}}function Ud(e,n,s){return{value:e,source:null,stack:s??null,digest:n??null}}function Zd(e,n){try{console.error(n.value)}catch(s){setTimeout(function(){throw s})}}var Yx=typeof WeakMap=="function"?WeakMap:Map;function Sh(e,n,s){s=Ai(-1,s),s.tag=3,s.payload={element:null};var c=n.value;return s.callback=function(){fu||(fu=!0,sf=c),Zd(e,n)},s}function Bh(e,n,s){s=Ai(-1,s),s.tag=3;var c=e.type.getDerivedStateFromError;if(typeof c=="function"){var g=n.value;s.payload=function(){return c(g)},s.callback=function(){Zd(e,n)}}var _=e.stateNode;return _!==null&&typeof _.componentDidCatch=="function"&&(s.callback=function(){Zd(e,n),typeof c!="function"&&(Ji===null?Ji=new Set([this]):Ji.add(this));var I=n.stack;this.componentDidCatch(n.value,{componentStack:I!==null?I:""})}),s}function Ph(e,n,s){var c=e.pingCache;if(c===null){c=e.pingCache=new Yx;var g=new Set;c.set(n,g)}else g=c.get(n),g===void 0&&(g=new Set,c.set(n,g));g.has(s)||(g.add(s),e=dv.bind(null,e,n,s),n.then(e,e))}function Th(e){do{var n;if((n=e.tag===13)&&(n=e.memoizedState,n=n!==null?n.dehydrated!==null:!0),n)return e;e=e.return}while(e!==null);return null}function Dh(e,n,s,c,g){return(e.mode&1)===0?(e===n?e.flags|=65536:(e.flags|=128,s.flags|=131072,s.flags&=-52805,s.tag===1&&(s.alternate===null?s.tag=17:(n=Ai(-1,1),n.tag=2,Yi(s,n,1))),s.lanes|=1),e):(e.flags|=65536,e.lanes=g,e)}var Xx=N.ReactCurrentOwner,jn=!1;function Rn(e,n,s,c){n.child=e===null?Y0(n,null,s,c):ks(n,e.child,s,c)}function Rh(e,n,s,c,g){s=s.render;var _=n.ref;return Bs(n,g),c=Ld(e,n,s,c,_,g),s=Md(),e!==null&&!jn?(n.updateQueue=e.updateQueue,n.flags&=-2053,e.lanes&=~g,gi(e,n,g)):(Mt&&s&&xd(n),n.flags|=1,Rn(e,n,c,g),n.child)}function Fh(e,n,s,c,g){if(e===null){var _=s.type;return typeof _=="function"&&!hf(_)&&_.defaultProps===void 0&&s.compare===null&&s.defaultProps===void 0?(n.tag=15,n.type=_,Nh(e,n,_,c,g)):(e=xu(s.type,null,c,n,n.mode,g),e.ref=n.ref,e.return=n,n.child=e)}if(_=e.child,(e.lanes&g)===0){var I=_.memoizedProps;if(s=s.compare,s=s!==null?s:zr,s(I,c)&&e.ref===n.ref)return gi(e,n,g)}return n.flags|=1,e=ro(_,c),e.ref=n.ref,e.return=n,n.child=e}function Nh(e,n,s,c,g){if(e!==null){var _=e.memoizedProps;if(zr(_,c)&&e.ref===n.ref)if(jn=!1,n.pendingProps=c=_,(e.lanes&g)!==0)(e.flags&131072)!==0&&(jn=!0);else return n.lanes=e.lanes,gi(e,n,g)}return Wd(e,n,s,c,g)}function Lh(e,n,s){var c=n.pendingProps,g=c.children,_=e!==null?e.memoizedState:null;if(c.mode==="hidden")if((n.mode&1)===0)n.memoizedState={baseLanes:0,cachePool:null,transitions:null},Tt(Rs,rr),rr|=s;else{if((s&1073741824)===0)return e=_!==null?_.baseLanes|s:s,n.lanes=n.childLanes=1073741824,n.memoizedState={baseLanes:e,cachePool:null,transitions:null},n.updateQueue=null,Tt(Rs,rr),rr|=e,null;n.memoizedState={baseLanes:0,cachePool:null,transitions:null},c=_!==null?_.baseLanes:s,Tt(Rs,rr),rr|=c}else _!==null?(c=_.baseLanes|s,n.memoizedState=null):c=s,Tt(Rs,rr),rr|=c;return Rn(e,n,g,s),n.child}function Mh(e,n){var s=n.ref;(e===null&&s!==null||e!==null&&e.ref!==s)&&(n.flags|=512,n.flags|=2097152)}function Wd(e,n,s,c,g){var _=zn(s)?Eo:bn.current;return _=ws(n,_),Bs(n,g),s=Ld(e,n,s,c,_,g),c=Md(),e!==null&&!jn?(n.updateQueue=e.updateQueue,n.flags&=-2053,e.lanes&=~g,gi(e,n,g)):(Mt&&c&&xd(n),n.flags|=1,Rn(e,n,s,g),n.child)}function Ih(e,n,s,c,g){if(zn(s)){var _=!0;Ul(n)}else _=!1;if(Bs(n,g),n.stateNode===null)au(e,n),Eh(n,s,c),Vd(n,s,c,g),c=!0;else if(e===null){var I=n.stateNode,q=n.memoizedProps;I.props=q;var Y=I.context,ce=s.contextType;typeof ce=="object"&&ce!==null?ce=pr(ce):(ce=zn(s)?Eo:bn.current,ce=ws(n,ce));var _e=s.getDerivedStateFromProps,we=typeof _e=="function"||typeof I.getSnapshotBeforeUpdate=="function";we||typeof I.UNSAFE_componentWillReceiveProps!="function"&&typeof I.componentWillReceiveProps!="function"||(q!==c||Y!==ce)&&kh(n,I,c,ce),$i=!1;var ye=n.memoizedState;I.state=ye,Xl(n,c,I,g),Y=n.memoizedState,q!==c||ye!==Y||On.current||$i?(typeof _e=="function"&&(Hd(n,s,_e,c),Y=n.memoizedState),(q=$i||Ch(n,s,q,c,ye,Y,ce))?(we||typeof I.UNSAFE_componentWillMount!="function"&&typeof I.componentWillMount!="function"||(typeof I.componentWillMount=="function"&&I.componentWillMount(),typeof I.UNSAFE_componentWillMount=="function"&&I.UNSAFE_componentWillMount()),typeof I.componentDidMount=="function"&&(n.flags|=4194308)):(typeof I.componentDidMount=="function"&&(n.flags|=4194308),n.memoizedProps=c,n.memoizedState=Y),I.props=c,I.state=Y,I.context=ce,c=q):(typeof I.componentDidMount=="function"&&(n.flags|=4194308),c=!1)}else{I=n.stateNode,J0(e,n),q=n.memoizedProps,ce=n.type===n.elementType?q:kr(n.type,q),I.props=ce,we=n.pendingProps,ye=I.context,Y=s.contextType,typeof Y=="object"&&Y!==null?Y=pr(Y):(Y=zn(s)?Eo:bn.current,Y=ws(n,Y));var Fe=s.getDerivedStateFromProps;(_e=typeof Fe=="function"||typeof I.getSnapshotBeforeUpdate=="function")||typeof I.UNSAFE_componentWillReceiveProps!="function"&&typeof I.componentWillReceiveProps!="function"||(q!==we||ye!==Y)&&kh(n,I,c,Y),$i=!1,ye=n.m Line truncated
`)}function Ls(r,a,o){const l=Math.floor(Date.now()/1e3);return{id:-Date.now(),type:"PRIV",conversation_key:r,text:a,sender_timestamp:l,received_at:l,path:null,txt_type:0,signature:null,outgoing:o,acked:1}}function zv(r){const a=F.useRef(null),o=F.useRef(null),l=F.useCallback(()=>{o.current!==null&&(clearInterval(o.current),o.current=null),a.current=null},[]),d=F.useCallback(async()=>{const m=a.current;if(!m)return;let h=null,x=null;for(let p=0;p<2;p++)try{h=await st.requestTelemetry(m.conversationId,"");break}catch(y){x=y instanceof Error?y:new Error("Unknown error"),p===0&&await new Promise(v=>setTimeout(v,2e3))}if(h){const p=Ls(m.conversationId,Ov(m,h),!1);r(y=>[...y,p])}else{const p=Ls(m.conversationId,`Duty cycle poll failed after retry: ${(x==null?void 0:x.message)??"Unknown error"}`,!1);r(y=>[...y,p])}},[r]),f=F.useCallback(async(m,h)=>{const x=m.trim().toLowerCase();if(x==="dutycycle_start"){l();let p=null,y=null;for(let k=0;k<2;k++)try{p=await st.requestTelemetry(h,"");break}catch(T){y=T instanceof Error?T:new Error("Unknown error"),k===0&&await new Promise(C=>setTimeout(C,2e3))}if(!p){const k=Ls(h,`Failed to start duty cycle tracking after retry: ${(y==null?void 0:y.message)??"Unknown error"}`,!1);return r(T=>[...T,k]),!0}const v=Math.floor(Date.now()/1e3);a.current={startTime:v,uptime:p.uptime_seconds,txAirtime:p.airtime_seconds,rxAirtime:p.rx_airtime_seconds,sentFlood:p.sent_flood,sentDirect:p.sent_direct,recvFlood:p.recv_flood,recvDirect:p.recv_direct,conversationId:h};const w=Ls(h,`Airtime/duty cycle statistics gathering begins at ${v}. Logs will follow every 5 minutes. To stop, run dutycycle_stop or navigate away from this conversation.`,!1);return r(k=>[...k,w]),o.current=window.setInterval(d,Mv),!0}if(x==="dutycycle_stop"){if(a.current&&a.current.conversationId===h){await d(),l();const p=Ls(h,"Airtime/duty cycle statistics gathering stopped.",!1);r(y=>[...y,p])}else{const p=Ls(h,"Duty cycle tracking is not active.",!1);r(y=>[...y,p])}return!0}return!1},[r,l,d]);return F.useEffect(()=>()=>{o.current!==null&&clearInterval(o.current)},[]),{handleAirtimeCommand:f,stopTracking:l}}function Iu(r){if(r<60)return`${r}s`;const a=Math.floor(r/86400),o=Math.floor(r%86400/3600),l=Math.floor(r%3600/60);return a>0?o>0&&l>0?`${a}d${o}h${l}m`:o>0?`${a}d${o}h`:l>0?`${a}d${l}m`:`${a}d`:o>0?l>0?`${o}h${l}m`:`${o}h`:`${l}m`}function jv(r){return["Telemetry",`Battery Voltage: ${r.battery_volts.toFixed(3)}V`,`Uptime: ${Iu(r.uptime_seconds)}`,`TX Airtime: ${Iu(r.airtime_seconds)}`,`RX Airtime: ${Iu(r.rx_airtime_seconds)}`,"",`Noise Floor: ${r.noise_floor_dbm} dBm`,`Last RSSI: ${r.last_rssi_dbm} dBm`,`Last SNR: ${r.last_snr_db.toFixed(1)} dB`,"",`Packets: ${r.packets_received.toLocaleString()} rx / ${r.packets_sent.toLocaleString()} tx`,`Flood: ${r.recv_flood.toLocaleString()} rx / ${r.sent_flood.toLocaleString()} tx`,`Direct: ${r.recv_direct.toLocaleString()} rx / ${r.sent_direct.toLocaleString()} tx`,`Duplicates: ${r.flood_dups.toLocaleString()} flood / ${r.direct_dups.toLocaleString()} direct`,"",`TX Queue: ${r.tx_queue_len}`,`Debug Flags: ${r.full_events}`].join(`
`)}function Hv(r){if(r.length===0)return`Neighbors
No neighbors reported`;const a=[...r].sort((l,d)=>d.snr-l.snr),o=[`Neighbors (${a.length})`];for(const l of a){const d=l.name||l.pubkey_prefix,f=l.snr>=0?`+${l.snr.toFixed(1)}`:l.snr.toFixed(1);o.push(`${d}, ${f} dB [${Iu(l.last_heard_seconds)} ago]`)}return o.join(`
`)}function Vv(r){if(r.length===0)return`ACL
No ACL entries`;const a=[`ACL (${r.length})`];for(const o of r){const l=o.name||o.pubkey_prefix;a.push(`${l}: ${o.permission_name}`)}return a.join(`
`)}function Io(r,a,o,l=0){const d=Math.floor(Date.now()/1e3);return{id:-Date.now()-l,type:"PRIV",conversation_key:r,text:a,sender_timestamp:d,received_at:d,path:null,txt_type:0,signature:null,outgoing:o,acked:1}}function Uv(r,a,o){const[l,d]=F.useState(!1),{handleAirtimeCommand:f,stopTracking:m}=zv(o);F.useEffect(()=>{d(!1),m()},[r==null?void 0:r.id,m]);const h=F.useMemo(()=>{if(!r||r.type!=="contact")return!1;const y=a.find(v=>v.public_key===r.id);return(y==null?void 0:y.type)===l0},[r,a]),x=F.useCallback(async y=>{if(!(!r||r.type!=="contact")&&h)try{const v=await st.requestTelemetry(r.id,y),w=Io(r.id,jv(v),!1,0),k=Io(r.id,Hv(v.neighbors),!1,1),T=Io(r.id,Vv(v.acl),!1,2);o(C=>[...C,w,k,T]),d(!0)}catch(v){const w=Io(r.id,`Telemetry request failed: ${v instanceof Error?v.message:"Unknown error"}`,!1,0);o(k=>[...k,w])}},[r,h,o]),p=F.useCallback(async y=>{if(!r||r.type!=="contact"||!h||!l||await f(y,r.id))return;const w=Io(r.id,`> ${y}`,!0,0);o(k=>[...k,w]);try{const k=await st.sendRepeaterCommand(r.id,y),T=Io(r.id,k.response,!1,1);k.sender_timestamp&&(T.sender_timestamp=k.sender_timestamp),o(C=>[...C,T])}catch(k){const T=Io(r.id,`Command failed: ${k instanceof Error?k.message:"Unknown error"}`,!1,1);o(C=>[...C,T])}},[r,h,l,o,f]);return{repeaterLoggedIn:l,activeContactIsRepeater:h,handleTelemetryRequest:x,handleRepeaterCommand:p}}const Zv=12;function Ws(r){return r.slice(0,Zv)}function BA(r,a){return!r||!a?!1:Ws(r)===Ws(a)}function bi(r,a){return r||Ws(a)}const Uf="remoteterm-lastMessageTime";function PA(r){try{const a=localStorage.getItem(r);return a?JSON.parse(a):{}}catch{return{}}}function Wv(r,a){try{localStorage.setItem(r,JSON.stringify(a))}catch{}}function Bp(){return PA(Uf)}function kf(r,a){const o=PA(Uf);return(!o[r]||a>o[r])&&(o[r]=a,Wv(Uf,o)),o}function Dr(r,a){return r==="channel"?`channel-${a}`:`contact-${Ws(a)}`}function Pp(r,a){if(!a)return!1;const o=a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`@\\[${o}\\]`,"i").test(r)}function qv(r,a,o,l=null){const[d,f]=F.useState({}),[m,h]=F.useState({}),[x,p]=F.useState(Bp),y=F.useRef(l);F.useEffect(()=>{y.current=l},[l]);const v=F.useRef(new Set),w=F.useRef(new Set);F.useEffect(()=>{const D=r.filter(N=>!v.current.has(N.key)),P=a.filter(N=>N.public_key&&!w.current.has(N.public_key));if(D.length===0&&P.length===0)return;D.forEach(N=>v.current.add(N.key)),P.forEach(N=>w.current.add(N.public_key)),(async()=>{const N=[...D.map(M=>({type:"CHAN",conversation_key:M.key})),...P.map(M=>({type:"PRIV",conversation_key:M.public_key}))];if(N.length!==0)try{const M=await st.getMessagesBulk(N,a0),z={},j={},H={};for(const te of D){const Z=M[`CHAN:${te.key}`]||[];if(Z.length>0){const V=Dr("channel",te.key),ne=te.last_read_at||0,X=Z.filter(de=>!de.outgoing&&de.received_at>ne);X.length>0&&(z[V]=X.length,X.some(de=>Pp(de.text,y.current))&&(j[V]=!0));const ie=Math.max(...Z.map(de=>de.received_at));H[V]=ie,kf(V,ie)}}for(const te of P){const Z=M[`PRIV:${te.public_key}`]||[];if(Z.length>0){const V=Dr("contact",te.public_key),ne=te.last_read_at||0,X=Z.filter(de=>!de.outgoing&&de.received_at>ne);X.length>0&&(z[V]=X.length,X.some(de=>Pp(de.text,y.current))&&(j[V]=!0));const ie=Math.max(...Z.map(de=>de.received_at));H[V]=ie,kf(V,ie)}}Object.keys(z).length>0&&f(te=>({...te,...z})),Object.keys(j).length>0&&h(te=>({...te,...j})),p(Bp())}catch(M){console.error("Failed to fetch messages bulk:",M)}})()},[r,a]),F.useEffect(()=>{if(o&&o.type!=="raw"&&o.type!=="map"){const D=Dr(o.type,o.id);f(P=>{if(P[D]){const S={...P};return delete S[D],S}return P}),h(P=>{if(P[D]){const S={...P};return delete S[D],S}return P}),o.type==="channel"?st.markChannelRead(o.id).catch(P=>{console.error("Failed to mark channel as read on server:",P)}):o.type==="contact"&&st.markContactRead(o.id).catch(P=>{console.error("Failed to mark contact as read on server:",P)})}},[o]);const k=F.useCallback((D,P)=>{f(S=>({...S,[D]:(S[D]||0)+1})),P&&h(S=>({...S,[D]:!0}))},[]),T=F.useCallback(()=>{f({}),h({}),st.markAllRead().catch(D=>{console.error("Failed to mark all as read on server:",D)})},[]),C=F.useCallback(D=>{if(D.type==="raw"||D.type==="map")return;const P=Dr(D.type,D.id);f(S=>{if(S[P]){const N={...S};return delete N[P],N}return S}),h(S=>{if(S[P]){const N={...S};return delete N[P],N}return S}),D.type==="channel"?st.markChannelRead(D.id).catch(S=>{console.error("Failed to mark channel as read on server:",S)}):D.type==="contact"&&st.markContactRead(D.id).catch(S=>{console.error("Failed to mark contact as read on server:",S)})},[]),E=F.useCallback(D=>{let P=null;if(D.type==="CHAN"&&D.conversation_key?P=Dr("channel",D.conversation_key):D.type==="PRIV"&&D.conversation_key&&(P=Dr("contact",D.conversation_key)),P){const S=D.received_at||Math.floor(Date.now()/1e3),N=kf(P,S);p(N)}},[]);return{unreadCounts:d,mentions:m,lastMessageTimes:x,incrementUnread:k,markAllRead:T,markConversationRead:C,trackNewMessage:E}}var u0=SA();const TA=Qs(u0);function Gv(r){if(typeof document>"u")return;let a=document.head||document.getElem Line truncated
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const wy=r=>r.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),by=r=>r.replace(/^([A-Z])|[\s-_]+(\w)/g,(a,o,l)=>l?l.toUpperCase():o.toLowerCase()),Rp=r=>{const a=by(r);return a.charAt(0).toUpperCase()+a.slice(1)},DA=(...r)=>r.filter((a,o,l)=>!!a&&a.trim()!==""&&l.indexOf(a)===o).join(" ").trim(),Cy=r=>{for(const a in r)if(a.startsWith("aria-")||a==="role"||a==="title")return!0};/**
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/var Ey={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/**
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const ky=F.forwardRef(({color:r="currentColor",size:a=24,strokeWidth:o=2,absoluteStrokeWidth:l,className:d="",children:f,iconNode:m,...h},x)=>F.createElement("svg",{ref:x,...Ey,width:a,height:a,stroke:r,strokeWidth:l?Number(o)*24/Number(a):o,className:DA("lucide",d),...!f&&!Cy(h)&&{"aria-hidden":"true"},...h},[...m.map(([p,y])=>F.createElement(p,y)),...Array.isArray(f)?f:[f]]));/**
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const c0=(r,a)=>{const o=F.forwardRef(({className:l,...d},f)=>F.createElement(ky,{ref:f,iconNode:a,className:DA(`lucide-${wy(Rp(r))}`,`lucide-${r}`,l),...d}));return o.displayName=Rp(r),o};/**
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Sy=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],By=c0("check",Sy);/**
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Py=[["path",{d:"M4 5h16",key:"1tepv9"}],["path",{d:"M4 12h16",key:"1lakjw"}],["path",{d:"M4 19h16",key:"1djgab"}]],Ty=c0("menu",Py);/**
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Dy=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],RA=c0("x",Dy);function Ry({health:r,config:a,onSettingsClick:o,onMenuClick:l}){const d=(r==null?void 0:r.radio_connected)??!1,[f,m]=F.useState(!1),h=async()=>{m(!0);try{const x=await st.reconnectRadio();x.connected&&kt.success("Reconnected",{description:x.message})}catch(x){kt.error("Reconnection failed",{description:x instanceof Error?x.message:"Check radio connection and power"})}finally{m(!1)}};return B.jsxs("div",{className:"flex items-center gap-4 px-4 py-2 bg-[#252525] border-b border-[#333] text-xs",children:[l&&B.jsx("button",{onClick:l,className:"md:hidden p-1 bg-transparent border-none text-[#e0e0e0] cursor-pointer","aria-label":"Open menu",children:B.jsx(Ty,{className:"h-5 w-5"})}),B.jsx("h1",{className:"hidden lg:block text-base font-semibold mr-auto",children:"RemoteTerm"}),B.jsxs("div",{className:"flex items-center gap-1 text-[#888]",children:[B.jsx("div",{className:`w-2 h-2 rounded-full ${d?"bg-[#4caf50]":"bg-[#666]"}`}),B.jsx("span",{className:"hidden lg:inline text-[#e0e0e0]",children:d?"Connected":"Disconnected"})]}),a&&B.jsx("div",{className:"hidden lg:flex items-center gap-1 text-[#888]",children:B.jsx("span",{className:"text-[#e0e0e0]",children:a.name||"Unnamed"})}),B.jsx("div",{className:"flex-1 lg:hidden"}),!d&&B.jsx("button",{onClick:h,disabled:f,className:"px-3 py-1 bg-[#4a3000] border border-[#6b4500] text-[#ffa500] rounded text-xs cursor-pointer hover:bg-[#5a3a00] disabled:opacity-50 disabled:cursor-not-allowed",children:f?"Reconnecting...":"Reconnect"}),B.jsxs("button",{onClick:o,className:"px-3 py-1 bg-[#333] border border-[#444] text-[#e0e0e0] rounded text-xs cursor-pointer hover:bg-[#444]",children:[B.jsx("span",{role:"img","aria-label":"Settings",children:"🔧"})," ","Radio & Config"]})]})}const Wf=2,Fy={text:"🛜",background:"#444444",textColor:"#ffffff"};function Ny(r){let a=0;for(let o=0;o<r.length;o++){const l=r.charCodeAt(o);a=(a<<5)-a+l,a=a&a}return Math.abs(a)}const Ly=/[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{1F600}-\u{1F64F}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]/u;function My(r,a){if(!r)return a.slice(0,2).toUpperCase();const o=r.match(Ly);if(o)return o[0];const l=r.match(/[a-zA-Z]/g);if(!l||l.length===0)return a.slice(0,2).toUpperCase();const d=r.indexOf(" ");if(d!==-1){const f=l[0],m=r.slice(d+1).match(/[a-zA-Z]/);if(m)return(f+m[0]).toUpperCase()}return l[0].toUpperCase()}function Iy(r){const a=Ny(r),o=a%360,l=50+(a>>8)%30,d=35+(a>>16)%20,f=`hsl(${o}, ${l}%, ${d}%)`,m=d<45?"#ffffff":"#000000";return{background:f,text:m}}function Oy(r,a,o){if(o===Wf)return Fy;const l=My(r,a),d=Iy(a);return{text:l,background:d.background,textColor:d.text}}function qf({name:r,publicKey:a,size:o=28,contactType:l}){const d=Oy(r,a,l);return B.jsx("div",{className:"flex items-center justify-center rounded-full font-semibold flex-shrink-0 select-none",style:{backgroundColor:d.background,color:d.textColor,width:o,height:o,fontSize:o*.45},children:d.text})}const FA="remoteterm-favorites";function Nc(){try{const r=localStorage.getItem(FA);return r?JSON.parse(r):[]}catch{return[]}}function NA(r){try{localStorage.setItem(FA,JSON.stringify(r))}catch{}}function zy(r,a){const o=Nc();if(o.some(d=>d.type===r&&d.id===a))return o;const l=[...o,{type:r,id:a}];return NA(l),l}function jy(r,a){const l=Nc().filter(d=>!(d.type===r&&d.id===a));return NA(l),l}function Hs(r,a,o){return r.some(l=>l.type===a&&l.id===o)}function Hy(r,a){return Nc().some(l=>l.type===r&&l.id===a)?jy(r,a):zy(r,a)}function LA(r){var a,o,l="";if(typeof r=="string"||typeof r=="number")l+=r;else if(typeof r=="object")if(Array.isArray(r)){var d=r.length;for(a=0;a<d;a++)r[a]&&(o=LA(r[a]))&&(l&&(l+=" "),l+=o)}else for(o in r)r[o]&&(l&&(l+=" "),l+=o);return l}function MA(){for(var r,a,o=0,l="",d=arguments.length;o<d;o++)(r=arguments[o])&&(a=LA(r))&&(l&&(l+=" "),l+=a);return l}const Vy=(r,a)=>{const o=new Array(r.length+a.length);for(let l=0;l<r.length;l++)o[l]=r[l];for(let l=0;l<a.length;l++)o[r.length+l]=a[l];return o},Uy=(r,a)=>({classGroupId:r,validator:a}),IA=(r=new Map,a=null,o)=>({nextPart:r,validators:a,classGroupId:o}),Sc="-",Fp=[],Zy="arbitrary..",Wy=r=>{const a=Gy(r),{conflictingClassGroups:o,conflictingClassGroupModifiers:l}=r;return{getClassGroupId:m=>{if(m.startsWith("[")&&m.endsWith("]"))return qy(m);const h=m.split(Sc),x=h[0]===""&&h.length>1?1:0;return OA(h,x,a)},getConflictingClassGroupIds:(m,h)=>{if(h){const x=l[m],p=o[m];return x?p?Vy(p,x):x:p||Fp}return o[m]||Fp}}},OA=(r,a,o)=>{if(r.length-a===0)return o.classGroupId;const d=r[a],f=o.nextPart.get(d);if(f){const p=OA(r,a+1,f);if(p)return p}const m=o.validators;if(m===null)return;const h=a===0?r.join(Sc):r.slice(a).join(Sc),x=m.length;for(let p=0;p<x;p++){const y=m[p];if(y.validator(h))return y.classGroupId}},qy=r=>r.slice(1,-1).indexOf(":")===-1?void 0:(()=>{const a=r.slice(1,-1),o=a.indexOf(":"),l=a.slice(0,o);return l?Zy+l:void 0})(),Gy=r=>{conLine truncated
`).map((W,R,U)=>B.jsxs("span",{children:[V_(W,h),R<U.length-1&&B.jsx("br",{})]},R)),!de&&B.jsx("span",{className:"text-[10px] text-muted-foreground/50 ml-2",children:ol(N.sender_timestamp||N.received_at)}),N.outgoing&&(N.acked>0?` ✓${N.acked>1?N.acked:""}`:" ?")]})]})]},N.id)})]}),v&&B.jsx("button",{onClick:C,className:"absolute bottom-4 right-4 w-10 h-10 rounded-full bg-muted hover:bg-accent border border-border flex items-center justify-center shadow-lg transition-opacity",title:"Scroll to bottom",children:B.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"text-muted-foreground",children:B.jsx("polyline",{points:"6 9 12 15 18 9"})})})]})}const Vp=156,Z_=140,W_=156,q_=120,G_=8,Q_=F.forwardRef(function({onSend:a,disabled:o,placeholder:l,isRepeaterMode:d,conversationType:f,senderName:m},h){const[x,p]=F.useState(""),[y,v]=F.useState(!1),w=F.useRef(null);F.useImperativeHandle(h,()=>({appendText:M=>{var z;p(j=>j+M),(z=w.current)==null||z.focus()}}));const k=F.useMemo(()=>{if(f==="contact")return{warningAt:Z_,dangerAt:Vp,hardLimit:Vp};if(f==="channel"){const M=(m==null?void 0:m.length)??10,z=Math.max(1,W_-M-2);return{warningAt:q_,dangerAt:Math.max(1,z-G_),hardLimit:z}}return null},[f,m]),{limitState:T,warningMessage:C}=F.useMemo(()=>{if(!k)return{limitState:"normal",warningMessage:null};const M=x.length;return M>=k.hardLimit?{limitState:"error",warningMessage:"likely truncated by radio"}:M>=k.dangerAt?{limitState:"danger",warningMessage:"may impact multi-repeater hop delivery"}:M>=k.warningAt?{limitState:"warning",warningMessage:"may impact multi-repeater hop delivery"}:{limitState:"normal",warningMessage:null}},[x.length,k]),E=k?k.hardLimit-x.length:0,D=F.useCallback(async M=>{M.preventDefault();const z=x.trim();if(d){if(y||o)return;v(!0);try{await a(z),p("")}catch(j){console.error("Failed to request telemetry:",j),kt.error("Failed to request telemetry",{description:j instanceof Error?j.message:"Check radio connection"});return}finally{v(!1)}setTimeout(()=>{var j;return(j=w.current)==null?void 0:j.focus()},0)}else{if(!z||y||o)return;v(!0);try{await a(z),p("")}catch(j){console.error("Failed to send message:",j),kt.error("Failed to send message",{description:j instanceof Error?j.message:"Check radio connection"});return}finally{v(!1)}setTimeout(()=>{var j;return(j=w.current)==null?void 0:j.focus()},0)}},[x,y,o,a,d]),P=F.useCallback(M=>{M.key==="Enter"&&!M.shiftKey&&(M.preventDefault(),D(M))},[D]),S=d?!0:x.trim().length>0,N=!d&&k!==null;return B.jsxs("form",{className:"px-4 py-3 border-t border-border flex flex-col gap-1",onSubmit:D,children:[B.jsxs("div",{className:"flex gap-2",children:[B.jsx(Yt,{ref:w,type:d?"password":"text",autoComplete:d?"off":void 0,value:x,onChange:M=>p(M.target.value),onKeyDown:P,placeholder:l||(d?"Enter password for admin login...":"Type a message..."),disabled:o||y,className:"flex-1 min-w-0"}),B.jsx(Nn,{type:"submit",disabled:o||y||!S,className:"flex-shrink-0",children:y?d?"Logging in...":"Sending...":d?x.trim()?"Log in with password":"Log in as guest/use repeater ACLs":"Send"})]}),N&&B.jsxs("div",{className:"flex items-center justify-end gap-2 text-xs",children:[B.jsxs("span",{className:at("tabular-nums",T==="error"||T==="danger"?"text-red-500 font-medium":T==="warning"?"text-yellow-500":"text-muted-foreground"),children:[x.length,"/",k.hardLimit,E<0&&` (${E})`]}),C&&B.jsxs("span",{className:at(T==="error"?"text-red-500":"text-yellow-500"),children:["— ",C]})]})]})});function ln(r,a,{checkForDefaultPrevented:o=!0}={}){return function(d){if(r==null||r(d),o===!1||!d.defaultPrevented)return a==null?void 0:a(d)}}function K_(r,a){const o=F.createContext(a),l=f=>{const{children:m,...h}=f,x=F.useMemo(()=>h,Object.values(h));return B.jsx(o.Provider,{value:x,children:m})};l.displayName=r+"Provider";function d(f){const m=F.useContext(o);if(m)return m;if(a!==void 0)return a;throw new Error(`\`${f}\` must be used within \`${r}\``)}return[l,d]}function cl(r,a=[]){let o=[];function l(f,m){const h=F.createContext(m),x=o.length;o=[...o,m];const p=v=>{var D;const{scope:w,children:k,...T}=v,C=((D=w==null?void 0:w[r])==null?void 0:D[x])||h,E=F.useMemo(()=>T,Object.values(T));return B.jsx(C.Provider,{value:E,children:k})};p.displayName=f+"Provider";function y(v,w){var C;const k=((C=w==null?void 0:w[r])==null?void 0:C[x])||h,T=F.useContext(k);if(T)return T;if(m!==void 0)return m;throw new Error(`\`${v}\` must be used within \`${f}\``)}return[p,y]}const d=()=>{const f=o.map(m=>F.createContext(m));return function(h){const x=(h==null?void 0:h[r])||f;return F.useMemo(()=>({[`__scope${r}`]:{...h,[r]:x}}),[h,x])}};return d.scopeName=r,[l,$_(d,...a)]}function $_(...r){const a=r[0];if(r.length===1)return a;const o=()=>{const l=r.map(d=>({useScope:d(),scopeName:d.scopeName}));return function(f){const m=l.reduce((h,{useScope:x,scopeName:p})=>{const v=x(f)[`__scope${p}Line truncated
.`.concat(D1,` {
overflow: hidden `).concat(l,`;
padding-right: `).concat(h,"px ").concat(l,`;
}
body[`).concat(Us,`] {
overflow: hidden `).concat(l,`;
overscroll-behavior: contain;
`).concat([a&&"position: relative ".concat(l,";"),o==="margin"&&`
padding-left: `.concat(d,`px;
padding-top: `).concat(f,`px;
padding-right: `).concat(m,`px;
margin-left:0;
margin-top:0;
margin-right: `).concat(h,"px ").concat(l,`;
`),o==="padding"&&"padding-right: ".concat(h,"px ").concat(l,";")].filter(Boolean).join(""),`
}
.`).concat(zu,` {
right: `).concat(h,"px ").concat(l,`;
}
.`).concat(ju,` {
margin-right: `).concat(h,"px ").concat(l,`;
}
.`).concat(zu," .").concat(zu,` {
right: 0 `).concat(l,`;
}
.`).concat(ju," .").concat(ju,` {
margin-right: 0 `).concat(l,`;
}
body[`).concat(Us,`] {
`).concat(R1,": ").concat(h,`px;
}
`)},Yp=function(){var r=parseInt(document.body.getAttribute(Us)||"0",10);return isFinite(r)?r:0},Y1=function(){F.useEffect(function(){return document.body.setAttribute(Us,(Yp()+1).toString()),function(){var r=Yp()-1;r<=0?document.body.removeAttribute(Us):document.body.setAttribute(Us,r.toString())}},[])},X1=function(r){var a=r.noRelative,o=r.noImportant,l=r.gapMode,d=l===void 0?"margin":l;Y1();var f=F.useMemo(function(){return Q1(d)},[d]);return F.createElement(K1,{styles:$1(f,!a,d,o?"":"!important")})},Kf=!1;if(typeof window<"u")try{var Fu=Object.defineProperty({},"passive",{get:function(){return Kf=!0,!0}});window.addEventListener("test",Fu,Fu),window.removeEventListener("test",Fu,Fu)}catch{Kf=!1}var Is=Kf?{passive:!1}:!1,J1=function(r){return r.tagName==="TEXTAREA"},sg=function(r,a){if(!(r instanceof Element))return!1;var o=window.getComputedStyle(r);return o[a]!=="hidden"&&!(o.overflowY===o.overflowX&&!J1(r)&&o[a]==="visible")},ew=function(r){return sg(r,"overflowY")},tw=function(r){return sg(r,"overflowX")},Xp=function(r,a){var o=a.ownerDocument,l=a;do{typeof ShadowRoot<"u"&&l instanceof ShadowRoot&&(l=l.host);var d=ag(r,l);if(d){var f=lg(r,l),m=f[1],h=f[2];if(m>h)return!0}l=l.parentNode}while(l&&l!==o.body);return!1},nw=function(r){var a=r.scrollTop,o=r.scrollHeight,l=r.clientHeight;return[a,o,l]},rw=function(r){var a=r.scrollLeft,o=r.scrollWidth,l=r.clientWidth;return[a,o,l]},ag=function(r,a){return r==="v"?ew(a):tw(a)},lg=function(r,a){return r==="v"?nw(a):rw(a)},iw=function(r,a){return r==="h"&&a==="rtl"?-1:1},ow=function(r,a,o,l,d){var f=iw(r,window.getComputedStyle(a).direction),m=f*l,h=o.target,x=a.contains(h),p=!1,y=m>0,v=0,w=0;do{if(!h)break;var k=lg(r,h),T=k[0],C=k[1],E=k[2],D=C-E-f*T;(T||D)&&ag(r,h)&&(v+=D,w+=T);var P=h.parentNode;h=P&&P.nodeType===Node.DOCUMENT_FRAGMENT_NODE?P.host:P}while(!x&&h!==document.body||x&&(a.contains(h)||a===h));return(y&&Math.abs(v)<1||!y&&Math.abs(w)<1)&&(p=!0),p},Nu=function(r){return"changedTouches"in r?[r.changedTouches[0].clientX,r.changedTouches[0].clientY]:[0,0]},Jp=function(r){return[r.deltaX,r.deltaY]},em=function(r){return r&&"current"in r?r.current:r},sw=function(r,a){return r[0]===a[0]&&r[1]===a[1]},aw=function(r){return`
.block-interactivity-`.concat(r,` {pointer-events: none;}
.allow-interactivity-`).concat(r,` {pointer-events: all;}
`)},lw=0,Os=[];function uw(r){var a=F.useRef([]),o=F.useRef([0,0]),l=F.useRef(),d=F.useState(lw++)[0],f=F.useState(og)[0],m=F.useRef(r);F.useEffect(function(){m.current=r},[r]),F.useEffect(function(){if(r.inert){document.body.classList.add("block-interactivity-".concat(d));var C=T1([r.lockRef.current],(r.shards||[]).map(em),!0).filter(Boolean);return C.forEach(function(E){return E.classList.add("allow-interactivity-".concat(d))}),function(){document.body.classList.remove("block-interactivity-".concat(d)),C.forEach(function(E){return E.classList.remove("allow-interactivity-".concat(d))})}}},[r.inert,r.lockRef.current,r.shards]);var h=F.useCallback(function(C,E){if("touches"in C&&C.touches.length===2||C.type==="wheel"&&C.ctrlKey)return!m.current.allowPinchZoom;var D=Nu(C),P=o.current,S="deltaX"in C?C.deltaX:P[0]-D[0],N="deltaY"in C?C.deltaY:P[1]-D[1],M,z=C.target,j=Math.abs(S)>Math.abs(N)?"h":"v";if("touches"in C&&j==="h"&&z.type==="range")return!1;var H=window.getSelection(),te=H&&H.anchorNode,Z=te?te===z||te.contains(z):!1;if(Z)return!1;var V=Xp(j,z);if(!V)return!0;if(V?M=j:(M=j==="v"?"h":"v",V=Xp(j,z)),!V)return!1;if(!l.current&&"changedTouches"in C&&(S||N)&&(l.current=M),!M)return!0;var ne=l.current||M;return ow(ne,E,C,ne==="h"?S:N)},[]),x=F.useCallback(function(C){var E=C;if(!(!Os.length||Os[Os.length-1]!==f)){var D="deltaY"in E?Jp(E):Nu(E),P=a.current.filter(function(M){return M.name===E.type&&(M.target===E.target||E.target===M.shadowParent)&&sw(M.delta,D)})[0];if(P&&P.should){E.cancelable&&E.preventDefault();return}if(!P){var S=(m.current.shards||[]).map(em).filter(Boolean).filter(function(M){return M.contains(E.target)}),N=S.length>0?h(E,S[0]):!m.current.noIsolation;N&&E.cancelable&&E.preventDefault()}}},[]),p=F.useCallback(function(C,E,D,P){var S={name:C,delta:E,target:D,should:P,shadowParent:cw(D)};a.current.push(S),setTimeout(function(){a.current=a.current.filter(function(N){return N!==S})},1)},[]),y=F.useCallback(function(C){o.current=Nu(C),l.current=void 0},[]),v=F.useCallback(function(C){p(C.type,Jp(C),C.target,h(C,r.lockRef.current))},[]),w=F.useCallback(function(C){p(C.type,Nu(C),C.target,h(C,r.lockRef.current))},[]);F.useEffect(function(){return Os.push(f),r.setCallbacks({onScrollCapture:v,onWheelCapture:v,onTouchMoveCapture:w}),document.addEventListener("wheel",x,Is),document.addEventListener("touchmove",x,Is),document.addEventListener("touchstart",y,Is),function(){Os=Os.filter(function(C){return C!==f}),document.removeEventListener("wheel",x,Is),document.removeEventListener("touchmove",x,Is),document.removeEventListener("touchstart",y,Is)}},[]);var k=r.removeScrollBar,T=r.inert;return F.createElement(F.Fragment,null,T?F.createElement(f,{styles:aw(d)}):null,k?F.createElement(X1,{noRelative:r.noRelative,gapMode:r.gapMode}):null)}function cw(r){for(var a=null;r!==null;)r instanceof ShadowRoot&&(a=r.host,r=r.host),r=r.parentNode;return a}const dw=z1(ig,uw);var ug=F.forwardRef(function(r,a){return F.createElement(Mc,Kr({},r,{ref:a,sideCar:dw}))});ug.classNames=Mc.classNames;var fw=function(r){if(typeof document>"u")return null;var a=Array.isArray(r)?r[0]:r;return a.ownerDocument.body},zs=new WeakMap,Lu=new WeakMap,Mu={},Lf=0,cg=function(r){return r&&(r.host||cg(r.parentNode))},hw=function(r,a){return a.map(function(o){if(r.contains(o))return o;var l=cg(o);return l&&r.contains(l)?l:(console.error("aria-hidden",o,"in not contained inside",r,". Doing nothing"),null)}).filter(function(o){return!!o})},pw=function(r,a,o,l){var d=hw(a,Array.isArray(r)?r:[r]);Mu[o]||(Mu[o]=new WeakMap);var f=Mu[o],m=[],h=new Set,x=new Set(d),p=function(v){!v||h.has(v)||(h.add(v),p(v.parentNode))};d.forEach(p);var y=function(v){!v||x.has(v)||Array.prototype.forEach.call(v.children,function(w){if(h.has(w))y(w);else try{var k=w.getAttribute(l),T=k!==null&&k!=="false",C=(zs.get(w)||0)+1,E=(f.get(w)||0)+1;zs.set(w,C),f.set(w,E),m.push(w),C===1&&T&&Lu.set(w,!0),E===1&&w.setAttribute(o,"true"),T||w.setAttribute(l,"true")}catch(D){console.error("aria-hidden: cannot operate on ",w,D)}})};return y(a),h.clear(),Lf++,function(){m.forEach(function(v){var w=zs.get(v)-1,k=f.get(v)-1;zs.set(v,w),f.set(v,k),w||(Lu.has(v)||v.removeAttribute(l),Lu.delete(v)),k||v.removeAttribute(o)}),Lf--,Lf||(zs=new WeakMap,zs=new WeakMap,Lu=new WeakMap,Mu={})}},mw=function(r,a,o){o===void 0&&(o="data-aria-hidden");var l=Array.from(Array.isArray(r)?r:[r]),d=fw(r);return d?(l.push.apply(l,Array.from(d.querySelectorAll("[aria-live], script"))),pw(l,d,o,"aria-hidden")):function(){return null}};function Aw(r){const a=gw(r),o=F.forwardRef((l,d)=>{const{children:f,...m}=l,h=F.Children.toArray(f),x=h.find(vw);if(x){const p=x.props.children,y=h.map(v=>v===x?F.Children.count(p)>1?F.Children.only(null):F.isValidElement(p)?p.props.children:null:v);return B.jsx(a,{...m,ref:d,children:F.isValidElement(p)?F.cloneElement(p,void 0,y):null})}return B.jsx(a,{...m,ref:d,children:f})});return o.displayName=`${r}.Slot`,o}function gw(r){const a=F.forwardRef((o,l)=>{const{chi Line truncated
If you want to hide the \`${a.titleName}\`, you can wrap it with our VisuallyHidden component.
For more information, see https://radix-ui.com/primitives/docs/components/${a.docsSlug}`;return F.useEffect(()=>{r&&(document.getElementById(r)||console.error(o))},[o,r]),null},Tw="DialogDescriptionWarning",Dw=({contentRef:r,descriptionId:a})=>{const l=`Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${Eg(Tw).contentName}}.`;return F.useEffect(()=>{var f;const d=(f=r.current)==null?void 0:f.getAttribute("aria-describedby");a&&d&&(document.getElementById(a)||console.warn(l))},[l,r,a]),null},kg=fg,Sg=mg,Oc=Ag,zc=gg,jc=vg,Hc=_g,Bg=bg;const Pg=kg,Rw=Sg,Tg=F.forwardRef(({className:r,...a},o)=>B.jsx(Oc,{ref:o,className:at("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",r),...a}));Tg.displayName=Oc.displayName;const g0=F.forwardRef(({className:r,children:a,...o},l)=>B.jsxs(Rw,{children:[B.jsx(Tg,{}),B.jsxs(zc,{ref:l,className:at("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",r),...o,children:[a,B.jsxs(Bg,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",children:[B.jsx(RA,{className:"h-4 w-4"}),B.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));g0.displayName=zc.displayName;const x0=({className:r,...a})=>B.jsx("div",{className:at("flex flex-col space-y-1.5 text-center sm:text-left",r),...a});x0.displayName="DialogHeader";const Dg=({className:r,...a})=>B.jsx("div",{className:at("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",r),...a});Dg.displayName="DialogFooter";const v0=F.forwardRef(({className:r,...a},o)=>B.jsx(jc,{ref:o,className:at("text-lg font-semibold leading-none tracking-tight",r),...a}));v0.displayName=jc.displayName;const y0=F.forwardRef(({className:r,...a},o)=>B.jsx(Hc,{ref:o,className:at("text-sm text-muted-foreground",r),...a}));y0.displayName=Hc.displayName;function tm(r){const a=Fw(r),o=F.forwardRef((l,d)=>{const{children:f,...m}=l,h=F.Children.toArray(f),x=h.find(Lw);if(x){const p=x.props.children,y=h.map(v=>v===x?F.Children.count(p)>1?F.Children.only(null):F.isValidElement(p)?p.props.children:null:v);return B.jsx(a,{...m,ref:d,children:F.isValidElement(p)?F.cloneElement(p,void 0,y):null})}return B.jsx(a,{...m,ref:d,children:f})});return o.displayName=`${r}.Slot`,o}function Fw(r){const a=F.forwardRef((o,l)=>{const{children:d,...f}=o;if(F.isValidElement(d)){const m=Iw(d),h=Mw(f,d.props);return d.type!==F.Fragment&&(h.ref=l?ul(l,m):m),F.cloneElement(d,h)}return F.Children.count(d)>1?F.Children.only(null):null});return a.displayName=`${r}.SlotClone`,a}var Nw=Symbol("radix.slottable");function Lw(r){return F.isValidElement(r)&&typeof r.type=="function"&&"__radixId"in r.type&&r.type.__radixId===Nw}function Mw(r,a){const o={...a};for(const l in a){const d=r[l],f=a[l];/^on[A-Z]/.test(l)?d&&f?o[l]=(...h)=>{const x=f(...h);return d(...h),x}:d&&(o[l]=d):l==="style"?o[l]={...d,...f}:l==="className"&&(o[l]=[d,f].filter(Boolean).join(" "))}return{...r,...o}}function Iw(r){var l,d;let a=(l=Object.getOwnPropertyDescriptor(r.props,"ref"))==null?void 0:l.get,o=a&&"isReactWarning"in a&&a.isReactWarning;return o?r.ref:(a=(d=Object.getOwnPropertyDescriptor(r,"ref"))==null?void 0:d.get,o=a&&"isReactWarning"in a&&a.isReactWarning,o?r.props.ref:r.props.ref||r.ref)}function Ow(r){const a=r+"CollectionProvider",[o,l]=cl(a),[d,f]=o(a,{collectionRef:{current:null},itemMap:new Map}),m=C=>{const{scope:E,children:D}=C,P=Ce.useRef(null),S=Ce.useRef(new Map).current;return B.jsx(d,{scope:E,itemMap:S,collectionRef:P,children:D})};m.displayName=a;const h=r+"CollectionSlot",x=tm(h),p=Ce.forwardRef((C,E)=>{const{scope:D,children:P}=C,S=f(h,D),N=xr(E,S.collectionRef);return B.jsx(x,{ref:N,children:P})});p.displayName=h;const y=r+"CollectionItemSlot",v="data-radix-collection-item",w=tm(y),k=Ce.forwardRef((C,E)=>{const{scope:D,children:P,...S}=C,N=Ce.useRef(null),M=xr(E,N),z=f(y,D);return Ce.useEffect(()=>(z.itemMap.set(N,{ref:N,...S}),()=>void z.itemMap.delete(N))),B.jsx(w,{[v]:"",ref:M,children:P})});k.displayName=y;function T(C){const E=f(r+"CollectionConsumer",C);return Ce.useCallback(()=>{const P=E.collectionRef.current;if(!P)return[];const S=Array.from(P.querySelectorAll(`[${v}]`));return Array.from(E.itemMap.values()).sort((z,j)=>S.indexOf(z.ref.current)-S.indexOf(j.ref.current))},[E.coll Line truncated
* Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com
* (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade
*/var T2=nl.exports,im;function D2(){return im||(im=1,(function(r,a){(function(o,l){l(a)})(T2,(function(o){var l="1.9.4";function d(t){var i,u,A,b;for(u=1,A=arguments.length;u<A;u++){b=arguments[u];for(i in b)t[i]=b[i]}return t}var f=Object.create||(function(){function t(){}return function(i){return t.prototype=i,new t}})();function m(t,i){var u=Array.prototype.slice;if(t.bind)return t.bind.apply(t,u.call(arguments,1));var A=u.call(arguments,2);return function(){return t.apply(i,A.length?A.concat(u.call(arguments)):arguments)}}var h=0;function x(t){return"_leaflet_id"in t||(t._leaflet_id=++h),t._leaflet_id}function p(t,i,u){var A,b,O,K;return K=function(){A=!1,b&&(O.apply(u,b),b=!1)},O=function(){A?b=arguments:(t.apply(u,arguments),setTimeout(K,i),A=!0)},O}function y(t,i,u){var A=i[1],b=i[0],O=A-b;return t===A&&u?t:((t-b)%O+O)%O+b}function v(){return!1}function w(t,i){if(i===!1)return t;var u=Math.pow(10,i===void 0?6:i);return Math.round(t*u)/u}function k(t){return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"")}function T(t){return k(t).split(/\s+/)}function C(t,i){Object.prototype.hasOwnProperty.call(t,"options")||(t.options=t.options?f(t.options):{});for(var u in i)t.options[u]=i[u];return t.options}function E(t,i,u){var A=[];for(var b in t)A.push(encodeURIComponent(u?b.toUpperCase():b)+"="+encodeURIComponent(t[b]));return(!i||i.indexOf("?")===-1?"?":"&")+A.join("&")}var D=/\{ *([\w_ -]+) *\}/g;function P(t,i){return t.replace(D,function(u,A){var b=i[A];if(b===void 0)throw new Error("No value provided for variable "+u);return typeof b=="function"&&(b=b(i)),b})}var S=Array.isArray||function(t){return Object.prototype.toString.call(t)==="[object Array]"};function N(t,i){for(var u=0;u<t.length;u++)if(t[u]===i)return u;return-1}var M="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=";function z(t){return window["webkit"+t]||window["moz"+t]||window["ms"+t]}var j=0;function H(t){var i=+new Date,u=Math.max(0,16-(i-j));return j=i+u,window.setTimeout(t,u)}var te=window.requestAnimationFrame||z("RequestAnimationFrame")||H,Z=window.cancelAnimationFrame||z("CancelAnimationFrame")||z("CancelRequestAnimationFrame")||function(t){window.clearTimeout(t)};function V(t,i,u){if(u&&te===H)t.call(i);else return te.call(window,m(t,i))}function ne(t){t&&Z.call(window,t)}var X={__proto__:null,extend:d,create:f,bind:m,get lastId(){return h},stamp:x,throttle:p,wrapNum:y,falseFn:v,formatNum:w,trim:k,splitWords:T,setOptions:C,getParamString:E,template:P,isArray:S,indexOf:N,emptyImageUrl:M,requestFn:te,cancelFn:Z,requestAnimFrame:V,cancelAnimFrame:ne};function ie(){}ie.extend=function(t){var i=function(){C(this),this.initialize&&this.initialize.apply(this,arguments),this.callInitHooks()},u=i.__super__=this.prototype,A=f(u);A.constructor=i,i.prototype=A;for(var b in this)Object.prototype.hasOwnProperty.call(this,b)&&b!=="prototype"&&b!=="__super__"&&(i[b]=this[b]);return t.statics&&d(i,t.statics),t.includes&&(de(t.includes),d.apply(null,[A].concat(t.includes))),d(A,t),delete A.statics,delete A.includes,A.options&&(A.options=u.options?f(u.options):{},d(A.options,t.options)),A._initHooks=[],A.callInitHooks=function(){if(!this._initHooksCalled){u.callInitHooks&&u.callInitHooks.call(this),this._initHooksCalled=!0;for(var O=0,K=A._initHooks.length;O<K;O++)A._initHooks[O].call(this)}},i},ie.include=function(t){var i=this.prototype.options;return d(this.prototype,t),t.options&&(this.prototype.options=i,this.mergeOptions(t.options)),this},ie.mergeOptions=function(t){return d(this.prototype.options,t),this},ie.addInitHook=function(t){var i=Array.prototype.slice.call(arguments,1),u=typeof t=="function"?t:function(){this[t].apply(this,i)};return this.prototype._initHooks=this.prototype._initHooks||[],this.prototype._initHooks.push(u),this};function de(t){if(!(typeof L>"u"||!L||!L.Mixin)){t=S(t)?t:[t];for(var i=0;i<t.length;i++)t[i]===L.Mixin.Events&&console.warn("Deprecated include of L.Mixin.Events: this property will be removed in future releases, please inherit from L.Evented instead.",new Error().stack)}}var ae={on:function(t,i,u){if(typeof t=="object")for(var A in t)this._on(A,t[A],i);else{t=T(t);for(var b=0,O=t.length;b<O;b++)this._on(t[b],i,u)}return this},off:function(t,i,u){if(!arguments.length)delete this._events;else if(typeof t=="object")for(var A in t)this._off(A,t[A],i);else{t=T(t);for(var b=arguments.length===1,O=0,K=t.length;O<K;O++)b?this._off(t[O]):this._off(t[O],i,u)}return this},_on:function(t,i,u,A){if(typeof i!="function"){console.warn("wrong listener type: "+typeof i);return}if(this._listens(t,i,u)===!1){u===this&&(u=void 0);var b={fn:i,ctx:u};A&&(b.once=!0),this._events=this._events||{},this._events[t]=this._events[t]||[],this._events[t].push(b)}},_off:function(t,i,u){var A,b,O;if(this._events&&(A=this._events[t],!!A)){if(arguments.length===1){if(this._firingCount)for(b=0,O=A.length;b<O;b++)A[b].fn=v;delete this._events[t];return}if(typeof i!="function"){console.warn("wrong listener type: "+typeof i);return}var K=tLine truncated
(c) 2012 by Cédric Mesnil. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/return(function(l){var d=o,f=d.lib,m=f.WordArray,h=f.Hasher,x=d.algo,p=m.create([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13]),y=m.create([5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11]),v=m.create([11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6]),w=m.create([8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]),k=m.create([0,1518500249,1859775393,2400959708,2840853838]),T=m.create([1352829926,1548603684,1836072691,2053994217,0]),C=x.RIPEMD160=h.extend({_doReset:function(){this._hash=m.create([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(z,j){for(var H=0;H<16;H++){var te=j+H,Z=z[te];z[te]=(Z<<8|Z>>>24)&16711935|(Z<<24|Z>>>8)&4278255360}var V=this._hash.words,ne=k.words,X=T.words,ie=p.words,de=y.words,ae=v.words,pe=w.words,G,J,W,R,U,Q,$,he,fe,ke;Q=G=V[0],$=J=V[1],he=W=V[2],fe=R=V[3],ke=U=V[4];for(var ge,H=0;H<80;H+=1)ge=G+z[j+ie[H]]|0,H<16?ge+=E(J,W,R)+ne[0]:H<32?ge+=D(J,W,R)+ne[1]:H<48?ge+=P(J,W,R)+ne[2]:H<64?ge+=S(J,W,R)+ne[3]:ge+=N(J,W,R)+ne[4],ge=ge|0,ge=M(ge,ae[H]),ge=ge+U|0,G=U,U=R,R=M(W,10),W=J,J=ge,ge=Q+z[j+de[H]]|0,H<16?ge+=N($,he,fe)+X[0]:H<32?ge+=S($,he,fe)+X[1]:H<48?ge+=P($,he,fe)+X[2]:H<64?ge+=D($,he,fe)+X[3]:ge+=E($,he,fe)+X[4],ge=ge|0,ge=M(ge,pe[H]),ge=ge+ke|0,Q=ke,ke=fe,fe=M(he,10),he=$,$=ge;ge=V[1]+W+fe|0,V[1]=V[2]+R+ke|0,V[2]=V[3]+U+Q|0,V[3]=V[4]+G+$|0,V[4]=V[0]+J+he|0,V[0]=ge},_doFinalize:function(){var z=this._data,j=z.words,H=this._nDataBytes*8,te=z.sigBytes*8;j[te>>>5]|=128<<24-te%32,j[(te+64>>>9<<4)+14]=(H<<8|H>>>24)&16711935|(H<<24|H>>>8)&4278255360,z.sigBytes=(j.length+1)*4,this._process();for(var Z=this._hash,V=Z.words,ne=0;ne<5;ne++){var X=V[ne];V[ne]=(X<<8|X>>>24)&16711935|(X<<24|X>>>8)&4278255360}return Z},clone:function(){var z=h.clone.call(this);return z._hash=this._hash.clone(),z}});function E(z,j,H){return z^j^H}function D(z,j,H){return z&j|~z&H}function P(z,j,H){return(z|~j)^H}function S(z,j,H){return z&H|j&~H}function N(z,j,H){return z^(j|~H)}function M(z,j){return z<<j|z>>>32-j}d.RIPEMD160=h._createHelper(C),d.HmacRIPEMD160=h._createHmacHelper(C)})(),o.RIPEMD160})})(tc)),tc.exports}var nc={exports:{}},yb=nc.exports,bm;function Qc(){return bm||(bm=1,(function(r,a){(function(o,l){r.exports=l(dt())})(yb,function(o){(function(){var l=o,d=l.lib,f=d.Base,m=l.enc,h=m.Utf8,x=l.algo;x.HMAC=f.extend({init:function(p,y){p=this._hasher=new p.init,typeof y=="string"&&(y=h.parse(y));var v=p.blockSize,w=v*4;y.sigBytes>w&&(y=p.finalize(y)),y.clamp();for(var k=this._oKey=y.clone(),T=this._iKey=y.clone(),C=k.words,E=T.words,D=0;D<v;D++)C[D]^=1549556828,E[D]^=909522486;k.sigBytes=T.sigBytes=w,this.reset()},reset:function(){var p=this._hasher;p.reset(),p.update(this._iKey)},update:function(p){return this._hasher.update(p),this},finalize:function(p){var y=this._hasher,v=y.finalize(p);y.reset();var w=y.finalize(this._oKey.clone().concat(v));return w}})})()})})(nc)),nc.exports}var rc={exports:{}},_b=rc.exports,Cm;function wb(){return Cm||(Cm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),fl(),Qc())})(_b,function(o){return(function(){var l=o,d=l.lib,f=d.Base,m=d.WordArray,h=l.algo,x=h.SHA256,p=h.HMAC,y=h.PBKDF2=f.extend({cfg:f.extend({keySize:128/32,hasher:x,iterations:25e4}),init:function(v){this.cfg=this.cfg.extend(v)},compute:function(v,w){for(var k=this.cfg,T=p.create(k.hasher,v),C=m.create(),E=m.create([1]),D=C.words,P=E.words,S=k.keySize,N=k.iterations;D.length<S;){var M=T.update(w).finalize(E);T.reset();for(var z=M.words,j=z.length,H=M,te=1;te<N;te++){H=T.finalize(H),T.reset();for(var Z=H.words,V=0;V<j;V++)z[V]^=Z[V]}C.concat(M),P[0]++}return C.sigBytes=S*4,C}});l.PBKDF2=function(v,w,k){return y.create(k).compute(v,w)}})(),o.PBKDF2})})(rc)),rc.exports}var ic={exports:{}},bb=ic.exports,Em;function uo(){return Em||(Em=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),mx(),Qc())})(bb,function(o){return(function(){var l=o,d=l.lib,f=d.Base,m=d.WordArray,h=l.algo,x=h.MD5,p=h.EvpKDF=f.extend({cfg:f.extend({keySize:128/32,hasher:x,iterations:1}),init:function(y){this.cfg=this.cfg.extend(y)},compute:function(y,v){for(var w,k=this.cfg,T=k.hasher.create(),C=m.create(),E=C.words,D=k.keySize,P=k.iterations;E.length<D;){w&&T.update(w),w=T.update(y).finalize(v),T.reset();for(var S=1;S<P;S++)w=T.finalize(w),T.reset();C.concat(w)}return C.sigBytes=D*4,C}});l.EvpKDF=function(y,v,w){return p.create(w).compute(y,v)}})(),o.EvpKDF})})(ic)),ic.exports}var oc={exports:{}},Cb=oc.exports,Line truncated
* Counter block mode compatible with Dr Brian Gladman fileenc.c
* derived from CryptoJS.mode.CTR
* Jan Hruby jhruby.web@gmail.com
*/return o.mode.CTRGladman=(function(){var l=o.lib.BlockCipherMode.extend();function d(h){if((h>>24&255)===255){var x=h>>16&255,p=h>>8&255,y=h&255;x===255?(x=0,p===255?(p=0,y===255?y=0:++y):++p):++x,h=0,h+=x<<16,h+=p<<8,h+=y}else h+=1<<24;return h}function f(h){return(h[0]=d(h[0]))===0&&(h[1]=d(h[1])),h}var m=l.Encryptor=l.extend({processBlock:function(h,x){var p=this._cipher,y=p.blockSize,v=this._iv,w=this._counter;v&&(w=this._counter=v.slice(0),this._iv=void 0),f(w);var k=w.slice(0);p.encryptBlock(k,0);for(var T=0;T<y;T++)h[x+T]^=k[T]}});return l.Decryptor=m,l})(),o.mode.CTRGladman})})(lc)),lc.exports}var uc={exports:{}},Db=uc.exports,Tm;function Rb(){return Tm||(Tm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(Db,function(o){return o.mode.OFB=(function(){var l=o.lib.BlockCipherMode.extend(),d=l.Encryptor=l.extend({processBlock:function(f,m){var h=this._cipher,x=h.blockSize,p=this._iv,y=this._keystream;p&&(y=this._keystream=p.slice(0),this._iv=void 0),h.encryptBlock(y,0);for(var v=0;v<x;v++)f[m+v]^=y[v]}});return l.Decryptor=d,l})(),o.mode.OFB})})(uc)),uc.exports}var cc={exports:{}},Fb=cc.exports,Dm;function Nb(){return Dm||(Dm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(Fb,function(o){return o.mode.ECB=(function(){var l=o.lib.BlockCipherMode.extend();return l.Encryptor=l.extend({processBlock:function(d,f){this._cipher.encryptBlock(d,f)}}),l.Decryptor=l.extend({processBlock:function(d,f){this._cipher.decryptBlock(d,f)}}),l})(),o.mode.ECB})})(cc)),cc.exports}var dc={exports:{}},Lb=dc.exports,Rm;function Mb(){return Rm||(Rm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(Lb,function(o){return o.pad.AnsiX923={pad:function(l,d){var f=l.sigBytes,m=d*4,h=m-f%m,x=f+h-1;l.clamp(),l.words[x>>>2]|=h<<24-x%4*8,l.sigBytes+=h},unpad:function(l){var d=l.words[l.sigBytes-1>>>2]&255;l.sigBytes-=d}},o.pad.Ansix923})})(dc)),dc.exports}var fc={exports:{}},Ib=fc.exports,Fm;function Ob(){return Fm||(Fm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(Ib,function(o){return o.pad.Iso10126={pad:function(l,d){var f=d*4,m=f-l.sigBytes%f;l.concat(o.lib.WordArray.random(m-1)).concat(o.lib.WordArray.create([m<<24],1))},unpad:function(l){var d=l.words[l.sigBytes-1>>>2]&255;l.sigBytes-=d}},o.pad.Iso10126})})(fc)),fc.exports}var hc={exports:{}},zb=hc.exports,Nm;function jb(){return Nm||(Nm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(zb,function(o){return o.pad.Iso97971={pad:function(l,d){l.concat(o.lib.WordArray.create([2147483648],1)),o.pad.ZeroPadding.pad(l,d)},unpad:function(l){o.pad.ZeroPadding.unpad(l),l.sigBytes--}},o.pad.Iso97971})})(hc)),hc.exports}var pc={exports:{}},Hb=pc.exports,Lm;function Vb(){return Lm||(Lm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(Hb,function(o){return o.pad.ZeroPadding={pad:function(l,d){var f=d*4;l.clamp(),l.sigBytes+=f-(l.sigBytes%f||f)},unpad:function(l){for(var d=l.words,f=l.sigBytes-1,f=l.sigBytes-1;f>=0;f--)if(d[f>>>2]>>>24-f%4*8&255){l.sigBytes=f+1;break}}},o.pad.ZeroPadding})})(pc)),pc.exports}var mc={exports:{}},Ub=mc.exports,Mm;function Zb(){return Mm||(Mm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(Ub,function(o){return o.pad.NoPadding={pad:function(){},unpad:function(){}},o.pad.NoPadding})})(mc)),mc.exports}var Ac={exports:{}},Wb=Ac.exports,Im;function qb(){return Im||(Im=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(Wb,function(o){return(function(l){var d=o,f=d.lib,m=f.CipherParams,h=d.enc,x=h.Hex,p=d.format;p.Hex={stringify:function(y){return y.ciphertext.toString(x)},parse:function(y){var v=x.parse(y);return m.create({ciphertext:v})}}})(),o.format.Hex})})(Ac)),Ac.exports}var gc={exports:{}},Gb=gc.exports,Om;function Qb(){return Om||(Om=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),Go(),Qo(),uo(),hn())})(Gb,function(o){return(function(){var l=o,d=l.lib,f=d.BlockCipher,m=l.algo,h=[],x=[],p=[],y=[],v=[],w=[],k=[],T=[],C=[],E=[];(function(){for(var S=[],N=0;N<256;N++)N<128?S[N]=N<<1:S[N]=N<<1^283;for(var M=0,z=0,N=0;N<256;N++){var j=z^z<<1^z<<2^z<<3^z<<4;j=j>>>8^j&255^99,h[M]=j,x[j]=M;var H=S[M],te=S[H],Z=S[te],V=S[j]*257^j*16843008;p[M]=V<<24|V>>>8,y[M]=V<<16|V>>>16,v[M]=V<<8|V>>>24,w[M]=V;var V=Z*16843009^te*65537^H*257^M*16843008;k[j]=V<<24|V>>>8,T[j]=V<<16|V>>>16,C[j]=V<<8|V>>>24,E[j]=V,M?(M=H^S[S[S[Z^H]]],z^=S[S[z]]):M=z=1}})();var D=[0,1,2,4,8,16,32,64,128,27,54],P=m.AES=f.extend({_doReset:function(){var S;if(!(this._nRounds&&this._keyPriorReset===this._key)){for(var N=this._keyPriorReset=this._key,M=N.words,z=N.sigBytes/4,j=this._nRounds=z+6,H=(j+1)*4,te=this._keySchedule=[],Z=0;Z<H;Z++)Z<z?te[Z]=M[Z]:(S=te[Z-1],Z%z?z>6&&Z%z==4&&(S=h[S>>>24]<<24|h[S>>>16&255]<<16|h[S>>>8&255]<<8|h[S&255]):(S=S<<8|S>>>24,S=h[S>>>24]<<24|h[S>>>16&255]<<16|h[S>>>8&255]<<8|h[S&255],S^=D[Z/z|0]<<24),te[Z]=te[Z-z]^S);for(var V=this._invKeySchedule=[],ne=0;ne<H;ne++){var Z=H-ne;if(ne%4)var S=te[Z];else var S=te[Z-4];ne<4||Z<=4?V[ne]=S:V[ne]=k[h[S>>>24]]^T[h[S>>>16&255]]^C[h[S>>>8&255]]^E[h[S&255]Line truncated
• Timestamp (4 bytes) - send time as unix timestamp
• Request Type (1 byte) - type of request (GetStats, GetTelemetryData, etc.)
• Request Data (remaining bytes) - additional request-specific data`,startByte:h+x,endByte:h+d.length-1,value:w});const k={type:r.PayloadType.Request,version:r.PayloadVersion.Version1,isValid:!0,timestamp:0,requestType:r.RequestType.GetStats,requestData:"",destinationHash:p,sourceHash:y,cipherMac:v,ciphertext:w};return f!=null&&f.includeSegments&&(k.segments=m),k}catch(m){return{type:r.PayloadType.Request,version:r.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode request payload"],timestamp:0,requestType:r.RequestType.GetStats,requestData:"",destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:""}}}}return Ka.RequestPayloadDecoder=o,Ka}var $a={},aA;function TC(){if(aA)return $a;aA=1,Object.defineProperty($a,"__esModule",{value:!0}),$a.ResponsePayloadDecoder=void 0;const r=or(),a=xn();class o{static decode(d,f){try{if(d.length<4){const T={type:r.PayloadType.Response,version:r.PayloadVersion.Version1,isValid:!1,errors:["Response payload too short (minimum 4 bytes: dest + source + MAC)"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return f!=null&&f.includeSegments&&(T.segments=[{name:"Invalid Response Data",description:"Response payload too short (minimum 4 bytes required)",startByte:f.segmentOffset||0,endByte:(f.segmentOffset||0)+d.length-1,value:(0,a.bytesToHex)(d)}]),T}const m=[],h=(f==null?void 0:f.segmentOffset)||0;let x=0;const p=(0,a.byteToHex)(d[x]);f!=null&&f.includeSegments&&m.push({name:"Destination Hash",description:"First byte of destination node public key",startByte:h+x,endByte:h+x,value:p}),x+=1;const y=(0,a.byteToHex)(d[x]);f!=null&&f.includeSegments&&m.push({name:"Source Hash",description:"First byte of source node public key",startByte:h+x,endByte:h+x,value:y}),x+=1;const v=(0,a.bytesToHex)(d.subarray(x,x+2));f!=null&&f.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data in next field",startByte:h+x,endByte:h+x+1,value:v}),x+=2;const w=(0,a.bytesToHex)(d.subarray(x));f!=null&&f.includeSegments&&d.length>x&&m.push({name:"Ciphertext",description:"Encrypted response data (tag + content)",startByte:h+x,endByte:h+d.length-1,value:w});const k={type:r.PayloadType.Response,version:r.PayloadVersion.Version1,isValid:!0,destinationHash:p,sourceHash:y,cipherMac:v,ciphertext:w,ciphertextLength:d.length-4};return f!=null&&f.includeSegments&&(k.segments=m),k}catch(m){return{type:r.PayloadType.Response,version:r.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode response payload"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0}}}}return $a.ResponsePayloadDecoder=o,$a}var Ya={},lA;function DC(){if(lA)return Ya;lA=1,Object.defineProperty(Ya,"__esModule",{value:!0}),Ya.AnonRequestPayloadDecoder=void 0;const r=or(),a=xn();class o{static decode(d,f){try{if(d.length<35){const T={type:r.PayloadType.AnonRequest,version:r.PayloadVersion.Version1,isValid:!1,errors:["AnonRequest payload too short (minimum 35 bytes: dest + public key + MAC)"],destinationHash:"",senderPublicKey:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return f!=null&&f.includeSegments&&(T.segments=[{name:"Invalid AnonRequest Data",description:"AnonRequest payload too short (minimum 35 bytes required: 1 for dest hash + 32 for public key + 2 for MAC)",startByte:f.segmentOffset||0,endByte:(f.segmentOffset||0)+d.length-1,value:(0,a.bytesToHex)(d)}]),T}const m=[],h=(f==null?void 0:f.segmentOffset)||0;let x=0;const p=(0,a.byteToHex)(d[0]);f!=null&&f.includeSegments&&m.push({name:"Destination Hash",description:`First byte of destination node public key: 0x${p}`,startByte:h+x,endByte:h+x,value:p}),x+=1;const y=(0,a.bytesToHex)(d.subarray(1,33));f!=null&&f.includeSegments&&m.push({name:"Sender Public Key",description:"Ed25519 public key of the sender (32 bytes)",startByte:h+x,endByte:h+x+31,value:y}),x+=32;const v=(0,a.bytesToHex)(d.subarray(33,35));f!=null&&f.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data verification (2 bytes)",startByte:h+x,endByte:h+x+1,value:v}),x+=2;const w=(0,a.bytesToHex)(d.subarray(35));f!=null&&f.includeSegments&&d.length>35&&m.push({name:"Ciphertext",description:`Encrypted message data (${d.length-35} bytes). Contains encrypted plaintext with this structure:
• Timestamp (4 bytes) - send time as unix timestamp
• Sync Timestamp (4 bytes) - room server only, sender's "sync messages SINCE x" timestamp
• Password (remaining bytes) - password for repeater/room`,startByte:h+x,endByte:h+d.length-1,value:w});const k={type:r.PayloadType.AnonRequest,version:r.PayloadVersion.Version1,isValid:!0,destinationHash:p,senderPublicKey:y,cipherMac:v,ciphertext:w,ciphertextLength:d.length-35};return f!=null&&f.includeSegments&&(k.segments=m),k}catch(m){return{type:r.PayloadType.AnonRequest,version:r.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode AnonRequest payload"],destinationHash:"",senderPublicKey:"",cipherMac:"",ciphertext:"",ciphertextLength:0}}}}return Ya.AnonRequestPayloadDecoder=o,Ya}var Xa={},uA;function RC(){if(uA)return Xa;uA=1,Object.defineProperty(Xa,"__esModule",{value:!0}),Xa.AckPayloadDecoder=void 0;const r=or(),a=xn();class o{static decode(d,f){try{if(d.length<4){const y={type:r.PayloadType.Ack,version:r.PayloadVersion.Version1,isValid:!1,errors:["Ack payload too short (minimum 4 bytes for checksum)"],checksum:""};return f!=null&&f.includeSegments&&(y.segments=[{name:"Invalid Ack Data",description:"Ack payload too short (minimum 4 bytes required for checksum)",startByte:f.segmentOffset||0,endByte:(f.segmentOffset||0)+d.length-1,value:(0,a.bytesToHex)(d)}]),y}const m=[],h=(f==null?void 0:f.segmentOffset)||0,x=(0,a.bytesToHex)(d.subarray(0,4));f!=null&&f.includeSegments&&m.push({name:"Checksum",description:`CRC checksum of message timestamp, text, and sender pubkey: 0x${x}`,startByte:h,endByte:h+3,value:x}),f!=null&&f.includeSegments&&d.length>4&&m.push({name:"Additional Data",description:"Extra data in Ack payload",startByte:h+4,endByte:h+d.length-1,value:(0,a.bytesToHex)(d.subarray(4))});const p={type:r.PayloadType.Ack,version:r.PayloadVersion.Version1,isValid:!0,checksum:x};return f!=null&&f.includeSegments&&(p.segments=m),p}catch(m){return{type:r.PayloadType.Ack,version:r.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode Ack payload"],checksum:""}}}}return Xa.AckPayloadDecoder=o,Xa}var Ja={},cA;function FC(){if(cA)return Ja;cA=1,Object.defineProperty(Ja,"__esModule",{value:!0}),Ja.PathPayloadDecoder=void 0;const r=or(),a=xn();class o{static decode(d){try{if(d.length<2)return{type:r.PayloadType.Path,version:r.PayloadVersion.Version1,isValid:!1,errors:["Path payload too short (minimum 2 bytes: path length + extra type)"],pathLength:0,pathHashes:[],extraType:0,extraData:""};const f=d[0];if(d.length<1+f+1)return{type:r.PayloadType.Path,version:r.PayloadVersion.Version1,isValid:!1,errors:[`Path payload too short (need ${1+f+1} bytes for path length + path + extra type)`],pathLength:f,pathHashes:[],extraType:0,extraData:""};const m=[];for(let p=0;p<f;p++)m.push((0,a.byteToHex)(d[1+p]));const h=d[1+f];let x="";return d.length>1+f+1&&(x=(0,a.bytesToHex)(d.subarray(1+f+1))),{type:r.PayloadType.Path,version:r.PayloadVersion.Version1,isValid:!0,pathLength:f,pathHashes:m,extraType:h,extraData:x}}catch(f){return{type:r.PayloadType.Path,version:r.PayloadVersion.Version1,isValid:!1,errors:[f instanceof Error?f.message:"Failed to decode Path payload"],pathLength:0,pathHashes:[],extraType:0,extraData:""}}}}return Ja.PathPayloadDecoder=o,Ja}var el={},dA;function NC(){if(dA)return el;dA=1,Object.defineProperty(el,"__esModule",{value:!0}),el.TextMessagePayloadDecoder=void 0;const r=or(),a=xn();class o{static decode(d,f){try{if(d.length<4){const T={type:r.PayloadType.TextMessage,version:r.PayloadVersion.Version1,isValid:!1,errors:["TextMessage payload too short (minimum 4 bytes: dest + source + MAC)"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return f!=null&&f.includeSegments&&(T.segments=[{name:"Invalid TextMessage Data",description:"TextMessage payload too short (minimum 4 bytes required)",startByte:f.segmentOffset||0,endByte:(f.segmentOffset||0)+d.length-1,value:(0,a.bytesToHex)(d)}]),T}const m=[],h=(f==null?void 0:f.segmentOffset)||0;let x=0;const p=(0,a.byteToHex)(d[x]);f!=null&&f.includeSegments&&m.push({name:"Destination Hash",description:"First byte of destination node public key",startByte:h+x,endByte:h+x,value:p}),x+=1;const y=(0,a.byteToHex)(d[x]);f!=null&&f.includeSegments&&m.push({name:"Source Hash",description:"First byte of source node public key",startByte:h+x,endByte:h+x,value:y}),x+=1;const v=(0,a.bytesToHex)(d.subarray(x,x+2));f!=null&&f.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data in next field",startByte:h+x,endByte:h+x+1,value:v}),x+=2;const w=(0,a.bytesToHex)(d.subarray(x));f!=null&&f.includeSegments&&d.length>x&&m.push({name:"Ciphertext",description:"Encrypted message data (timestamp + message text)",startByte:h+x,endByte:h+d.length-1,value:w});const k={type:r.PayloadType.TextMessage,version:r.PayloadVersion.Version1,isValid:!0,destinationHash:p,sourceHash:y,cipherMac:v,ciphertext:w,ciphertextLength:d.length-4};return f!=null&&f.includeSegments&&(k.segments=m),k}catch(m){return{type:r.PayloadType.TextMessage,version:r.PayloadVersion.Version1,i Line truncated
// SHA256 round constants
const K: array<u32, 64> = array<u32, 64>(
0x428a2f98u, 0x71374491u, 0xb5c0fbcfu, 0xe9b5dba5u, 0x3956c25bu, 0x59f111f1u, 0x923f82a4u, 0xab1c5ed5u,
0xd807aa98u, 0x12835b01u, 0x243185beu, 0x550c7dc3u, 0x72be5d74u, 0x80deb1feu, 0x9bdc06a7u, 0xc19bf174u,
0xe49b69c1u, 0xefbe4786u, 0x0fc19dc6u, 0x240ca1ccu, 0x2de92c6fu, 0x4a7484aau, 0x5cb0a9dcu, 0x76f988dau,
0x983e5152u, 0xa831c66du, 0xb00327c8u, 0xbf597fc7u, 0xc6e00bf3u, 0xd5a79147u, 0x06ca6351u, 0x14292967u,
0x27b70a85u, 0x2e1b2138u, 0x4d2c6dfcu, 0x53380d13u, 0x650a7354u, 0x766a0abbu, 0x81c2c92eu, 0x92722c85u,
0xa2bfe8a1u, 0xa81a664bu, 0xc24b8b70u, 0xc76c51a3u, 0xd192e819u, 0xd6990624u, 0xf40e3585u, 0x106aa070u,
0x19a4c116u, 0x1e376c08u, 0x2748774cu, 0x34b0bcb5u, 0x391c0cb3u, 0x4ed8aa4au, 0x5b9cca4fu, 0x682e6ff3u,
0x748f82eeu, 0x78a5636fu, 0x84c87814u, 0x8cc70208u, 0x90befffau, 0xa4506cebu, 0xbef9a3f7u, 0xc67178f2u
);
// Character lookup table (a-z = 0-25, 0-9 = 26-35, dash = 36)
const CHARS: array<u32, 37> = array<u32, 37>(
0x61u, 0x62u, 0x63u, 0x64u, 0x65u, 0x66u, 0x67u, 0x68u, 0x69u, 0x6au, // a-j
0x6bu, 0x6cu, 0x6du, 0x6eu, 0x6fu, 0x70u, 0x71u, 0x72u, 0x73u, 0x74u, // k-t
0x75u, 0x76u, 0x77u, 0x78u, 0x79u, 0x7au, // u-z
0x30u, 0x31u, 0x32u, 0x33u, 0x34u, 0x35u, 0x36u, 0x37u, 0x38u, 0x39u, // 0-9
0x2du // dash
);
struct Params {
target_channel_hash: u32,
batch_offset: u32,
name_length: u32,
batch_size: u32,
target_mac: u32, // First 2 bytes of target MAC (in high 16 bits)
ciphertext_words: u32, // Number of 32-bit words in ciphertext
ciphertext_len_bits: u32, // Length of ciphertext in bits
verify_mac: u32, // 1 to verify MAC, 0 to skip
}
@group(0) @binding(0) var<uniform> params: Params;
@group(0) @binding(1) var<storage, read_write> match_count: atomic<u32>;
@group(0) @binding(2) var<storage, read_write> match_indices: array<u32>;
@group(0) @binding(3) var<storage, read> ciphertext: array<u32>; // Ciphertext data
fn rotr(x: u32, n: u32) -> u32 {
return (x >> n) | (x << (32u - n));
}
fn ch(x: u32, y: u32, z: u32) -> u32 {
return (x & y) ^ (~x & z);
}
fn maj(x: u32, y: u32, z: u32) -> u32 {
return (x & y) ^ (x & z) ^ (y & z);
}
fn sigma0(x: u32) -> u32 {
return rotr(x, 2u) ^ rotr(x, 13u) ^ rotr(x, 22u);
}
fn sigma1(x: u32) -> u32 {
return rotr(x, 6u) ^ rotr(x, 11u) ^ rotr(x, 25u);
}
fn gamma0(x: u32) -> u32 {
return rotr(x, 7u) ^ rotr(x, 18u) ^ (x >> 3u);
}
fn gamma1(x: u32) -> u32 {
return rotr(x, 17u) ^ rotr(x, 19u) ^ (x >> 10u);
}
// Convert index to room name bytes, returns the hash as a u32 for the first byte check
fn index_to_room_name(idx: u32, length: u32, msg: ptr<function, array<u32, 16>>) -> bool {
// Message starts with '#' (0x23)
var byte_pos = 0u;
var word_idx = 0u;
var current_word = 0x23000000u; // '#' in big-endian position 0
byte_pos = 1u;
var remaining = idx;
var prev_was_dash = false;
// Generate room name from index
for (var i = 0u; i < length; i++) {
let char_count = select(37u, 36u, i == 0u || i == length - 1u); // no dash at start/end
var char_idx = remaining % char_count;
remaining = remaining / char_count;
// Check for consecutive dashes (invalid)
let is_dash = char_idx == 36u && i > 0u && i < length - 1u;
if (is_dash && prev_was_dash) {
return false; // Invalid: consecutive dashes
}
prev_was_dash = is_dash;
// Map char index to actual character
let c = CHARS[char_idx];
// Pack byte into current word (big-endian)
let shift = (3u - byte_pos % 4u) * 8u;
if (byte_pos % 4u == 0u && byte_pos > 0u) {
(*msg)[word_idx] = current_word;
word_idx = word_idx + 1u;
current_word = 0u;
}
current_word = current_word | (c << shift);
byte_pos = byte_pos + 1u;
}
// Add padding: 0x80 followed by zeros, then length in bits
let msg_len_bits = (length + 1u) * 8u; // +1 for '#'
// Add 0x80 padding byte
let shift = (3u - byte_pos % 4u) * 8u;
if (byte_pos % 4u == 0u) {
(*msg)[word_idx] = current_word;
word_idx = word_idx + 1u;
current_word = 0x80000000u;
} else {
current_word = current_word | (0x80u << shift);
}
byte_pos = byte_pos + 1u;
// Store current word
if (byte_pos % 4u == 0u || word_idx < 14u) {
(*msg)[word_idx] = current_word;
word_idx = word_idx + 1u;
}
// Zero-fill until word 14
for (var i = word_idx; i < 14u; i++) {
(*msg)[i] = 0u;
}
// Length in bits (64-bit, but we only use lower 32 bits for short messages)
(*msg)[14u] = 0u;
(*msg)[15u] = msg_len_bits;
return true;
}
fn sha256_block(msg: ptr<function, array<u32, 16>>) -> array<u32, 8> {
// Initialize hash values
var h: array<u32, 8> = array<u32, 8>(
0x6a09e667u, 0xbb67ae85u, 0x3c6ef372u, 0xa54ff53au,
0x510e527fu, 0x9b05688cu, 0x1f83d9abu, 0x5be0cd19u
);
// Message schedule
var w: array<u32, 64>;
for (var i = 0u; i < 16u; i++) {
w[i] = (*msg)[i];
}
for (var i = 16u; i < 64u; i++) {
w[i] = gamma1(w[i-2u]) + w[i-7u] + gamma0(w[i-15u]) + w[i-16u];
}
// Compression
var a = h[0]; var b = h[1]; var c = h[2]; var d = h[3];
var e = h[4]; var f = h[5]; var g = h[6]; var hh = h[7];
for (var i = 0u; i < 64u; i++) {
let t1 = hh + sigma1(e) + ch(e, f, g) + K[i] + w[i];
let t2 = sigma0(a) + maj(a, b, c);
hh = g; g = f; f = e; e = d + t1;
d = c; c = b; b = a; a = t1 + t2;
}
h[0] = h[0] + a; h[1] = h[1] + b; h[2] = h[2] + c; h[3] = h[3] + d;
h[4] = h[4] + e; h[5] = h[5] + f; h[6] = h[6] + g; h[7] = h[7] + hh;
return h;
}
// Compute SHA256 of the key (16 bytes) to get channel hash
fn sha256_key(key: array<u32, 4>) -> u32 {
var msg: array<u32, 16>;
// Key bytes (16 bytes = 4 words)
msg[0] = key[0];
msg[1] = key[1];
msg[2] = key[2];
msg[3] = key[3];
// Padding: 0x80 followed by zeros
msg[4] = 0x80000000u;
for (var i = 5u; i < 14u; i++) {
msg[i] = 0u;
}
// Length: 128 bits
msg[14] = 0u;
msg[15] = 128u;
let hash = sha256_block(&msg);
// Return first byte of hash (big-endian)
return hash[0] >> 24u;
}
// HMAC-SHA256 for MAC verification
// Key is 16 bytes (4 words), padded to 32 bytes with zeros for MeshCore
// Returns first 2 bytes of HMAC (as u32 in high 16 bits)
fn hmac_sha256_mac(key: array<u32, 4>, ciphertext_len: u32) -> u32 {
// HMAC: H((K' ^ opad) || H((K' ^ ipad) || message))
// K' is 64 bytes (32 bytes key + 32 bytes zero padding for MeshCore, then padded to 64)
// ipad = 0x36 repeated, opad = 0x5c repeated
// Build padded key (64 bytes = 16 words)
// MeshCore uses 32-byte secret: 16-byte key + 16 zero bytes
var k_pad: array<u32, 16>;
k_pad[0] = key[0];
k_pad[1] = key[1];
k_pad[2] = key[2];
k_pad[3] = key[3];
for (var i = 4u; i < 16u; i++) {
k_pad[i] = 0u;
}
// Inner hash: SHA256((K' ^ ipad) || message)
// First block: K' ^ ipad (64 bytes)
var inner_block: array<u32, 16>;
for (var i = 0u; i < 16u; i++) {
inner_block[i] = k_pad[i] ^ 0x36363636u;
}
// Initialize hash state with first block
var h: array<u32, 8> = sha256_block(&inner_block);
// Process ciphertext blocks (continuing from h state)
let ciphertext_words = params.ciphertext_words;
var word_idx = 0u;
// Process full 64-byte blocks of ciphertext
while (word_idx + 16u <= ciphertext_words) {
var block: array<u32, 16>;
for (var i = 0u; i < 16u; i++) {
block[i] = ciphertext[word_idx + i];
}
h = sha256_block_continue(&block, h);
word_idx = word_idx + 16u;
}
// Final block with remaining ciphertext + padding
var final_block: array<u32, 16>;
var remaining = ciphertext_words - word_idx;
for (var i = 0u; i < 16u; i++) {
if (i < remaining) {
final_block[i] = ciphertext[word_idx + i];
} else if (i == remaining) {
// Add 0x80 padding
final_block[i] = 0x80000000u;
} else {
final_block[i] = 0u;
}
}
// Add length (64 bytes of ipad + ciphertext length)
let total_bits = 512u + params.ciphertext_len_bits;
if (remaining < 14u) {
final_block[14] = 0u;
final_block[15] = total_bits;
h = sha256_block_continue(&final_block, h);
} else {
// Need extra block for length
h = sha256_block_continue(&final_block, h);
var len_block: array<u32, 16>;
for (var i = 0u; i < 14u; i++) {
len_block[i] = 0u;
}
len_block[14] = 0u;
len_block[15] = total_bits;
h = sha256_block_continue(&len_block, h);
}
let inner_hash = h;
// Outer hash: SHA256((K' ^ opad) || inner_hash)
var outer_block: array<u32, 16>;
for (var i = 0u; i < 16u; i++) {
outer_block[i] = k_pad[i] ^ 0x5c5c5c5cu;
}
h = sha256_block(&outer_block);
// Second block: inner_hash (32 bytes) + padding
var hash_block: array<u32, 16>;
for (var i = 0u; i < 8u; i++) {
hash_block[i] = inner_hash[i];
}
hash_block[8] = 0x80000000u;
for (var i = 9u; i < 14u; i++) {
hash_block[i] = 0u;
}
hash_block[14] = 0u;
hash_block[15] = 512u + 256u; // 64 bytes opad + 32 bytes inner hash
h = sha256_block_continue(&hash_block, h);
// Return first 2 bytes (high 16 bits of first word)
return h[0] & 0xFFFF0000u;
}
// SHA256 block computation continuing from existing state
fn sha256_block_continue(msg: ptr<function, array<u32, 16>>, h_in: array<u32, 8>) -> array<u32, 8> {
var h = h_in;
// Message schedule
var w: array<u32, 64>;
for (var i = 0u; i < 16u; i++) {
w[i] = (*msg)[i];
}
for (var i = 16u; i < 64u; i++) {
w[i] = gamma1(w[i-2u]) + w[i-7u] + gamma0(w[i-15u]) + w[i-16u];
}
// Compression
var a = h[0]; var b = h[1]; var c = h[2]; var d = h[3];
var e = h[4]; var f = h[5]; var g = h[6]; var hh = h[7];
for (var i = 0u; i < 64u; i++) {
let t1 = hh + sigma1(e) + ch(e, f, g) + K[i] + w[i];
let t2 = sigma0(a) + maj(a, b, c);
hh = g; g = f; f = e; e = d + t1;
d = c; c = b; b = a; a = t1 + t2;
}
h[0] = h[0] + a; h[1] = h[1] + b; h[2] = h[2] + c; h[3] = h[3] + d;
h[4] = h[4] + e; h[5] = h[5] + f; h[6] = h[6] + g; h[7] = h[7] + hh;
return h;
}
// Process a single candidate and record match if found
fn process_candidate(name_idx: u32) {
// Generate message for this room name
var msg: array<u32, 16>;
let valid = index_to_room_name(name_idx, params.name_length, &msg);
if (!valid) {
return;
}
// Compute SHA256("#roomname") - this gives us the key
let key_hash = sha256_block(&msg);
// Take first 16 bytes (4 words) as the key
var key: array<u32, 4>;
key[0] = key_hash[0];
key[1] = key_hash[1];
key[2] = key_hash[2];
key[3] = key_hash[3];
// Compute SHA256(key) to get channel hash
let channel_hash = sha256_key(key);
// Check if channel hash matches target
if (channel_hash != params.target_channel_hash) {
return;
}
// Channel hash matches - verify MAC if enabled
if (params.verify_mac == 1u) {
let computed_mac = hmac_sha256_mac(key, params.ciphertext_len_bits);
if (computed_mac != params.target_mac) {
return;
}
}
// Found a match - record the index
let match_idx = atomicAdd(&match_count, 1u);
if (match_idx < 1024u) { // Limit stored matches
match_indices[match_idx] = name_idx;
}
}
// Each thread processes 32 candidates to amortize thread overhead
const CANDIDATES_PER_THREAD: u32 = 32u;
@compute @workgroup_size(256)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let base_idx = global_id.x * CANDIDATES_PER_THREAD;
for (var i = 0u; i < CANDIDATES_PER_THREAD; i++) {
let idx = base_idx + i;
if (idx >= params.batch_size) {
return;
}
let name_idx = params.batch_offset + idx;
process_candidate(name_idx);
}
}
`}async init(){if(!navigator.gpu)return console.warn("WebGPU not supported"),!1;try{const a=await navigator.gpu.requestAdapter();if(!a)return console.warn("No GPU adapter found"),!1;this.device=await a.requestDevice(),this.bindGroupLayout=this.device.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:3,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}}]}),this.paramsBuffer=this.device.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.matchCountBuffer=this.device.createBuffer({size:4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST}),this.matchIndicesBuffer=this.device.createBuffer({size:1024*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC});for(let d=0;d<2;d++)this.matchCountReadBuffers[d]=this.device.createBuffer({size:4,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),this.matchIndicesReadBuffers[d]=this.device.createBuffer({size:1024*4,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST});const o=this.device.createShaderModule({code:this.shaderCode}),l=this.device.createPipelineLayout({bindGroupLayouts:[this.bindGroupLayout]});return this.pipeline=this.device.createComputePipeline({layout:l,compute:{module:o,entryPoint:"main"}}),!0}catch(a){return console.error("WebGPU initialization failed:",a),!1}}isAvailable(){return this.device!==null&&this.pipeline!==null}indexToRoomName(a,o){return Zo(o,a)}countNamesForLength(a){return rl(a)}async runBatch(a,o,l,d,f,m){if(!this.device||!this.pipeline||!this.bindGroupLayout||!this.paramsBuffer||!this.matchCountBuffer||!this.matchIndicesBuffer||!this.matchCountReadBuffers[0]||!this.matchCountReadBuffers[1]||!this.matchIndicesReadBuffers[0]||!this.matchIndicesReadBuffers[1])throw new Error("GPU not initialized");const h=this.currentReadBufferIndex;this.currentReadBufferIndex=1-this.currentReadBufferIndex;const x=this.matchCountReadBuffers[h],p=this.matchIndicesReadBuffers[h],y=f&&m?1:0;let v,w=0,k=0;if(y){const M=new Uint8Array(f.length/2);for(let Z=0;Z<M.length;Z++)M[Z]=parseInt(f.substr(Z*2,2),16);w=M.length*8;const z=Math.ceil(M.length/4)*4,j=new Uint8Array(z);j.set(M),v=new Uint32Array(z/4);for(let Z=0;Z<v.length;Z++)v[Z]=j[Z*4]<<24|j[Z*4+1]<<16|j[Z*4+2]<<8|j[Z*4+3];const H=parseInt(m.substr(0,2),16),te=parseInt(m.substr(2,2),16);k=H<<24|te<<16}else v=new Uint32Array([0]);const T=Math.max(v.length*4,4);(!this.ciphertextBuffer||this.ciphertextBufferSize<T)&&(this.ciphertextBuffer&&this.ciphertextBuffer.destroy(),this.ciphertextBuffer=this.device.createBuffer({size:T,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),this.ciphertextBufferSize=T,this.bindGroupDirty=!0);const C=new Uint32Array([a,l,o,d,k,v.length,w,y]);this.device.queue.writeBuffer(this.paramsBuffer,0,C),this.device.queue.writeBuffer(this.ciphertextBuffer,0,v),this.device.queue.writeBuffer(this.matchCountBuffer,0,$c.ZERO_DATA),(this.bindGroupDirty||!this.bindGroup)&&(this.bindGroup=this.device.createBindGroup({layout:this.bindGroupLayout,entries:[{binding:0,resource:{buffer:this.paramsBuffer}},{binding:1,resource:{buffer:this.matchCountBuffer}},{binding:2,resource:{buffer:this.matchIndicesBuffer}},{binding:3,resource:{buffer:this.ciphertextBuffer}}]}),this.bindGroupDirty=!1);const E=this.device.createCommandEncoder(),D=E.beginComputePass();D.setPipeline(this.pipeline),D.setBindGroup(0,this.bindGroup),D.dispatchWorkgroups(Math.ceil(d/(256*32))),D.end(),E.copyBufferToBuffer(this.matchCountBuffer,0,x,0,4),E.copyBufferToBuffer(this.matchIndicesBuffer,0,p,0,1024*4),this.device.queue.submit([E.finish()]),await x.mapAsync(GPUMapMode.READ);const S=new Uint32Array(x.getMappedRange())[0];x.unmap();const N=[];if(S>0){await p.mapAsync(GPUMapMode.READ);const M=new Uint32Array(p.getMappedRange());for(let z=0;z<Math.min(S,1024);z++)N.push(M[z]);p.unmap()}return N}destroy(){var a,o,l,d,f,m,h,x;(a=this.paramsBuffer)==null||a.destroy(),(o=this.matchCountBuffer)==null||o.destroy(),(l=this.matchIndicesBuffer)==null||l.destroy(),(d=this.ciphertextBuffer)==null||d.destroy(),(f=this.matchCountReadBuffers[0])==null||f.destroy(),(m=this.matchCountReadBuffers[1])==null||m.destroy(),(h=this.matchIndicesReadBuffers[0])==null||h.destroy(),(x=this.matchIndicesReadBuffers[1])==null||x.destroy(),this.paramsBuffer=null,this.matchCountBuffer=null,this.matchIndicesBuffer=null,this.ciphertextBuffer=null,this.ciphertextBufferSize=0,this.matchCountReadBuffers=[null,null],this.matchIndicesReadBuffers=[null,null],this.currentReadBufferIndex=0,this.bindGroup=null,this.bindGroupDirty=!0,this.device&&(this.device.destroy(),this.device=null),this.pipeline=null,this.bindGroupLayout=null}}$c.ZERO_DATA=new Uint32Array([0]);function QC(){return typeof navigator<"u"&&"gpu"in navigator}class _A{runBatch(a,o,l,d,f,m){const h=[],x=a.toString(16).padStart(2,"0 Line truncated
`).map(f=>f.trim().toLowerCase()).filter(f=>f.length>0);this.wordlist=d.filter(wA)}setWordlist(a){this.wordlist=a.map(o=>o.trim().toLowerCase()).filter(wA)}abort(){this.abortFlag=!0}isGpuAvailable(){return QC()}async decodePacket(a){var l;const o=a.trim().replace(/\s+/g,"").replace(/^0x/i,"");if(!o||!/^[0-9a-fA-F]+$/.test(o))return null;try{const f=(l=(await xA.MeshCorePacketDecoder.decodeWithVerification(o,{})).payload)==null?void 0:l.decoded;return!(f!=null&&f.channelHash)||!(f!=null&&f.ciphertext)||!(f!=null&&f.cipherMac)?null:{channelHash:f.channelHash,ciphertext:f.ciphertext,cipherMac:f.cipherMac,isGroupText:!0}}catch{return null}}async crack(a,o,l){this.abortFlag=!1,this.useTimestampFilter=(o==null?void 0:o.useTimestampFilter)??!0,this.useUtf8Filter=(o==null?void 0:o.useUtf8Filter)??!0,this.useSenderFilter=(o==null?void 0:o.useSenderFilter)??!0,this.validSeconds=(o==null?void 0:o.validSeconds)??n0,this.useCpu=(o==null?void 0:o.forceCpu)??!1;const d=(o==null?void 0:o.maxLength)??8,f=(o==null?void 0:o.startingLength)??1,m=(o==null?void 0:o.useDictionary)??!0,h=(o==null?void 0:o.startFromType)??"bruteforce",x=a.toLowerCase(),p=await this.decodePacket(x);if(!p)return{found:!1,error:"Invalid packet or not a GroupText packet"};const{channelHash:y,ciphertext:v,cipherMac:w}=p,k=parseInt(y,16);this.useCpu?this.cpuInstance||(this.cpuInstance=new _A):this.gpuInstance||(this.gpuInstance=new $c,await this.gpuInstance.init()||(this.useCpu=!0,this.cpuInstance=new _A));const T=performance.now();let C=0,E=performance.now(),D=f,P=0,S=0,N=!1;if(o!=null&&o.startFrom){const X=o.startFrom.toLowerCase();if(h==="dictionary"){const ie=this.wordlist.indexOf(X);ie>=0&&(S=ie+1)}else{N=!0;const ie=WC(X);ie&&(D=Math.max(f,ie.length),P=ie.index+1,P>=rl(D)&&(D++,P=0))}}let M=0;m&&!N&&this.wordlist.length>0&&(M+=this.wordlist.length-S);for(let X=D;X<=d;X++)M+=rl(X);M-=P;const z=(X,ie,de)=>{if(!l)return;const pe=(performance.now()-T)/1e3,G=pe>0?Math.round(C/pe):0,J=M-C,W=G>0?J/G:0;l({checked:C,total:M,percent:M>0?Math.min(100,C/M*100):0,rateKeysPerSec:G,etaSeconds:W,elapsedSeconds:pe,currentLength:ie,currentPosition:de,phase:X})},j=X=>{if(!Ix(v,w,X))return{valid:!1};const ie=xA.ChannelCrypto.decryptGroupTextMessage(v,w,X);return!ie.success||!ie.data?{valid:!1}:this.useTimestampFilter&&!qC(ie.data.timestamp,this.validSeconds)?{valid:!1}:this.useUtf8Filter&&!GC(ie.data.message)?{valid:!1}:this.useSenderFilter&&!ie.data.sender?{valid:!1}:{valid:!0,message:ie.data.sender?`${ie.data.sender}: ${ie.data.message}`:ie.data.message}};if(!N&&S===0&&D===f&&P===0){z("public-key",0,t0);const X=i0(kc);if(y===X){const ie=j(kc);if(ie.valid)return{found:!0,roomName:t0,key:kc,decryptedMessage:ie.message}}}if(m&&!N&&this.wordlist.length>0)for(let X=S;X<this.wordlist.length;X++){if(this.abortFlag)return{found:!1,aborted:!0,resumeFrom:this.wordlist[X],resumeType:"dictionary"};const ie=this.wordlist[X],de=r0("#"+ie),ae=i0(de);if(parseInt(ae,16)===k){const G=j(de);if(G.valid)return{found:!0,roomName:ie,key:de,decryptedMessage:G.message,resumeFrom:ie,resumeType:"dictionary"}}C++;const pe=performance.now();pe-E>=200&&(z("wordlist",ie.length,ie),E=pe,await new Promise(G=>setTimeout(G,0)))}const H=this.useCpu?1024:32768,te=(o==null?void 0:o.gpuDispatchMs)??1e3;let Z=H,V=!1;for(let X=D;X<=d;X++){if(this.abortFlag)return{found:!1,aborted:!0,resumeFrom:Zo(X,0)||void 0,resumeType:"bruteforce"};const ie=rl(X);let de=X===D?P:0;for(;de<ie;){if(this.abortFlag)return{found:!1,aborted:!0,resumeFrom:Zo(X,de)||void 0,resumeType:"bruteforce"};const ae=Math.min(Z,ie-de),pe=performance.now();let G;this.useCpu?G=this.cpuInstance.runBatch(k,X,de,ae,v,w):G=await this.gpuInstance.runBatch(k,X,de,ae,v,w);const J=performance.now()-pe;if(C+=ae,!this.useCpu&&!V&&ae>=H&&J>0){const R=te/J,U=Math.round(ae*R),Q=Math.pow(2,Math.round(Math.log2(Math.max(H,U))));Z=Math.max(H,Q),V=!0}for(const R of G){const U=Zo(X,R);if(!U)continue;const Q=r0("#"+U),$=j(Q);if($.valid)return{found:!0,roomName:U,key:Q,decryptedMessage:$.message,resumeFrom:U,resumeType:"bruteforce"}}de+=ae;const W=performance.now();if(W-E>=200){const R=Zo(X,Math.min(de,ie-1))||"";z("bruteforce",X,R),E=W,await new Promise(U=>setTimeout(U,0))}}}return{found:!1,resumeFrom:Zo(d,rl(d)-1)||void 0,resumeType:"bruteforce"}}destroy(){this.gpuInstance&&(this.gpuInstance.destroy(),this.gpuInstance=null),this.cpuInstance&&(this.cpuInstance.destroy(),this.cpuInstance=null)}}var Hf,bA;function JC(){return bA||(bA=1,Hf={webm:"data:video/webm;base64,GkXfowEAAAAAAAAfQoaBAUL3gQFC8oEEQvOBCEKChHdlYm1Ch4EEQoWBAhhTgGcBAAAAAAAVkhFNm3RALE27i1OrhBVJqWZTrIHfTbuMU6uEFlSua1OsggEwTbuMU6uEHFO7a1OsghV17AEAAAAAAACkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmAQAAAAAAAEUq17GDD0JATYCNTGF2ZjU1LjMzLjEwMFdBjUxhdmY1NS4zMy4xMDBzpJBlrrXf3DCDVB8KcgbMpcr+RImIQJBgAAAAAAAWVK5rAQAAAAAAD++uAQAAAAA Line truncated
NoSleep enabled for older iOS devices. This can interrupt
active or long-running network requests from completing successfully.
See https://github.com/richtr/NoSleep.js/issues/15 for more details.
`),this.noSleepTimer=window.setInterval(()=>{document.hidden||(window.location.href=window.location.href.split("#")[0],window.setTimeout(window.stop,0))},15e3),this.enabled=!0,Promise.resolve()):this.noSleepVideo.play().then(h=>(this.enabled=!0,h)).catch(h=>{throw this.enabled=!1,h})}disable(){l()?(this._wakeLock&&this._wakeLock.release(),this._wakeLock=null):o()?this.noSleepTimer&&(console.warn(`
NoSleep now disabled for older iOS devices.
`),window.clearInterval(this.noSleepTimer),this.noSleepTimer=null):this.noSleepVideo.pause(),this.enabled=!1}}return Vf=d,Vf}var tE=eE();const nE=Qs(tE);function rE(r){if(r.length<4)return null;try{const o=parseInt(r.slice(0,2),16)&3;let l=2;if(o===0||o===3){if(r.length<l+8)return null;l+=8}if(r.length<l+2)return null;const d=parseInt(r.slice(l,l+2),16);l+=2;const f=d*2;return r.length<l+f?null:(l+=f,r.slice(l))}catch{return null}}function iE({packets:r,channels:a,onChannelCreate:o,onRunningChange:l,visible:d=!1}){const[f,m]=F.useState(!1),[h,x]=F.useState(6),[p,y]=F.useState(!1),[v,w]=F.useState(!0),[k,T]=F.useState(!1),[C,E]=F.useState(null),[D,P]=F.useState(new Map),[S,N]=F.useState([]),[M,z]=F.useState(!1),[j,H]=F.useState(null),[te,Z]=F.useState(null),[V,ne]=F.useState(0),X=F.useRef(null),ie=F.useRef(null),de=F.useRef(!1),ae=F.useRef(!1),pe=F.useRef(!1),G=F.useRef(new Map),J=F.useRef(!1),W=F.useRef(6),R=F.useRef(!0),U=F.useRef(!1),Q=F.useRef(new Set),$=F.useRef(new Set);F.useEffect(()=>{const Se=new XC;X.current=Se,H(Se.isGpuAvailable());const Ue=new nE;return ie.current=Ue,()=>{Se.destroy(),X.current=null,Ue.disable(),ie.current=null}},[]),F.useEffect(()=>{!d||M||$2(async()=>{const{ENGLISH_WORDLIST:Se}=await import("./wordlist-BtmChKSf.js");return{ENGLISH_WORDLIST:Se}},[]).then(({ENGLISH_WORDLIST:Se})=>{X.current&&(X.current.setWordlist(Se),z(!0))}).catch(Se=>{console.error("Failed to load wordlist:",Se),kt.error("Failed to load wordlist",{description:"Cracking will not be available"})})},[d,M]),F.useEffect(()=>{const Se=()=>{st.getUndecryptedPacketCount().then(({count:lt})=>Z(lt)).catch(()=>Z(null))};Se();const Ue=setInterval(Se,3e4);return()=>clearInterval(Ue)},[]);const he=F.useMemo(()=>new Set(a.map(Se=>Se.key.toUpperCase())),[a]),fe=r.filter(Se=>Se.payload_type==="GROUP_TEXT"&&!Se.decrypted);F.useEffect(()=>{let Se=0;P(Ue=>{const lt=new Map(Ue);let Dt=!1;for(const xt of fe)if(!lt.has(xt.id)){const it=rE(xt.data);if(it&&$.current.has(it)){Se++;continue}it&&$.current.add(it),lt.set(xt.id,{packet:xt,attempts:0,lastAttemptLength:0,status:"pending"}),Dt=!0}return Dt?(G.current=lt,lt):Ue}),Se>0&&ne(Ue=>Ue+Se)},[fe.length]),F.useEffect(()=>{G.current=D},[D]),F.useEffect(()=>{J.current=p},[p]),F.useEffect(()=>{W.current=h},[h]),F.useEffect(()=>{R.current=v},[v]),F.useEffect(()=>{U.current=k},[k]),F.useEffect(()=>{Q.current=new Set(fe.map(Se=>Se.id))},[fe]),F.useEffect(()=>{l==null||l(f)},[f,l]);const ke=Array.from(D.values()).filter(Se=>Se.status==="pending").length,ge=Array.from(D.values()).filter(Se=>Se.status==="cracked").length,Ze=Array.from(D.values()).filter(Se=>Se.status==="failed").length,$e=F.useCallback(async()=>{if(pe.current||!X.current||!de.current)return;const Se=G.current;let Ue=null,lt=null;for(const[Ke,Xe]of Se.entries())if(Xe.status==="pending"){Ue=Xe,lt=Ke;break}if(!Ue&&J.current){const Ke=Array.from(Se.entries()).filter(([,Xe])=>Xe.status==="failed"&&Xe.lastAttemptLength<10);Ke.length>0&&(Ke.sort((Xe,xe)=>Xe[1].lastAttemptLength-xe[1].lastAttemptLength),[lt,Ue]=Ke[0])}if(!Ue||lt===null){de.current&&setTimeout(()=>$e(),1e3);return}if(!Q.current.has(lt)){P(Ke=>{const Xe=new Map(Ke);return Xe.delete(lt),Xe}),de.current&&setTimeout(()=>$e(),10);return}pe.current=!0;const Dt=W.current,xt=Ue.lastAttemptLength>0,it=xt?Ue.lastAttemptLength+1:Dt;try{const Ke=await X.current.crack(Ue.packet.data,{maxLength:it,useSenderFilter:!0,useTimestampFilter:!0,useUtf8Filter:!0,...U.current&&{gpuDispatchMs:1e4},...xt&&{useDictionary:!1,startingLength:it}},Xe=>{E(Xe)});if(ae.current){ae.current=!1,pe.current=!1,E(null);return}if(Ke.found&&Ke.roomName&&Ke.key){P(Te=>{const pt=new Map(Te),Ut=pt.get(lt);return Ut&&pt.set(lt,{...Ut,status:"cracked",attempts:Ut.attempts+1,lastAttemptLength:it}),pt});const Xe={roomName:Ke.roomName,key:Ke.key,packetId:lt,message:Ke.decryptedMessage||"",crackedAt:Date.now()};N(Te=>[...Te,Xe]);const xe=Ke.key.toUpperCase();if(!he.has(xe))try{const Te="#"+Ke.roomName;await o(Te,Ke.key),R.current&&await st.decryptHistoricalPackets({key_type:"channel",channel_name:Te})}catch(Te){console.error("Failed to create channel or decrypt historical:",Te),kt.error("Failed to save cracked channel",{description:Te instanceof Error?Te.message:"Channel discovered but could not be saved"})}}else P(Xe=>{const xe=new Map(Xe),Te=xe.get(lt);return Te&&xe.set(lt,{...Te,status:"failed",attempts:Te.attempts+1,lastAttemptLength:it}),xe})}catch(Ke){console.error("Cracking error:",Ke),P(Xe=>{const xe=new Map(Xe),Te=xe.get(lt);return Te&&xe.set(lt,{...Te,status:"failed",attempts:Te.attempts+1,lastAttemptLength:it}),xe})}pe.current=!1,E(null),de.current&&setTimeout(()=>$e(),100)},[he,o]),wt=()=>{var Se;if(!j){kt.error("WebGPU not available",{description:"Cracking requires Chrome 113+ or Edge 113+ with WebGPU support."});return}m(!0),de.current=!0,ae.current=!1,(Se=ie.current)==null||Se.enable(),$e()},ft=()=>{var Se,Ue;m(!1),de.current=!1,ae.current=!0,(Se=X.current)==null||Se.abort(),(Ue=ie.current)==nu Line truncated
//# sourceMappingURL=index-DRuKVg0T.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"mappings":";;;;;;;;6CASa,IAAIA,EAAE,OAAO,IAAI,eAAe,EAAEC,EAAE,OAAO,IAAI,cAAc,EAAEC,EAAE,OAAO,IAAI,gBAAgB,EAAEC,EAAE,OAAO,IAAI,mBAAmB,EAAEC,EAAE,OAAO,IAAI,gBAAgB,EAAEC,EAAE,OAAO,IAAI,gBAAgB,EAAEC,EAAE,OAAO,IAAI,eAAe,EAAEC,EAAE,OAAO,IAAI,mBAAmB,EAAEC,EAAE,OAAO,IAAI,gBAAgB,EAAEC,EAAE,OAAO,IAAI,YAAY,EAAE,EAAE,OAAO,IAAI,YAAY,EAAEC,EAAE,OAAO,SAAS,SAASC,EAAEC,EAAE,CAAC,OAAUA,IAAP,MAAqB,OAAOA,GAAlB,SAA2B,MAAKA,EAAEF,GAAGE,EAAEF,CAAC,GAAGE,EAAE,YAAY,EAAqB,OAAOA,GAApB,WAAsBA,EAAE,KAAI,CAC1e,IAAIC,EAAE,CAAC,UAAU,UAAU,CAAC,MAAM,EAAE,EAAE,mBAAmB,UAAU,GAAG,oBAAoB,UAAU,GAAG,gBAAgB,UAAU,EAAE,EAAEC,EAAE,OAAO,OAAOC,EAAE,GAAG,SAAS,EAAEH,EAAEI,EAAEC,EAAE,CAAC,KAAK,MAAML,EAAE,KAAK,QAAQI,EAAE,KAAK,KAAKD,EAAE,KAAK,QAAQE,GAAGJ,CAAC,CAAC,EAAE,UAAU,iBAAiB,GACnQ,EAAE,UAAU,SAAS,SAASD,EAAEI,EAAE,CAAC,GAAc,OAAOJ,GAAlB,UAAkC,OAAOA,GAApB,YAA6BA,GAAN,KAAQ,MAAM,MAAM,uHAAuH,EAAE,KAAK,QAAQ,gBAAgB,KAAKA,EAAEI,EAAE,UAAU,CAAC,EAAE,EAAE,UAAU,YAAY,SAASJ,EAAE,CAAC,KAAK,QAAQ,mBAAmB,KAAKA,EAAE,aAAa,CAAC,EAAE,SAASM,GAAG,EAAEA,EAAE,UAAU,EAAE,UAAU,SAASC,EAAEP,EAAEI,EAAEC,EAAE,CAAC,KAAK,MAAML,EAAE,KAAK,QAAQI,EAAE,KAAK,KAAKD,EAAE,KAAK,QAAQE,GAAGJ,CAAC,CAAC,IAAIO,EAAED,EAAE,UAAU,IAAID,EACrfE,EAAE,YAAYD,EAAEL,EAAEM,EAAE,EAAE,SAAS,EAAEA,EAAE,qBAAqB,GAAG,IAAIC,EAAE,MAAM,QAAQC,EAAE,OAAO,UAAU,eAAeC,EAAE,CAAC,QAAQ,IAAI,EAAEC,EAAE,CAAC,IAAI,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,EAAE,EACxK,SAASC,EAAEb,EAAEI,EAAEC,EAAE,CAAC,IAAIS,EAAEC,GAAE,GAAGC,GAAE,KAAKC,GAAE,KAAK,GAASb,GAAN,KAAQ,IAAIU,KAAcV,EAAE,MAAX,SAAiBa,GAAEb,EAAE,KAAcA,EAAE,MAAX,SAAiBY,GAAE,GAAGZ,EAAE,KAAKA,EAAEM,EAAE,KAAKN,EAAEU,CAAC,GAAG,CAACF,EAAE,eAAeE,CAAC,IAAIC,GAAED,CAAC,EAAEV,EAAEU,CAAC,GAAG,IAAII,GAAE,UAAU,OAAO,EAAE,GAAOA,KAAJ,EAAMH,GAAE,SAASV,UAAU,EAAEa,GAAE,CAAC,QAAQC,GAAE,MAAMD,EAAC,EAAEE,GAAE,EAAEA,GAAEF,GAAEE,KAAID,GAAEC,EAAC,EAAE,UAAUA,GAAE,CAAC,EAAEL,GAAE,SAASI,EAAC,CAAC,GAAGnB,GAAGA,EAAE,aAAa,IAAIc,KAAKI,GAAElB,EAAE,aAAakB,GAAWH,GAAED,CAAC,IAAZ,SAAgBC,GAAED,CAAC,EAAEI,GAAEJ,CAAC,GAAG,MAAM,CAAC,SAAS1B,EAAE,KAAKY,EAAE,IAAIgB,GAAE,IAAIC,GAAE,MAAMF,GAAE,OAAOJ,EAAE,OAAO,CAAC,CAC7a,SAASU,GAAErB,EAAEI,EAAE,CAAC,MAAM,CAAC,SAAShB,EAAE,KAAKY,EAAE,KAAK,IAAII,EAAE,IAAIJ,EAAE,IAAI,MAAMA,EAAE,MAAM,OAAOA,EAAE,MAAM,CAAC,CAAC,SAASsB,EAAEtB,EAAE,CAAC,OAAiB,OAAOA,GAAlB,UAA4BA,IAAP,MAAUA,EAAE,WAAWZ,CAAC,CAAC,SAASmC,EAAOvB,EAAE,CAAC,IAAII,EAAE,CAAC,IAAI,KAAK,IAAI,IAAI,EAAE,MAAM,IAAIJ,EAAE,QAAQ,QAAQ,SAASA,EAAE,CAAC,OAAOI,EAAEJ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAIwB,GAAE,OAAO,SAASC,EAAEzB,EAAEI,EAAE,CAAC,OAAiB,OAAOJ,GAAlB,UAA4BA,IAAP,MAAgBA,EAAE,KAAR,KAAYuB,EAAO,GAAGvB,EAAE,GAAG,EAAEI,EAAE,SAAS,EAAE,CAAC,CAC/W,SAASsB,GAAE1B,EAAEI,EAAEC,EAAES,EAAEC,GAAE,CAAC,IAAIC,GAAE,OAAOhB,GAAmBgB,KAAd,aAA6BA,KAAZ,aAAchB,EAAE,MAAK,IAAIiB,GAAE,GAAG,GAAUjB,IAAP,KAASiB,GAAE,OAAQ,QAAOD,GAAC,CAAE,IAAK,SAAS,IAAK,SAASC,GAAE,GAAG,MAAM,IAAK,SAAS,OAAOjB,EAAE,SAAQ,CAAE,KAAKZ,EAAE,KAAKC,EAAE4B,GAAE,EAAE,CAAC,CAAC,GAAGA,GAAE,OAAOA,GAAEjB,EAAEe,GAAEA,GAAEE,EAAC,EAAEjB,EAAOc,IAAL,GAAO,IAAIW,EAAER,GAAE,CAAC,EAAEH,EAAEL,EAAEM,EAAC,GAAGV,EAAE,GAASL,GAAN,OAAUK,EAAEL,EAAE,QAAQwB,GAAE,KAAK,EAAE,KAAKE,GAAEX,GAAEX,EAAEC,EAAE,GAAG,SAASL,GAAE,CAAC,OAAOA,EAAC,CAAC,GAASe,IAAN,OAAUO,EAAEP,EAAC,IAAIA,GAAEM,GAAEN,GAAEV,GAAG,CAACU,GAAE,KAAKE,IAAGA,GAAE,MAAMF,GAAE,IAAI,IAAI,GAAGA,GAAE,KAAK,QAAQS,GAAE,KAAK,EAAE,KAAKxB,CAAC,GAAGI,EAAE,KAAKW,EAAC,GAAG,EAAyB,GAAvBE,GAAE,EAAEH,EAAOA,IAAL,GAAO,IAAIA,EAAE,IAAOL,EAAET,CAAC,EAAE,QAAQkB,GAAE,EAAEA,GAAElB,EAAE,OAAOkB,KAAI,CAACF,GACrfhB,EAAEkB,EAAC,EAAE,IAAIC,GAAEL,EAAEW,EAAET,GAAEE,EAAC,EAAED,IAAGS,GAAEV,GAAEZ,EAAEC,EAAEc,GAAEJ,EAAC,CAAC,SAASI,GAAEpB,EAAEC,CAAC,EAAe,OAAOmB,IAApB,WAAsB,IAAInB,EAAEmB,GAAE,KAAKnB,CAAC,EAAEkB,GAAE,EAAE,EAAEF,GAAEhB,EAAE,KAAI,GAAI,MAAMgB,GAAEA,GAAE,MAAMG,GAAEL,EAAEW,EAAET,GAAEE,IAAG,EAAED,IAAGS,GAAEV,GAAEZ,EAAEC,EAAEc,GAAEJ,EAAC,UAAqBC,KAAX,SAAa,MAAMZ,EAAE,OAAOJ,CAAC,EAAE,MAAM,mDAAuEI,IAApB,kBAAsB,qBAAqB,OAAO,KAAKJ,CAAC,EAAE,KAAK,IAAI,EAAE,IAAII,GAAG,2EAA2E,EAAE,OAAOa,EAAC,CACzZ,SAASU,GAAE3B,EAAEI,EAAEC,EAAE,CAAC,GAASL,GAAN,KAAQ,OAAOA,EAAE,IAAIc,EAAE,GAAGC,GAAE,EAAE,OAAAW,GAAE1B,EAAEc,EAAE,GAAG,GAAG,SAASd,GAAE,CAAC,OAAOI,EAAE,KAAKC,EAAEL,GAAEe,IAAG,CAAC,CAAC,EAASD,CAAC,CAAC,SAASc,GAAE5B,EAAE,CAAC,GAAQA,EAAE,UAAP,GAAe,CAAC,IAAII,EAAEJ,EAAE,QAAQI,EAAEA,EAAC,EAAGA,EAAE,KAAK,SAASA,EAAE,EAAQJ,EAAE,UAAN,GAAoBA,EAAE,UAAP,MAAeA,EAAE,QAAQ,EAAEA,EAAE,QAAQI,EAAC,EAAE,SAASA,EAAE,EAAQJ,EAAE,UAAN,GAAoBA,EAAE,UAAP,MAAeA,EAAE,QAAQ,EAAEA,EAAE,QAAQI,EAAC,CAAC,EAAOJ,EAAE,UAAP,KAAiBA,EAAE,QAAQ,EAAEA,EAAE,QAAQI,EAAE,CAAC,GAAOJ,EAAE,UAAN,EAAc,OAAOA,EAAE,QAAQ,QAAQ,MAAMA,EAAE,OAAQ,CAC5Z,IAAI6B,GAAE,CAAC,QAAQ,IAAI,EAAEC,EAAE,CAAC,WAAW,IAAI,EAAEC,EAAE,CAAC,uBAAuBF,GAAE,wBAAwBC,EAAE,kBAAkBnB,CAAC,EAAE,SAASqB,GAAG,CAAC,MAAM,MAAM,0DAA0D,CAAE,CACzM,OAAAC,GAAA,SAAiB,CAAC,IAAIN,GAAE,QAAQ,SAAS3B,EAAEI,EAAEC,EAAE,CAACsB,GAAE3B,EAAE,UAAU,CAACI,EAAE,MAAM,KAAK,SAAS,CAAC,EAAEC,CAAC,CAAC,EAAE,MAAM,SAASL,EAAE,CAAC,IAAII,EAAE,EAAE,OAAAuB,GAAE3B,EAAE,UAAU,CAACI,GAAG,CAAC,EAASA,CAAC,EAAE,QAAQ,SAASJ,EAAE,CAAC,OAAO2B,GAAE3B,EAAE,SAASA,EAAE,CAAC,OAAOA,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,SAASA,EAAE,CAAC,GAAG,CAACsB,EAAEtB,CAAC,EAAE,MAAM,MAAM,Line truncated
+542
View File
@@ -0,0 +1,542 @@
var Pv=Object.defineProperty;var Tv=(r,a,o)=>a in r?Pv(r,a,{enumerable:!0,configurable:!0,writable:!0,value:o}):r[a]=o;var Oo=(r,a,o)=>Tv(r,typeof a!="symbol"?a+"":a,o);function Dv(r,a){for(var o=0;o<a.length;o++){const l=a[o];if(typeof l!="string"&&!Array.isArray(l)){for(const d in l)if(d!=="default"&&!(d in r)){const f=Object.getOwnPropertyDescriptor(l,d);f&&Object.defineProperty(r,d,f.get?f:{enumerable:!0,get:()=>l[d]})}}}return Object.freeze(Object.defineProperty(r,Symbol.toStringTag,{value:"Module"}))}(function(){const a=document.createElement("link").relList;if(a&&a.supports&&a.supports("modulepreload"))return;for(const d of document.querySelectorAll('link[rel="modulepreload"]'))l(d);new MutationObserver(d=>{for(const f of d)if(f.type==="childList")for(const m of f.addedNodes)m.tagName==="LINK"&&m.rel==="modulepreload"&&l(m)}).observe(document,{childList:!0,subtree:!0});function o(d){const f={};return d.integrity&&(f.integrity=d.integrity),d.referrerPolicy&&(f.referrerPolicy=d.referrerPolicy),d.crossOrigin==="use-credentials"?f.credentials="include":d.crossOrigin==="anonymous"?f.credentials="omit":f.credentials="same-origin",f}function l(d){if(d.ep)return;d.ep=!0;const f=o(d);fetch(d.href,f)}})();var Tf=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function $s(r){return r&&r.__esModule&&Object.prototype.hasOwnProperty.call(r,"default")?r.default:r}function NA(r){if(Object.prototype.hasOwnProperty.call(r,"__esModule"))return r;var a=r.default;if(typeof a=="function"){var o=function l(){return this instanceof l?Reflect.construct(a,arguments,this.constructor):a.apply(this,arguments)};o.prototype=a.prototype}else o={};return Object.defineProperty(o,"__esModule",{value:!0}),Object.keys(r).forEach(function(l){var d=Object.getOwnPropertyDescriptor(r,l);Object.defineProperty(o,l,d.get?d:{enumerable:!0,get:function(){return r[l]}})}),o}var Df={exports:{}},Ua={},Rf={exports:{}},ut={};/**
* @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 Ep;function Rv(){if(Ep)return ut;Ep=1;var r=Symbol.for("react.element"),a=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),l=Symbol.for("react.strict_mode"),d=Symbol.for("react.profiler"),f=Symbol.for("react.provider"),m=Symbol.for("react.context"),h=Symbol.for("react.forward_ref"),x=Symbol.for("react.suspense"),p=Symbol.for("react.memo"),v=Symbol.for("react.lazy"),y=Symbol.iterator;function w(R){return R===null||typeof R!="object"?null:(R=y&&R[y]||R["@@iterator"],typeof R=="function"?R:null)}var B={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},D=Object.assign,C={};function k(R,U,Q){this.props=R,this.context=U,this.refs=C,this.updater=Q||B}k.prototype.isReactComponent={},k.prototype.setState=function(R,U){if(typeof R!="object"&&typeof R!="function"&&R!=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,R,U,"setState")},k.prototype.forceUpdate=function(R){this.updater.enqueueForceUpdate(this,R,"forceUpdate")};function P(){}P.prototype=k.prototype;function T(R,U,Q){this.props=R,this.context=U,this.refs=C,this.updater=Q||B}var S=T.prototype=new P;S.constructor=T,D(S,k.prototype),S.isPureReactComponent=!0;var N=Array.isArray,I=Object.prototype.hasOwnProperty,j={current:null},H={key:!0,ref:!0,__self:!0,__source:!0};function z(R,U,Q){var $,de={},fe=null,ke=null;if(U!=null)for($ in U.ref!==void 0&&(ke=U.ref),U.key!==void 0&&(fe=""+U.key),U)I.call(U,$)&&!H.hasOwnProperty($)&&(de[$]=U[$]);var ge=arguments.length-2;if(ge===1)de.children=Q;else if(1<ge){for(var Ze=Array(ge),$e=0;$e<ge;$e++)Ze[$e]=arguments[$e+2];de.children=Ze}if(R&&R.defaultProps)for($ in ge=R.defaultProps,ge)de[$]===void 0&&(de[$]=ge[$]);return{$$typeof:r,type:R,key:fe,ref:ke,props:de,_owner:j.current}}function ee(R,U){return{$$typeof:r,type:R.type,key:U,ref:R.ref,props:R.props,_owner:R._owner}}function Z(R){return typeof R=="object"&&R!==null&&R.$$typeof===r}function V(R){var U={"=":"=0",":":"=2"};return"$"+R.replace(/[=:]/g,function(Q){return U[Q]})}var ne=/\/+/g;function J(R,U){return typeof R=="object"&&R!==null&&R.key!=null?V(""+R.key):U.toString(36)}function re(R,U,Q,$,de){var fe=typeof R;(fe==="undefined"||fe==="boolean")&&(R=null);var ke=!1;if(R===null)ke=!0;else switch(fe){case"string":case"number":ke=!0;break;case"object":switch(R.$$typeof){case r:case a:ke=!0}}if(ke)return ke=R,de=de(ke),R=$===""?"."+J(ke,0):$,N(de)?(Q="",R!=null&&(Q=R.replace(ne,"$&/")+"/"),re(de,U,Q,"",function($e){return $e})):de!=null&&(Z(de)&&(de=ee(de,Q+(!de.key||ke&&ke.key===de.key?"":(""+de.key).replace(ne,"$&/")+"/")+R)),U.push(de)),1;if(ke=0,$=$===""?".":$+":",N(R))for(var ge=0;ge<R.length;ge++){fe=R[ge];var Ze=$+J(fe,ge);ke+=re(fe,U,Q,Ze,de)}else if(Ze=w(R),typeof Ze=="function")for(R=Ze.call(R),ge=0;!(fe=R.next()).done;)fe=fe.value,Ze=$+J(fe,ge++),ke+=re(fe,U,Q,Ze,de);else if(fe==="object")throw U=String(R),Error("Objects are not valid as a React child (found: "+(U==="[object Object]"?"object with keys {"+Object.keys(R).join(", ")+"}":U)+"). If you meant to render a collection of children, use an array instead.");return ke}function he(R,U,Q){if(R==null)return R;var $=[],de=0;return re(R,$,"","",function(fe){return U.call(Q,fe,de++)}),$}function ae(R){if(R._status===-1){var U=R._result;U=U(),U.then(function(Q){(R._status===0||R._status===-1)&&(R._status=1,R._result=Q)},function(Q){(R._status===0||R._status===-1)&&(R._status=2,R._result=Q)}),R._status===-1&&(R._status=0,R._result=U)}if(R._status===1)return R._result.default;throw R._result}var pe={current:null},G={transition:null},Y={ReactCurrentDispatcher:pe,ReactCurrentBatchConfig:G,ReactCurrentOwner:j};function q(){throw Error("act(...) is not supported in production builds of React.")}return ut.Children={map:he,forEach:function(R,U,Q){he(R,function(){U.apply(this,arguments)},Q)},count:function(R){var U=0;return he(R,function(){U++}),U},toArray:function(R){return he(R,function(U){return U})||[]},only:function(R){if(!Z(R))throw Error("React.Children.only expected to receive a single React element child.");return R}},ut.Component=k,ut.Fragment=o,ut.Profiler=d,ut.PureComponent=T,ut.StrictMode=l,ut.Suspense=x,ut.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=Y,ut.act=q,ut.cloneElement=function(R,U,Q){if(R==null)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+R+".");var $=D({},R.props),de=R.key,fe=R.ref,ke=R._owner;if(U!=null){if(U.ref!==void 0&&(fe=U.ref,ke=j.current),U.key!==void 0&&(de=""+U.key),R.type&&R.type.defaultProps)var ge=R.type.defaultProps;for(Ze in U)I.call(U,Ze)&&!H.hasOwnProperty(Ze)&&($[Ze]=U[Ze]===void 0&&ge!==void 0?ge[Ze]:U[Ze])}var Ze=arguments.length-2;if(Ze===1)$.children=Q;else if(1<Ze){ge=Array(Ze);for(var $e=0;$e<Ze;$e++)ge[$e]=arguments[$e+2];$.children=ge}return{$$typeof:r,type:R.type,key:de,ref:fe,props:$,_owner:ke}},ut.creLine truncated
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var Sp;function Fv(){if(Sp)return Ua;Sp=1;var r=m0(),a=Symbol.for("react.element"),o=Symbol.for("react.fragment"),l=Object.prototype.hasOwnProperty,d=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,f={key:!0,ref:!0,__self:!0,__source:!0};function m(h,x,p){var v,y={},w=null,B=null;p!==void 0&&(w=""+p),x.key!==void 0&&(w=""+x.key),x.ref!==void 0&&(B=x.ref);for(v in x)l.call(x,v)&&!f.hasOwnProperty(v)&&(y[v]=x[v]);if(h&&h.defaultProps)for(v in x=h.defaultProps,x)y[v]===void 0&&(y[v]=x[v]);return{$$typeof:a,type:h,key:w,ref:B,props:y,_owner:d.current}}return Ua.Fragment=o,Ua.jsx=m,Ua.jsxs=m,Ua}var Bp;function Nv(){return Bp||(Bp=1,Df.exports=Fv()),Df.exports}var E=Nv(),F=m0();const Ce=$s(F),A0=Dv({__proto__:null,default:Ce},[F]);var Bu={},Ff={exports:{}},Zn={},Nf={exports:{}},Lf={};/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var Pp;function Lv(){return Pp||(Pp=1,(function(r){function a(G,Y){var q=G.length;G.push(Y);e:for(;0<q;){var R=q-1>>>1,U=G[R];if(0<d(U,Y))G[R]=Y,G[q]=U,q=R;else break e}}function o(G){return G.length===0?null:G[0]}function l(G){if(G.length===0)return null;var Y=G[0],q=G.pop();if(q!==Y){G[0]=q;e:for(var R=0,U=G.length,Q=U>>>1;R<Q;){var $=2*(R+1)-1,de=G[$],fe=$+1,ke=G[fe];if(0>d(de,q))fe<U&&0>d(ke,de)?(G[R]=ke,G[fe]=q,R=fe):(G[R]=de,G[$]=q,R=$);else if(fe<U&&0>d(ke,q))G[R]=ke,G[fe]=q,R=fe;else break e}}return Y}function d(G,Y){var q=G.sortIndex-Y.sortIndex;return q!==0?q:G.id-Y.id}if(typeof performance=="object"&&typeof performance.now=="function"){var f=performance;r.unstable_now=function(){return f.now()}}else{var m=Date,h=m.now();r.unstable_now=function(){return m.now()-h}}var x=[],p=[],v=1,y=null,w=3,B=!1,D=!1,C=!1,k=typeof setTimeout=="function"?setTimeout:null,P=typeof clearTimeout=="function"?clearTimeout:null,T=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function S(G){for(var Y=o(p);Y!==null;){if(Y.callback===null)l(p);else if(Y.startTime<=G)l(p),Y.sortIndex=Y.expirationTime,a(x,Y);else break;Y=o(p)}}function N(G){if(C=!1,S(G),!D)if(o(x)!==null)D=!0,ae(I);else{var Y=o(p);Y!==null&&pe(N,Y.startTime-G)}}function I(G,Y){D=!1,C&&(C=!1,P(z),z=-1),B=!0;var q=w;try{for(S(Y),y=o(x);y!==null&&(!(y.expirationTime>Y)||G&&!V());){var R=y.callback;if(typeof R=="function"){y.callback=null,w=y.priorityLevel;var U=R(y.expirationTime<=Y);Y=r.unstable_now(),typeof U=="function"?y.callback=U:y===o(x)&&l(x),S(Y)}else l(x);y=o(x)}if(y!==null)var Q=!0;else{var $=o(p);$!==null&&pe(N,$.startTime-Y),Q=!1}return Q}finally{y=null,w=q,B=!1}}var j=!1,H=null,z=-1,ee=5,Z=-1;function V(){return!(r.unstable_now()-Z<ee)}function ne(){if(H!==null){var G=r.unstable_now();Z=G;var Y=!0;try{Y=H(!0,G)}finally{Y?J():(j=!1,H=null)}}else j=!1}var J;if(typeof T=="function")J=function(){T(ne)};else if(typeof MessageChannel<"u"){var re=new MessageChannel,he=re.port2;re.port1.onmessage=ne,J=function(){he.postMessage(null)}}else J=function(){k(ne,0)};function ae(G){H=G,j||(j=!0,J())}function pe(G,Y){z=k(function(){G(r.unstable_now())},Y)}r.unstable_IdlePriority=5,r.unstable_ImmediatePriority=1,r.unstable_LowPriority=4,r.unstable_NormalPriority=3,r.unstable_Profiling=null,r.unstable_UserBlockingPriority=2,r.unstable_cancelCallback=function(G){G.callback=null},r.unstable_continueExecution=function(){D||B||(D=!0,ae(I))},r.unstable_forceFrameRate=function(G){0>G||125<G?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):ee=0<G?Math.floor(1e3/G):5},r.unstable_getCurrentPriorityLevel=function(){return w},r.unstable_getFirstCallbackNode=function(){return o(x)},r.unstable_next=function(G){switch(w){case 1:case 2:case 3:var Y=3;break;default:Y=w}var q=w;w=Y;try{return G()}finally{w=q}},r.unstable_pauseExecution=function(){},r.unstable_requestPaint=function(){},r.unstable_runWithPriority=function(G,Y){switch(G){case 1:case 2:case 3:case 4:case 5:break;default:G=3}var q=w;w=G;try{return Y()}finally{w=q}},r.unstable_scheduleCallback=function(G,Y,q){var R=r.unstable_now();switch(typeof q=="object"&&q!==null?(q=q.delay,q=typeof q=="number"&&0<q?R+q:R):q=R,G){case 1:var U=-1;break;case 2:U=250;break;case 5:U=1073741823;break;case 4:U=1e4;break;default:U=5e3}return U=q+U,G={id:v++,callback:Y,priorityLevel:G,startTime:q,expirationTime:U,sortIndex:-1},q>R?(G.sortIndex=q,a(p,G),o(x)===null&&G===o(p)&&(C?(P(z),z=-1):C=!0,pe(N,q-R))):(G.sortIndex=U,a(x,G),D||B||(D=!0,ae(I))),G},r.unstable_shouldYield=V,r.unstable_wrapCallback=function(G){var Y=w;return function(){var q=w;w=Y;try{return G.apply(this,arguments)}finally{w=q}}}})(Lf)),Lf}var Tp;function Mv(){return Tp||(Tp=1,Nf.exports=Lv()),Nf.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 Dp;function Iv(){if(Dp)return Zn;Dp=1;var r=m0(),a=Mv();function o(e){for(var n="https://reactjs.org/docs/error-decoder.html?invariant="+e,s=1;s<arguments.length;s++)n+="&args[]="+encodeURIComponent(arguments[s]);return"Minified React error #"+e+"; visit "+n+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var l=new Set,d={};function f(e,n){m(e,n),m(e+"Capture",n)}function m(e,n){for(d[e]=n,e=0;e<n.length;e++)l.add(n[e])}var h=!(typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),x=Object.prototype.hasOwnProperty,p=/^[: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]*$/,v={},y={};function w(e){return x.call(y,e)?!0:x.call(v,e)?!1:p.test(e)?y[e]=!0:(v[e]=!0,!1)}function B(e,n,s,c){if(s!==null&&s.type===0)return!1;switch(typeof n){case"function":case"symbol":return!0;case"boolean":return c?!1:s!==null?!s.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function D(e,n,s,c){if(n===null||typeof n>"u"||B(e,n,s,c))return!0;if(c)return!1;if(s!==null)switch(s.type){case 3:return!n;case 4:return n===!1;case 5:return isNaN(n);case 6:return isNaN(n)||1>n}return!1}function C(e,n,s,c,g,_,M){this.acceptsBooleans=n===2||n===3||n===4,this.attributeName=c,this.attributeNamespace=g,this.mustUseProperty=s,this.propertyName=e,this.type=n,this.sanitizeURL=_,this.removeEmptyString=M}var k={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){k[e]=new C(e,0,!1,e,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var n=e[0];k[n]=new C(n,1,!1,e[1],null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){k[e]=new C(e,2,!1,e.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){k[e]=new C(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){k[e]=new C(e,3,!1,e.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(e){k[e]=new C(e,3,!0,e,null,!1,!1)}),["capture","download"].forEach(function(e){k[e]=new C(e,4,!1,e,null,!1,!1)}),["cols","rows","size","span"].forEach(function(e){k[e]=new C(e,6,!1,e,null,!1,!1)}),["rowSpan","start"].forEach(function(e){k[e]=new C(e,5,!1,e.toLowerCase(),null,!1,!1)});var P=/[\-:]([a-z])/g;function T(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 n=e.replace(P,T);k[n]=new C(n,1,!1,e,null,!1,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var n=e.replace(P,T);k[n]=new C(n,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(e){var n=e.replace(P,T);k[n]=new C(n,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(e){k[e]=new C(e,1,!1,e.toLowerCase(),null,!1,!1)}),k.xlinkHref=new C("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(e){k[e]=new C(e,1,!1,e.toLowerCase(),null,!0,!0)});function S(e,n,s,c){var g=k.hasOwnProperty(n)?k[n]:null;(g!==null?g.type!==0:c||!(2<n.length)||n[0]!=="o"&&n[0]!=="O"||n[1]!=="n"&&n[1]!= Line truncated
`+R+e}var Q=!1;function $(e,n){if(!e||Q)return"";Q=!0;var s=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(n)if(n=function(){throw Error()},Object.defineProperty(n.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(n,[])}catch(ce){var c=ce}Reflect.construct(e,[],n)}else{try{n.call()}catch(ce){c=ce}e.call(n.prototype)}else{try{throw Error()}catch(ce){c=ce}e()}}catch(ce){if(ce&&c&&typeof ce.stack=="string"){for(var g=ce.stack.split(`
`),_=c.stack.split(`
`),M=g.length-1,W=_.length-1;1<=M&&0<=W&&g[M]!==_[W];)W--;for(;1<=M&&0<=W;M--,W--)if(g[M]!==_[W]){if(M!==1||W!==1)do if(M--,W--,0>W||g[M]!==_[W]){var X=`
`+g[M].replace(" at new "," at ");return e.displayName&&X.includes("<anonymous>")&&(X=X.replace("<anonymous>",e.displayName)),X}while(1<=M&&0<=W);break}}}finally{Q=!1,Error.prepareStackTrace=s}return(e=e?e.displayName||e.name:"")?U(e):""}function de(e){switch(e.tag){case 5:return U(e.type);case 16:return U("Lazy");case 13:return U("Suspense");case 19:return U("SuspenseList");case 0:case 2:case 15:return e=$(e.type,!1),e;case 11:return e=$(e.type.render,!1),e;case 1:return e=$(e.type,!0),e;default:return""}}function fe(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 H:return"Fragment";case j:return"Portal";case ee:return"Profiler";case z:return"StrictMode";case J:return"Suspense";case re:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case V:return(e.displayName||"Context")+".Consumer";case Z:return(e._context.displayName||"Context")+".Provider";case ne:var n=e.render;return e=e.displayName,e||(e=n.displayName||n.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case he:return n=e.displayName||null,n!==null?n:fe(e.type)||"Memo";case ae:n=e._payload,e=e._init;try{return fe(e(n))}catch{}}return null}function ke(e){var n=e.type;switch(e.tag){case 24:return"Cache";case 9:return(n.displayName||"Context")+".Consumer";case 10:return(n._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=n.render,e=e.displayName||e.name||"",n.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return n;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return fe(n);case 8:return n===z?"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 n=="function")return n.displayName||n.name||null;if(typeof n=="string")return n}return null}function ge(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Ze(e){var n=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(n==="checkbox"||n==="radio")}function $e(e){var n=Ze(e)?"checked":"value",s=Object.getOwnPropertyDescriptor(e.constructor.prototype,n),c=""+e[n];if(!e.hasOwnProperty(n)&&typeof s<"u"&&typeof s.get=="function"&&typeof s.set=="function"){var g=s.get,_=s.set;return Object.defineProperty(e,n,{configurable:!0,get:function(){return g.call(this)},set:function(M){c=""+M,_.call(this,M)}}),Object.defineProperty(e,n,{enumerable:s.enumerable}),{getValue:function(){return c},setValue:function(M){c=""+M},stopTracking:function(){e._valueTracker=null,delete e[n]}}}}function wt(e){e._valueTracker||(e._valueTracker=$e(e))}function ft(e){if(!e)return!1;var n=e._valueTracker;if(!n)return!0;var s=n.getValue(),c="";return e&&(c=Ze(e)?e.checked?"true":"false":e.value),e=c,e!==s?(n.setValue(e),!0):!1}function Se(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 Ue(e,n){var s=n.checked;return q({},n,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:s??e._wrapperState.initialChecked})}function lt(e,n){var s=n.defaultValue==null?"":n.defaultValue,c=n.checked!=null?n.checked:n.defaultChecked;s=ge(n.value!=null?n.value:s),e._wrapperState={initialChecked:c,initialValue:s,controlled:n.type==="checkbox"||n.type==="radio"?n.checked!=null:n.value!=null}}function Dt(e,n){n=n.checked,n!=null&&S(e,"checked",n,!1)}function xt(e,n){Dt(e,n);var s=ge(n.value),c=n.type;if(s!=null)c==="number"?(s===0&&e.value===""||e.value!=s)&&(e.value=""+s):e.value!==""+s&&(e.value=""+s);else if(c==="submit"||c==="reset"){e.removeAttribute("value");return}n.hasOwnProperty("value")?Ke(e,n.type,s):n.hasOwnProperty("defaultValue")&&Ke(e,n.type,ge(n.defaultValue)),n.checked==null&&n.defaultChecked!=null&&(e.defaultChecked=!!n.defaultChecked)}function it(e,n,s){if(n.hasOwnProperty("value")||n.hasOwnProperty("defaultValue")){var c=n.type;if(!(c!=="submit"&&c!=="reset"||n.value!==void 0&&n.value!==null))return;n=""+e._wrapperState.initialValue,s||n===e.value||(e.value=n),e.defaultValue=n}s=e.name,s!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,s!==""&&(e.name=s)}function Ke(e,n,s){(n!=="number"||Se(e.ownerDocument)!==e)&&(s==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+s&&(e.defaultValue=""+s))}var Xe=Array.isArray;function xe(e,n,s,c){if(e=e.options,n){n={};for(var g=0;g<s.length;g++)n["$"+s[g]]=!0;for(s=0;s<e.length;s++)g=n.hasOwnProperty("$"+e[s].value),e[s].selected!==g&&(e[s].selected=g),g&&c&&(e[s].defaultSelected=!0)}else{for(s=""+ge(s),n=null,g=0;g<e.length;g++){if(e[g].value===s){e[g].selected=!0,c&&(e[g].defaultSelected=!0);return}n!==null||e[g].disabled||(n=e[g])}n!==null&&(n.selected=!0)}}function Te(e,n){if(n.dangerouslySetInnerHT Line truncated
`).replace(K,"")}function ue(e,n,s){if(n=ie(n),ie(e)!==n&&s)throw Error(o(425))}function ve(){}var Pe=null,qe=null;function nt(e,n){return e==="textarea"||e==="noscript"||typeof n.children=="string"||typeof n.children=="number"||typeof n.dangerouslySetInnerHTML=="object"&&n.dangerouslySetInnerHTML!==null&&n.dangerouslySetInnerHTML.__html!=null}var rn=typeof setTimeout=="function"?setTimeout:void 0,Xt=typeof clearTimeout=="function"?clearTimeout:void 0,Fn=typeof Promise=="function"?Promise:void 0,bn=typeof queueMicrotask=="function"?queueMicrotask:typeof Fn<"u"?function(e){return Fn.resolve(null).then(e).catch(Wi)}:rn;function Wi(e){setTimeout(function(){throw e})}function Ba(e,n){var s=n,c=0;do{var g=s.nextSibling;if(e.removeChild(s),g&&g.nodeType===8)if(s=g.data,s==="/$"){if(c===0){e.removeChild(g),Yn(n);return}c--}else s!=="$"&&s!=="$?"&&s!=="$!"||c++;s=g}while(s);Yn(n)}function Ur(e){for(;e!=null;e=e.nextSibling){var n=e.nodeType;if(n===1||n===3)break;if(n===8){if(n=e.data,n==="$"||n==="$!"||n==="$?")break;if(n==="/$")return null}}return e}function Ul(e){e=e.previousSibling;for(var n=0;e;){if(e.nodeType===8){var s=e.data;if(s==="$"||s==="$!"||s==="$?"){if(n===0)return e;n--}else s==="/$"&&n++}e=e.previousSibling}return null}var ui=Math.random().toString(36).slice(2),fr="__reactFiber$"+ui,qi="__reactProps$"+ui,_t="__reactContainer$"+ui,Gi="__reactEvents$"+ui,Cd="__reactListeners$"+ui,Ed="__reactHandles$"+ui;function ci(e){var n=e[fr];if(n)return n;for(var s=e.parentNode;s;){if(n=s[_t]||s[fr]){if(s=n.alternate,n.child!==null||s!==null&&s.child!==null)for(e=Ul(e);e!==null;){if(s=e[fr])return s;e=Ul(e)}return n}e=s,s=e.parentNode}return null}function di(e){return e=e[fr]||e[_t],!e||e.tag!==5&&e.tag!==6&&e.tag!==13&&e.tag!==3?null:e}function fi(e){if(e.tag===5||e.tag===6)return e.stateNode;throw Error(o(33))}function ws(e){return e[qi]||null}var kd=[],bs=-1;function Qi(e){return{current:e}}function Ft(e){0>bs||(e.current=kd[bs],kd[bs]=null,bs--)}function Tt(e,n){bs++,kd[bs]=e.current,e.current=n}var Ki={},Cn=Qi(Ki),zn=Qi(!1),So=Ki;function Cs(e,n){var s=e.type.contextTypes;if(!s)return Ki;var c=e.stateNode;if(c&&c.__reactInternalMemoizedUnmaskedChildContext===n)return c.__reactInternalMemoizedMaskedChildContext;var g={},_;for(_ in s)g[_]=n[_];return c&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=n,e.__reactInternalMemoizedMaskedChildContext=g),g}function jn(e){return e=e.childContextTypes,e!=null}function Zl(){Ft(zn),Ft(Cn)}function G0(e,n,s){if(Cn.current!==Ki)throw Error(o(168));Tt(Cn,n),Tt(zn,s)}function Q0(e,n,s){var c=e.stateNode;if(n=n.childContextTypes,typeof c.getChildContext!="function")return s;c=c.getChildContext();for(var g in c)if(!(g in n))throw Error(o(108,ke(e)||"Unknown",g));return q({},s,c)}function Wl(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Ki,So=Cn.current,Tt(Cn,e),Tt(zn,zn.current),!0}function K0(e,n,s){var c=e.stateNode;if(!c)throw Error(o(169));s?(e=Q0(e,n,So),c.__reactInternalMemoizedMergedChildContext=e,Ft(zn),Ft(Cn),Tt(Cn,e)):Ft(zn),Tt(zn,s)}var hi=null,ql=!1,Sd=!1;function $0(e){hi===null?hi=[e]:hi.push(e)}function Qx(e){ql=!0,$0(e)}function $i(){if(!Sd&&hi!==null){Sd=!0;var e=0,n=ht;try{var s=hi;for(ht=1;e<s.length;e++){var c=s[e];do c=c(!0);while(c!==null)}hi=null,ql=!1}catch(g){throw hi!==null&&(hi=hi.slice(e+1)),vl(ra,$i),g}finally{ht=n,Sd=!1}}return null}var Es=[],ks=0,Gl=null,Ql=0,hr=[],pr=0,Bo=null,pi=1,mi="";function Po(e,n){Es[ks++]=Ql,Es[ks++]=Gl,Gl=e,Ql=n}function Y0(e,n,s){hr[pr++]=pi,hr[pr++]=mi,hr[pr++]=Bo,Bo=e;var c=pi;e=mi;var g=32-tt(c)-1;c&=~(1<<g),s+=1;var _=32-tt(n)+g;if(30<_){var M=g-g%5;_=(c&(1<<M)-1).toString(32),c>>=M,g-=M,pi=1<<32-tt(n)+g|s<<g|c,mi=_+e}else pi=1<<_|s<<g|c,mi=e}function Bd(e){e.return!==null&&(Po(e,1),Y0(e,1,0))}function Pd(e){for(;e===Gl;)Gl=Es[--ks],Es[ks]=null,Ql=Es[--ks],Es[ks]=null;for(;e===Bo;)Bo=hr[--pr],hr[pr]=null,mi=hr[--pr],hr[pr]=null,pi=hr[--pr],hr[pr]=null}var nr=null,rr=null,Mt=!1,kr=null;function X0(e,n){var s=xr(5,null,null,0);s.elementType="DELETED",s.stateNode=n,s.return=e,n=e.deletions,n===null?(e.deletions=[s],e.flags|=16):n.push(s)}function J0(e,n){switch(e.tag){case 5:var s=e.type;return n=n.nodeType!==1||s.toLowerCase()!==n.nodeName.toLowerCase()?null:n,n!==null?(e.stateNode=n,nr=e,rr=Ur(n.firstChild),!0):!1;case 6:return n=e.pendingProps===""||n.nodeType!==3?null:n,n!==null?(e.stateNode=n,nr=e,rr=null,!0):!1;case 13:return n=n.nodeType!==8?null:n,n!==null?(s=Bo!==null?{id:pi,overflow:mi}:null,e.memoizedState={dehydrated:n,treeContext:s,retryLane:1073741824},s=xr(18,null,null,0),s.stateNode=n,s.return=e,e.child=s,nr=e,rr=null,!0):!1;default:return!1}}function Td(e){return(e.mode&1)!==0&&(e.flags&128)===0}function Dd(e){if(Mt){var n=rr;if(n){var s=n;if(!J0(e,n)){if(Td(e))throw Error(o(418));n=Ur(s.nextSibling);var c=nr;n&&J0(e,n)?X0(c,s):(e.flags=e.flags&-4097|2,Mt=!1,nr=e)}}else{if(Td(e))throw Error(o(418));e.flags=e.flags&-4097|2,Mt=!1,nr=e}}}function eh(e){for(e=e.r Line truncated
Error generating stack: `+_.message+`
`+_.stack}return{value:e,source:n,stack:g,digest:null}}function Jd(e,n,s){return{value:e,source:null,stack:s??null,digest:n??null}}function ef(e,n){try{console.error(n.value)}catch(s){setTimeout(function(){throw s})}}var rv=typeof WeakMap=="function"?WeakMap:Map;function Nh(e,n,s){s=gi(-1,s),s.tag=3,s.payload={element:null};var c=n.value;return s.callback=function(){pu||(pu=!0,Af=c),ef(e,n)},s}function Lh(e,n,s){s=gi(-1,s),s.tag=3;var c=e.type.getDerivedStateFromError;if(typeof c=="function"){var g=n.value;s.payload=function(){return c(g)},s.callback=function(){ef(e,n)}}var _=e.stateNode;return _!==null&&typeof _.componentDidCatch=="function"&&(s.callback=function(){ef(e,n),typeof c!="function"&&(eo===null?eo=new Set([this]):eo.add(this));var M=n.stack;this.componentDidCatch(n.value,{componentStack:M!==null?M:""})}),s}function Mh(e,n,s){var c=e.pingCache;if(c===null){c=e.pingCache=new rv;var g=new Set;c.set(n,g)}else g=c.get(n),g===void 0&&(g=new Set,c.set(n,g));g.has(s)||(g.add(s),e=gv.bind(null,e,n,s),n.then(e,e))}function Ih(e){do{var n;if((n=e.tag===13)&&(n=e.memoizedState,n=n!==null?n.dehydrated!==null:!0),n)return e;e=e.return}while(e!==null);return null}function Oh(e,n,s,c,g){return(e.mode&1)===0?(e===n?e.flags|=65536:(e.flags|=128,s.flags|=131072,s.flags&=-52805,s.tag===1&&(s.alternate===null?s.tag=17:(n=gi(-1,1),n.tag=2,Xi(s,n,1))),s.lanes|=1),e):(e.flags|=65536,e.lanes=g,e)}var iv=N.ReactCurrentOwner,Hn=!1;function Nn(e,n,s,c){n.child=e===null?ih(n,null,s,c):Bs(n,e.child,s,c)}function zh(e,n,s,c,g){s=s.render;var _=n.ref;return Ts(n,g),c=Wd(e,n,s,c,_,g),s=qd(),e!==null&&!Hn?(n.updateQueue=e.updateQueue,n.flags&=-2053,e.lanes&=~g,xi(e,n,g)):(Mt&&s&&Bd(n),n.flags|=1,Nn(e,n,c,g),n.child)}function jh(e,n,s,c,g){if(e===null){var _=s.type;return typeof _=="function"&&!bf(_)&&_.defaultProps===void 0&&s.compare===null&&s.defaultProps===void 0?(n.tag=15,n.type=_,Hh(e,n,_,c,g)):(e=yu(s.type,null,c,n,n.mode,g),e.ref=n.ref,e.return=n,n.child=e)}if(_=e.child,(e.lanes&g)===0){var M=_.memoizedProps;if(s=s.compare,s=s!==null?s:jr,s(M,c)&&e.ref===n.ref)return xi(e,n,g)}return n.flags|=1,e=io(_,c),e.ref=n.ref,e.return=n,n.child=e}function Hh(e,n,s,c,g){if(e!==null){var _=e.memoizedProps;if(jr(_,c)&&e.ref===n.ref)if(Hn=!1,n.pendingProps=c=_,(e.lanes&g)!==0)(e.flags&131072)!==0&&(Hn=!0);else return n.lanes=e.lanes,xi(e,n,g)}return tf(e,n,s,c,g)}function Vh(e,n,s){var c=n.pendingProps,g=c.children,_=e!==null?e.memoizedState:null;if(c.mode==="hidden")if((n.mode&1)===0)n.memoizedState={baseLanes:0,cachePool:null,transitions:null},Tt(Ns,ir),ir|=s;else{if((s&1073741824)===0)return e=_!==null?_.baseLanes|s:s,n.lanes=n.childLanes=1073741824,n.memoizedState={baseLanes:e,cachePool:null,transitions:null},n.updateQueue=null,Tt(Ns,ir),ir|=e,null;n.memoizedState={baseLanes:0,cachePool:null,transitions:null},c=_!==null?_.baseLanes:s,Tt(Ns,ir),ir|=c}else _!==null?(c=_.baseLanes|s,n.memoizedState=null):c=s,Tt(Ns,ir),ir|=c;return Nn(e,n,g,s),n.child}function Uh(e,n){var s=n.ref;(e===null&&s!==null||e!==null&&e.ref!==s)&&(n.flags|=512,n.flags|=2097152)}function tf(e,n,s,c,g){var _=jn(s)?So:Cn.current;return _=Cs(n,_),Ts(n,g),s=Wd(e,n,s,c,_,g),c=qd(),e!==null&&!Hn?(n.updateQueue=e.updateQueue,n.flags&=-2053,e.lanes&=~g,xi(e,n,g)):(Mt&&c&&Bd(n),n.flags|=1,Nn(e,n,s,g),n.child)}function Zh(e,n,s,c,g){if(jn(s)){var _=!0;Wl(n)}else _=!1;if(Ts(n,g),n.stateNode===null)uu(e,n),Rh(n,s,c),Xd(n,s,c,g),c=!0;else if(e===null){var M=n.stateNode,W=n.memoizedProps;M.props=W;var X=M.context,ce=s.contextType;typeof ce=="object"&&ce!==null?ce=mr(ce):(ce=jn(s)?So:Cn.current,ce=Cs(n,ce));var _e=s.getDerivedStateFromProps,we=typeof _e=="function"||typeof M.getSnapshotBeforeUpdate=="function";we||typeof M.UNSAFE_componentWillReceiveProps!="function"&&typeof M.componentWillReceiveProps!="function"||(W!==c||X!==ce)&&Fh(n,M,c,ce),Yi=!1;var ye=n.memoizedState;M.state=ye,eu(n,c,M,g),X=n.memoizedState,W!==c||ye!==X||zn.current||Yi?(typeof _e=="function"&&(Yd(n,s,_e,c),X=n.memoizedState),(W=Yi||Dh(n,s,W,c,ye,X,ce))?(we||typeof M.UNSAFE_componentWillMount!="function"&&typeof M.componentWillMount!="function"||(typeof M.componentWillMount=="function"&&M.componentWillMount(),typeof M.UNSAFE_componentWillMount=="function"&&M.UNSAFE_componentWillMount()),typeof M.componentDidMount=="function"&&(n.flags|=4194308)):(typeof M.componentDidMount=="function"&&(n.flags|=4194308),n.memoizedProps=c,n.memoizedState=X),M.props=c,M.state=X,M.context=ce,c=W):(typeof M.componentDidMount=="function"&&(n.flags|=4194308),c=!1)}else{M=n.stateNode,sh(e,n),W=n.memoizedProps,ce=n.type===n.elementType?W:Sr(n.type,W),M.props=ce,we=n.pendingProps,ye=M.context,X=s.contextType,typeof X=="object"&&X!==null?X=mr(X):(X=jn(s)?So:Cn.current,X=Cs(n,X));var Fe=s.getDerivedStateFromProps;(_e=typeof Fe=="function"||typeof M.getSnapshotBeforeUpdate=="function")||typeof M.UNSAFE_componentWillReceiveProps!="function"&&typeof M.componentWillReceiveProps!="function"||(W!==we||ye!==X)&&Fh(n,M,c,X),Yi=!1,ye=n.m Line truncated
`)}function Is(r,a,o){const l=Math.floor(Date.now()/1e3);return{id:-Date.now(),type:"PRIV",conversation_key:r,text:a,sender_timestamp:l,received_at:l,path:null,txt_type:0,signature:null,outgoing:o,acked:1}}function Wv(r){const a=F.useRef(null),o=F.useRef(null),l=F.useCallback(()=>{o.current!==null&&(clearInterval(o.current),o.current=null),a.current=null},[]),d=F.useCallback(async()=>{const m=a.current;if(!m)return;let h=null,x=null;for(let p=0;p<2;p++)try{h=await st.requestTelemetry(m.conversationId,"");break}catch(v){x=v instanceof Error?v:new Error("Unknown error"),p===0&&await new Promise(y=>setTimeout(y,2e3))}if(h){const p=Is(m.conversationId,Zv(m,h),!1);r(v=>[...v,p])}else{const p=Is(m.conversationId,`Duty cycle poll failed after retry: ${(x==null?void 0:x.message)??"Unknown error"}`,!1);r(v=>[...v,p])}},[r]),f=F.useCallback(async(m,h)=>{const x=m.trim().toLowerCase();if(x==="dutycycle_start"){l();let p=null,v=null;for(let B=0;B<2;B++)try{p=await st.requestTelemetry(h,"");break}catch(D){v=D instanceof Error?D:new Error("Unknown error"),B===0&&await new Promise(C=>setTimeout(C,2e3))}if(!p){const B=Is(h,`Failed to start duty cycle tracking after retry: ${(v==null?void 0:v.message)??"Unknown error"}`,!1);return r(D=>[...D,B]),!0}const y=Math.floor(Date.now()/1e3);a.current={startTime:y,uptime:p.uptime_seconds,txAirtime:p.airtime_seconds,rxAirtime:p.rx_airtime_seconds,sentFlood:p.sent_flood,sentDirect:p.sent_direct,recvFlood:p.recv_flood,recvDirect:p.recv_direct,conversationId:h};const w=Is(h,`Airtime/duty cycle statistics gathering begins at ${y}. Logs will follow every 5 minutes. To stop, run dutycycle_stop or navigate away from this conversation.`,!1);return r(B=>[...B,w]),o.current=window.setInterval(d,Vv),!0}if(x==="dutycycle_stop"){if(a.current&&a.current.conversationId===h){await d(),l();const p=Is(h,"Airtime/duty cycle statistics gathering stopped.",!1);r(v=>[...v,p])}else{const p=Is(h,"Duty cycle tracking is not active.",!1);r(v=>[...v,p])}return!0}return!1},[r,l,d]);return F.useEffect(()=>()=>{o.current!==null&&clearInterval(o.current)},[]),{handleAirtimeCommand:f,stopTracking:l}}function Hu(r){if(r<60)return`${r}s`;const a=Math.floor(r/86400),o=Math.floor(r%86400/3600),l=Math.floor(r%3600/60);return a>0?o>0&&l>0?`${a}d${o}h${l}m`:o>0?`${a}d${o}h`:l>0?`${a}d${l}m`:`${a}d`:o>0?l>0?`${o}h${l}m`:`${o}h`:`${l}m`}function qv(r){return["Telemetry",`Battery Voltage: ${r.battery_volts.toFixed(3)}V`,`Uptime: ${Hu(r.uptime_seconds)}`,`TX Airtime: ${Hu(r.airtime_seconds)}`,`RX Airtime: ${Hu(r.rx_airtime_seconds)}`,"",`Noise Floor: ${r.noise_floor_dbm} dBm`,`Last RSSI: ${r.last_rssi_dbm} dBm`,`Last SNR: ${r.last_snr_db.toFixed(1)} dB`,"",`Packets: ${r.packets_received.toLocaleString()} rx / ${r.packets_sent.toLocaleString()} tx`,`Flood: ${r.recv_flood.toLocaleString()} rx / ${r.sent_flood.toLocaleString()} tx`,`Direct: ${r.recv_direct.toLocaleString()} rx / ${r.sent_direct.toLocaleString()} tx`,`Duplicates: ${r.flood_dups.toLocaleString()} flood / ${r.direct_dups.toLocaleString()} direct`,"",`TX Queue: ${r.tx_queue_len}`,`Debug Flags: ${r.full_events}`].join(`
`)}function Gv(r){if(r.length===0)return`Neighbors
No neighbors reported`;const a=[...r].sort((l,d)=>d.snr-l.snr),o=[`Neighbors (${a.length})`];for(const l of a){const d=l.name||l.pubkey_prefix,f=l.snr>=0?`+${l.snr.toFixed(1)}`:l.snr.toFixed(1);o.push(`${d}, ${f} dB [${Hu(l.last_heard_seconds)} ago]`)}return o.join(`
`)}function Qv(r){if(r.length===0)return`ACL
No ACL entries`;const a=[`ACL (${r.length})`];for(const o of r){const l=o.name||o.pubkey_prefix;a.push(`${l}: ${o.permission_name}`)}return a.join(`
`)}function zo(r,a,o,l=0){const d=Math.floor(Date.now()/1e3);return{id:-Date.now()-l,type:"PRIV",conversation_key:r,text:a,sender_timestamp:d,received_at:d,path:null,txt_type:0,signature:null,outgoing:o,acked:1}}function Kv(r,a,o){const[l,d]=F.useState(!1),{handleAirtimeCommand:f,stopTracking:m}=Wv(o);F.useEffect(()=>{d(!1),m()},[r==null?void 0:r.id,m]);const h=F.useMemo(()=>{if(!r||r.type!=="contact")return!1;const v=a.find(y=>y.public_key===r.id);return(v==null?void 0:v.type)===zc},[r,a]),x=F.useCallback(async v=>{if(!(!r||r.type!=="contact")&&h)try{const y=await st.requestTelemetry(r.id,v),w=zo(r.id,qv(y),!1,0),B=zo(r.id,Gv(y.neighbors),!1,1),D=zo(r.id,Qv(y.acl),!1,2);o(C=>[...C,w,B,D]),d(!0)}catch(y){const w=zo(r.id,`Telemetry request failed: ${y instanceof Error?y.message:"Unknown error"}`,!1,0);o(B=>[...B,w])}},[r,h,o]),p=F.useCallback(async v=>{if(!r||r.type!=="contact"||!h||!l||await f(v,r.id))return;const w=zo(r.id,`> ${v}`,!0,0);o(B=>[...B,w]);try{const B=await st.sendRepeaterCommand(r.id,v),D=zo(r.id,B.response,!1,1);B.sender_timestamp&&(D.sender_timestamp=B.sender_timestamp),o(C=>[...C,D])}catch(B){const D=zo(r.id,`Command failed: ${B instanceof Error?B.message:"Unknown error"}`,!1,1);o(C=>[...C,D])}},[r,h,l,o,f]);return{repeaterLoggedIn:l,activeContactIsRepeater:h,handleTelemetryRequest:x,handleRepeaterCommand:p}}const $v=12;function Gs(r){return r.slice(0,$v)}function MA(r,a){return!r||!a?!1:Gs(r)===Gs(a)}function Ci(r,a){return r||Gs(a)}const Jf="remoteterm-lastMessageTime";function IA(r){try{const a=localStorage.getItem(r);return a?JSON.parse(a):{}}catch{return{}}}function Yv(r,a){try{localStorage.setItem(r,JSON.stringify(a))}catch{}}function Lp(){return IA(Jf)}function Mf(r,a){const o=IA(Jf);return(!o[r]||a>o[r])&&(o[r]=a,Yv(Jf,o)),o}function Rr(r,a){return r==="channel"?`channel-${a}`:`contact-${Gs(a)}`}function Mp(r,a){if(!a)return!1;const o=a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`@\\[${o}\\]`,"i").test(r)}function Xv(r,a,o,l=null){const[d,f]=F.useState({}),[m,h]=F.useState({}),[x,p]=F.useState(Lp),v=F.useRef(l);F.useEffect(()=>{v.current=l},[l]);const y=F.useRef(new Set),w=F.useRef(new Set);F.useEffect(()=>{const P=r.filter(N=>!y.current.has(N.key)),T=a.filter(N=>N.public_key&&!w.current.has(N.public_key));if(P.length===0&&T.length===0)return;P.forEach(N=>y.current.add(N.key)),T.forEach(N=>w.current.add(N.public_key)),(async()=>{const N=[...P.map(I=>({type:"CHAN",conversation_key:I.key})),...T.map(I=>({type:"PRIV",conversation_key:I.public_key}))];if(N.length!==0)try{const I=await st.getMessagesBulk(N,g0),j={},H={},z={};for(const ee of P){const Z=I[`CHAN:${ee.key}`]||[];if(Z.length>0){const V=Rr("channel",ee.key),ne=ee.last_read_at||0,J=Z.filter(he=>!he.outgoing&&he.received_at>ne);J.length>0&&(j[V]=J.length,J.some(he=>Mp(he.text,v.current))&&(H[V]=!0));const re=Math.max(...Z.map(he=>he.received_at));z[V]=re,Mf(V,re)}}for(const ee of T){const Z=I[`PRIV:${ee.public_key}`]||[];if(Z.length>0){const V=Rr("contact",ee.public_key),ne=ee.last_read_at||0,J=Z.filter(he=>!he.outgoing&&he.received_at>ne);J.length>0&&(j[V]=J.length,J.some(he=>Mp(he.text,v.current))&&(H[V]=!0));const re=Math.max(...Z.map(he=>he.received_at));z[V]=re,Mf(V,re)}}Object.keys(j).length>0&&f(ee=>({...ee,...j})),Object.keys(H).length>0&&h(ee=>({...ee,...H})),p(Lp())}catch(I){console.error("Failed to fetch messages bulk:",I)}})()},[r,a]),F.useEffect(()=>{if(o&&o.type!=="raw"&&o.type!=="map"){const P=Rr(o.type,o.id);f(T=>{if(T[P]){const S={...T};return delete S[P],S}return T}),h(T=>{if(T[P]){const S={...T};return delete S[P],S}return T}),o.type==="channel"?st.markChannelRead(o.id).catch(T=>{console.error("Failed to mark channel as read on server:",T)}):o.type==="contact"&&st.markContactRead(o.id).catch(T=>{console.error("Failed to mark contact as read on server:",T)})}},[o]);const B=F.useCallback((P,T)=>{f(S=>({...S,[P]:(S[P]||0)+1})),T&&h(S=>({...S,[P]:!0}))},[]),D=F.useCallback(()=>{f({}),h({}),st.markAllRead().catch(P=>{console.error("Failed to mark all as read on server:",P)})},[]),C=F.useCallback(P=>{if(P.type==="raw"||P.type==="map")return;const T=Rr(P.type,P.id);f(S=>{if(S[T]){const N={...S};return delete N[T],N}return S}),h(S=>{if(S[T]){const N={...S};return delete N[T],N}return S}),P.type==="channel"?st.markChannelRead(P.id).catch(S=>{console.error("Failed to mark channel as read on server:",S)}):P.type==="contact"&&st.markContactRead(P.id).catch(S=>{console.error("Failed to mark contact as read on server:",S)})},[]),k=F.useCallback(P=>{let T=null;if(P.type==="CHAN"&&P.conversation_key?T=Rr("channel",P.conversation_key):P.type==="PRIV"&&P.conversation_key&&(T=Rr("contact",P.conversation_key)),T){const S=P.received_at||Math.floor(Date.now()/1e3),N=Mf(T,S);p(N)}},[]);return{unreadCounts:d,mentions:m,lastMessageTimes:x,incrementUnread:B,markAllRead:D,markConversationRead:C,trackNewMessage:k}}var x0=LA();const OA=$s(x0);function Jv(r){if(typeof document>"u")return;let a=document.head||document.getElem Line truncated
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const By=r=>r.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),Py=r=>r.replace(/^([A-Z])|[\s-_]+(\w)/g,(a,o,l)=>l?l.toUpperCase():o.toLowerCase()),zp=r=>{const a=Py(r);return a.charAt(0).toUpperCase()+a.slice(1)},zA=(...r)=>r.filter((a,o,l)=>!!a&&a.trim()!==""&&l.indexOf(a)===o).join(" ").trim(),Ty=r=>{for(const a in r)if(a.startsWith("aria-")||a==="role"||a==="title")return!0};/**
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/var Dy={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/**
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Ry=F.forwardRef(({color:r="currentColor",size:a=24,strokeWidth:o=2,absoluteStrokeWidth:l,className:d="",children:f,iconNode:m,...h},x)=>F.createElement("svg",{ref:x,...Dy,width:a,height:a,stroke:r,strokeWidth:l?Number(o)*24/Number(a):o,className:zA("lucide",d),...!f&&!Ty(h)&&{"aria-hidden":"true"},...h},[...m.map(([p,v])=>F.createElement(p,v)),...Array.isArray(f)?f:[f]]));/**
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const v0=(r,a)=>{const o=F.forwardRef(({className:l,...d},f)=>F.createElement(Ry,{ref:f,iconNode:a,className:zA(`lucide-${By(zp(r))}`,`lucide-${r}`,l),...d}));return o.displayName=zp(r),o};/**
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Fy=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],Ny=v0("check",Fy);/**
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Ly=[["path",{d:"M4 5h16",key:"1tepv9"}],["path",{d:"M4 12h16",key:"1lakjw"}],["path",{d:"M4 19h16",key:"1djgab"}]],My=v0("menu",Ly);/**
* @license lucide-react v0.562.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/const Iy=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],jA=v0("x",Iy);function Oy({health:r,config:a,onSettingsClick:o,onMenuClick:l}){const d=(r==null?void 0:r.radio_connected)??!1,[f,m]=F.useState(!1),h=async()=>{m(!0);try{const x=await st.reconnectRadio();x.connected&&kt.success("Reconnected",{description:x.message})}catch(x){kt.error("Reconnection failed",{description:x instanceof Error?x.message:"Check radio connection and power"})}finally{m(!1)}};return E.jsxs("div",{className:"flex items-center gap-4 px-4 py-2 bg-[#252525] border-b border-[#333] text-xs",children:[l&&E.jsx("button",{onClick:l,className:"md:hidden p-1 bg-transparent border-none text-[#e0e0e0] cursor-pointer","aria-label":"Open menu",children:E.jsx(My,{className:"h-5 w-5"})}),E.jsx("h1",{className:"hidden lg:block text-base font-semibold mr-auto",children:"RemoteTerm"}),E.jsxs("div",{className:"flex items-center gap-1 text-[#888]",children:[E.jsx("div",{className:`w-2 h-2 rounded-full ${d?"bg-[#4caf50]":"bg-[#666]"}`}),E.jsx("span",{className:"hidden lg:inline text-[#e0e0e0]",children:d?"Connected":"Disconnected"})]}),a&&E.jsx("div",{className:"hidden lg:flex items-center gap-1 text-[#888]",children:E.jsx("span",{className:"text-[#e0e0e0]",children:a.name||"Unnamed"})}),E.jsx("div",{className:"flex-1 lg:hidden"}),!d&&E.jsx("button",{onClick:h,disabled:f,className:"px-3 py-1 bg-[#4a3000] border border-[#6b4500] text-[#ffa500] rounded text-xs cursor-pointer hover:bg-[#5a3a00] disabled:opacity-50 disabled:cursor-not-allowed",children:f?"Reconnecting...":"Reconnect"}),E.jsxs("button",{onClick:o,className:"px-3 py-1 bg-[#333] border border-[#444] text-[#e0e0e0] rounded text-xs cursor-pointer hover:bg-[#444]",children:[E.jsx("span",{role:"img","aria-label":"Settings",children:"🔧"})," ","Radio & Config"]})]})}const t0=2,zy={text:"🛜",background:"#444444",textColor:"#ffffff"};function jy(r){let a=0;for(let o=0;o<r.length;o++){const l=r.charCodeAt(o);a=(a<<5)-a+l,a=a&a}return Math.abs(a)}const Hy=/[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{1F600}-\u{1F64F}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]/u;function Vy(r,a){if(!r)return a.slice(0,2).toUpperCase();const o=r.match(Hy);if(o)return o[0];const l=r.match(/[a-zA-Z]/g);if(!l||l.length===0)return a.slice(0,2).toUpperCase();const d=r.indexOf(" ");if(d!==-1){const f=l[0],m=r.slice(d+1).match(/[a-zA-Z]/);if(m)return(f+m[0]).toUpperCase()}return l[0].toUpperCase()}function Uy(r){const a=jy(r),o=a%360,l=50+(a>>8)%30,d=35+(a>>16)%20,f=`hsl(${o}, ${l}%, ${d}%)`,m=d<45?"#ffffff":"#000000";return{background:f,text:m}}function Zy(r,a,o){if(o===t0)return zy;const l=Vy(r,a),d=Uy(a);return{text:l,background:d.background,textColor:d.text}}function n0({name:r,publicKey:a,size:o=28,contactType:l}){const d=Zy(r,a,l);return E.jsx("div",{className:"flex items-center justify-center rounded-full font-semibold flex-shrink-0 select-none",style:{backgroundColor:d.background,color:d.textColor,width:o,height:o,fontSize:o*.45},children:d.text})}const HA="remoteterm-favorites";function jc(){try{const r=localStorage.getItem(HA);return r?JSON.parse(r):[]}catch{return[]}}function VA(r){try{localStorage.setItem(HA,JSON.stringify(r))}catch{}}function Wy(r,a){const o=jc();if(o.some(d=>d.type===r&&d.id===a))return o;const l=[...o,{type:r,id:a}];return VA(l),l}function qy(r,a){const l=jc().filter(d=>!(d.type===r&&d.id===a));return VA(l),l}function Us(r,a,o){return r.some(l=>l.type===a&&l.id===o)}function Gy(r,a){return jc().some(l=>l.type===r&&l.id===a)?qy(r,a):Wy(r,a)}function UA(r){var a,o,l="";if(typeof r=="string"||typeof r=="number")l+=r;else if(typeof r=="object")if(Array.isArray(r)){var d=r.length;for(a=0;a<d;a++)r[a]&&(o=UA(r[a]))&&(l&&(l+=" "),l+=o)}else for(o in r)r[o]&&(l&&(l+=" "),l+=o);return l}function ZA(){for(var r,a,o=0,l="",d=arguments.length;o<d;o++)(r=arguments[o])&&(a=UA(r))&&(l&&(l+=" "),l+=a);return l}const Qy=(r,a)=>{const o=new Array(r.length+a.length);for(let l=0;l<r.length;l++)o[l]=r[l];for(let l=0;l<a.length;l++)o[r.length+l]=a[l];return o},Ky=(r,a)=>({classGroupId:r,validator:a}),WA=(r=new Map,a=null,o)=>({nextPart:r,validators:a,classGroupId:o}),Dc="-",jp=[],$y="arbitrary..",Yy=r=>{const a=Jy(r),{conflictingClassGroups:o,conflictingClassGroupModifiers:l}=r;return{getClassGroupId:m=>{if(m.startsWith("[")&&m.endsWith("]"))return Xy(m);const h=m.split(Dc),x=h[0]===""&&h.length>1?1:0;return qA(h,x,a)},getConflictingClassGroupIds:(m,h)=>{if(h){const x=l[m],p=o[m];return x?p?Qy(p,x):x:p||jp}return o[m]||jp}}},qA=(r,a,o)=>{if(r.length-a===0)return o.classGroupId;const d=r[a],f=o.nextPart.get(d);if(f){const p=qA(r,a+1,f);if(p)return p}const m=o.validators;if(m===null)return;const h=a===0?r.join(Dc):r.slice(a).join(Dc),x=m.length;for(let p=0;p<x;p++){const v=m[p];if(v.validator(h))return v.classGroupId}},Xy=r=>r.slice(1,-1).indexOf(":")===-1?void 0:(()=>{const a=r.slice(1,-1),o=a.indexOf(":"),l=a.slice(0,o);return l?$y+l:void 0})(),Jy=r=>{conLine truncated
.`.concat(L1,` {
overflow: hidden `).concat(l,`;
padding-right: `).concat(h,"px ").concat(l,`;
}
body[`).concat(Ws,`] {
overflow: hidden `).concat(l,`;
overscroll-behavior: contain;
`).concat([a&&"position: relative ".concat(l,";"),o==="margin"&&`
padding-left: `.concat(d,`px;
padding-top: `).concat(f,`px;
padding-right: `).concat(m,`px;
margin-left:0;
margin-top:0;
margin-right: `).concat(h,"px ").concat(l,`;
`),o==="padding"&&"padding-right: ".concat(h,"px ").concat(l,";")].filter(Boolean).join(""),`
}
.`).concat(Uu,` {
right: `).concat(h,"px ").concat(l,`;
}
.`).concat(Zu,` {
margin-right: `).concat(h,"px ").concat(l,`;
}
.`).concat(Uu," .").concat(Uu,` {
right: 0 `).concat(l,`;
}
.`).concat(Zu," .").concat(Zu,` {
margin-right: 0 `).concat(l,`;
}
body[`).concat(Ws,`] {
`).concat(M1,": ").concat(h,`px;
}
`)},rm=function(){var r=parseInt(document.body.getAttribute(Ws)||"0",10);return isFinite(r)?r:0},tw=function(){F.useEffect(function(){return document.body.setAttribute(Ws,(rm()+1).toString()),function(){var r=rm()-1;r<=0?document.body.removeAttribute(Ws):document.body.setAttribute(Ws,r.toString())}},[])},nw=function(r){var a=r.noRelative,o=r.noImportant,l=r.gapMode,d=l===void 0?"margin":l;tw();var f=F.useMemo(function(){return X1(d)},[d]);return F.createElement(J1,{styles:ew(f,!a,d,o?"":"!important")})},o0=!1;if(typeof window<"u")try{var Iu=Object.defineProperty({},"passive",{get:function(){return o0=!0,!0}});window.addEventListener("test",Iu,Iu),window.removeEventListener("test",Iu,Iu)}catch{o0=!1}var zs=o0?{passive:!1}:!1,rw=function(r){return r.tagName==="TEXTAREA"},pg=function(r,a){if(!(r instanceof Element))return!1;var o=window.getComputedStyle(r);return o[a]!=="hidden"&&!(o.overflowY===o.overflowX&&!rw(r)&&o[a]==="visible")},iw=function(r){return pg(r,"overflowY")},ow=function(r){return pg(r,"overflowX")},im=function(r,a){var o=a.ownerDocument,l=a;do{typeof ShadowRoot<"u"&&l instanceof ShadowRoot&&(l=l.host);var d=mg(r,l);if(d){var f=Ag(r,l),m=f[1],h=f[2];if(m>h)return!0}l=l.parentNode}while(l&&l!==o.body);return!1},sw=function(r){var a=r.scrollTop,o=r.scrollHeight,l=r.clientHeight;return[a,o,l]},aw=function(r){var a=r.scrollLeft,o=r.scrollWidth,l=r.clientWidth;return[a,o,l]},mg=function(r,a){return r==="v"?iw(a):ow(a)},Ag=function(r,a){return r==="v"?sw(a):aw(a)},lw=function(r,a){return r==="h"&&a==="rtl"?-1:1},uw=function(r,a,o,l,d){var f=lw(r,window.getComputedStyle(a).direction),m=f*l,h=o.target,x=a.contains(h),p=!1,v=m>0,y=0,w=0;do{if(!h)break;var B=Ag(r,h),D=B[0],C=B[1],k=B[2],P=C-k-f*D;(D||P)&&mg(r,h)&&(y+=P,w+=D);var T=h.parentNode;h=T&&T.nodeType===Node.DOCUMENT_FRAGMENT_NODE?T.host:T}while(!x&&h!==document.body||x&&(a.contains(h)||a===h));return(v&&Math.abs(y)<1||!v&&Math.abs(w)<1)&&(p=!0),p},Ou=function(r){return"changedTouches"in r?[r.changedTouches[0].clientX,r.changedTouches[0].clientY]:[0,0]},om=function(r){return[r.deltaX,r.deltaY]},sm=function(r){return r&&"current"in r?r.current:r},cw=function(r,a){return r[0]===a[0]&&r[1]===a[1]},dw=function(r){return`
.block-interactivity-`.concat(r,` {pointer-events: none;}
.allow-interactivity-`).concat(r,` {pointer-events: all;}
`)},fw=0,js=[];function hw(r){var a=F.useRef([]),o=F.useRef([0,0]),l=F.useRef(),d=F.useState(fw++)[0],f=F.useState(hg)[0],m=F.useRef(r);F.useEffect(function(){m.current=r},[r]),F.useEffect(function(){if(r.inert){document.body.classList.add("block-interactivity-".concat(d));var C=N1([r.lockRef.current],(r.shards||[]).map(sm),!0).filter(Boolean);return C.forEach(function(k){return k.classList.add("allow-interactivity-".concat(d))}),function(){document.body.classList.remove("block-interactivity-".concat(d)),C.forEach(function(k){return k.classList.remove("allow-interactivity-".concat(d))})}}},[r.inert,r.lockRef.current,r.shards]);var h=F.useCallback(function(C,k){if("touches"in C&&C.touches.length===2||C.type==="wheel"&&C.ctrlKey)return!m.current.allowPinchZoom;var P=Ou(C),T=o.current,S="deltaX"in C?C.deltaX:T[0]-P[0],N="deltaY"in C?C.deltaY:T[1]-P[1],I,j=C.target,H=Math.abs(S)>Math.abs(N)?"h":"v";if("touches"in C&&H==="h"&&j.type==="range")return!1;var z=window.getSelection(),ee=z&&z.anchorNode,Z=ee?ee===j||ee.contains(j):!1;if(Z)return!1;var V=im(H,j);if(!V)return!0;if(V?I=H:(I=H==="v"?"h":"v",V=im(H,j)),!V)return!1;if(!l.current&&"changedTouches"in C&&(S||N)&&(l.current=I),!I)return!0;var ne=l.current||I;return uw(ne,k,C,ne==="h"?S:N)},[]),x=F.useCallback(function(C){var k=C;if(!(!js.length||js[js.length-1]!==f)){var P="deltaY"in k?om(k):Ou(k),T=a.current.filter(function(I){return I.name===k.type&&(I.target===k.target||k.target===I.shadowParent)&&cw(I.delta,P)})[0];if(T&&T.should){k.cancelable&&k.preventDefault();return}if(!T){var S=(m.current.shards||[]).map(sm).filter(Boolean).filter(function(I){return I.contains(k.target)}),N=S.length>0?h(k,S[0]):!m.current.noIsolation;N&&k.cancelable&&k.preventDefault()}}},[]),p=F.useCallback(function(C,k,P,T){var S={name:C,delta:k,target:P,should:T,shadowParent:pw(P)};a.current.push(S),setTimeout(function(){a.current=a.current.filter(function(N){return N!==S})},1)},[]),v=F.useCallback(function(C){o.current=Ou(C),l.current=void 0},[]),y=F.useCallback(function(C){p(C.type,om(C),C.target,h(C,r.lockRef.current))},[]),w=F.useCallback(function(C){p(C.type,Ou(C),C.target,h(C,r.lockRef.current))},[]);F.useEffect(function(){return js.push(f),r.setCallbacks({onScrollCapture:y,onWheelCapture:y,onTouchMoveCapture:w}),document.addEventListener("wheel",x,zs),document.addEventListener("touchmove",x,zs),document.addEventListener("touchstart",v,zs),function(){js=js.filter(function(C){return C!==f}),document.removeEventListener("wheel",x,zs),document.removeEventListener("touchmove",x,zs),document.removeEventListener("touchstart",v,zs)}},[]);var B=r.removeScrollBar,D=r.inert;return F.createElement(F.Fragment,null,D?F.createElement(f,{styles:dw(d)}):null,B?F.createElement(nw,{noRelative:r.noRelative,gapMode:r.gapMode}):null)}function pw(r){for(var a=null;r!==null;)r instanceof ShadowRoot&&(a=r.host,r=r.host),r=r.parentNode;return a}const mw=U1(fg,hw);var gg=F.forwardRef(function(r,a){return F.createElement(Vc,$r({},r,{ref:a,sideCar:mw}))});gg.classNames=Vc.classNames;var Aw=function(r){if(typeof document>"u")return null;var a=Array.isArray(r)?r[0]:r;return a.ownerDocument.body},Hs=new WeakMap,zu=new WeakMap,ju={},Wf=0,xg=function(r){return r&&(r.host||xg(r.parentNode))},gw=function(r,a){return a.map(function(o){if(r.contains(o))return o;var l=xg(o);return l&&r.contains(l)?l:(console.error("aria-hidden",o,"in not contained inside",r,". Doing nothing"),null)}).filter(function(o){return!!o})},xw=function(r,a,o,l){var d=gw(a,Array.isArray(r)?r:[r]);ju[o]||(ju[o]=new WeakMap);var f=ju[o],m=[],h=new Set,x=new Set(d),p=function(y){!y||h.has(y)||(h.add(y),p(y.parentNode))};d.forEach(p);var v=function(y){!y||x.has(y)||Array.prototype.forEach.call(y.children,function(w){if(h.has(w))v(w);else try{var B=w.getAttribute(l),D=B!==null&&B!=="false",C=(Hs.get(w)||0)+1,k=(f.get(w)||0)+1;Hs.set(w,C),f.set(w,k),m.push(w),C===1&&D&&zu.set(w,!0),k===1&&w.setAttribute(o,"true"),D||w.setAttribute(l,"true")}catch(P){console.error("aria-hidden: cannot operate on ",w,P)}})};return v(a),h.clear(),Wf++,function(){m.forEach(function(y){var w=Hs.get(y)-1,B=f.get(y)-1;Hs.set(y,w),f.set(y,B),w||(zu.has(y)||y.removeAttribute(l),zu.delete(y)),B||y.removeAttribute(o)}),Wf--,Wf||(Hs=new WeakMap,Hs=new WeakMap,zu=new WeakMap,ju={})}},vw=function(r,a,o){o===void 0&&(o="data-aria-hidden");var l=Array.from(Array.isArray(r)?r:[r]),d=Aw(r);return d?(l.push.apply(l,Array.from(d.querySelectorAll("[aria-live], script"))),xw(l,d,o,"aria-hidden")):function(){return null}};function yw(r){const a=_w(r),o=F.forwardRef((l,d)=>{const{children:f,...m}=l,h=F.Children.toArray(f),x=h.find(bw);if(x){const p=x.props.children,v=h.map(y=>y===x?F.Children.count(p)>1?F.Children.only(null):F.isValidElement(p)?p.props.children:null:y);return E.jsx(a,{...m,ref:d,children:F.isValidElement(p)?F.cloneElement(p,void 0,v):null})}return E.jsx(a,{...m,ref:d,children:f})});return o.displayName=`${r}.Slot`,o}function _w(r){const a=F.forwardRef((o,l)=>{const{chi Line truncated
If you want to hide the \`${a.titleName}\`, you can wrap it with our VisuallyHidden component.
For more information, see https://radix-ui.com/primitives/docs/components/${a.docsSlug}`;return F.useEffect(()=>{r&&(document.getElementById(r)||console.error(o))},[o,r]),null},Nw="DialogDescriptionWarning",Lw=({contentRef:r,descriptionId:a})=>{const l=`Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${Fg(Nw).contentName}}.`;return F.useEffect(()=>{var f;const d=(f=r.current)==null?void 0:f.getAttribute("aria-describedby");a&&d&&(document.getElementById(a)||console.warn(l))},[l,r,a]),null},Ng=yg,Lg=bg,Zc=Cg,Wc=Eg,qc=Sg,Gc=Pg,Mg=Dg;const k0=Ng,Mw=Lg,Ig=F.forwardRef(({className:r,...a},o)=>E.jsx(Zc,{ref:o,className:at("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",r),...a}));Ig.displayName=Zc.displayName;const Qc=F.forwardRef(({className:r,children:a,...o},l)=>E.jsxs(Mw,{children:[E.jsx(Ig,{}),E.jsxs(Wc,{ref:l,className:at("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",r),...o,children:[a,E.jsxs(Mg,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",children:[E.jsx(jA,{className:"h-4 w-4"}),E.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));Qc.displayName=Wc.displayName;const Kc=({className:r,...a})=>E.jsx("div",{className:at("flex flex-col space-y-1.5 text-center sm:text-left",r),...a});Kc.displayName="DialogHeader";const S0=({className:r,...a})=>E.jsx("div",{className:at("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",r),...a});S0.displayName="DialogFooter";const $c=F.forwardRef(({className:r,...a},o)=>E.jsx(qc,{ref:o,className:at("text-lg font-semibold leading-none tracking-tight",r),...a}));$c.displayName=qc.displayName;const Yc=F.forwardRef(({className:r,...a},o)=>E.jsx(Gc,{ref:o,className:at("text-sm text-muted-foreground",r),...a}));Yc.displayName=Gc.displayName;function Iw({open:r,onClose:a,path:o,senderInfo:l,contacts:d,config:f}){const m=Y_(o,l,d,f);return E.jsx(k0,{open:r,onOpenChange:h=>!h&&a(),children:E.jsxs(Qc,{className:"max-w-md max-h-[80vh] flex flex-col",children:[E.jsxs(Kc,{children:[E.jsx($c,{children:"Message Path"}),E.jsxs(Yc,{children:["This shows ",E.jsx("em",{children:"one route"})," that this message traveled through the mesh network. Flood messages may arrive via multiple paths, and routers may be incorrectly identified due to prefix collisions between heard and non-heard router advertisements."]})]}),E.jsx("div",{className:"flex-1 overflow-y-auto py-2",children:E.jsx(Ow,{resolved:m})}),E.jsx(S0,{children:E.jsx(Pn,{onClick:a,children:"Close"})})]})})}function Ow({resolved:r}){const a=o=>{if(o===0)return xn(r.sender.lat,r.sender.lon)?{lat:r.sender.lat,lon:r.sender.lon}:null;const l=r.hops[o-1];return l.matches.length>1||l.matches.length===0?null:xn(l.matches[0].lat,l.matches[0].lon)?{lat:l.matches[0].lat,lon:l.matches[0].lon}:null};return E.jsxs("div",{className:"space-y-0",children:[E.jsx(am,{label:"Sender",name:r.sender.name,prefix:r.sender.prefix,distance:null,isFirst:!0}),r.hops.map((o,l)=>E.jsx(zw,{hop:o,hopNumber:l+1,prevLocation:a(l)},l)),E.jsx(am,{label:"Receiver (me)",name:r.receiver.name,prefix:r.receiver.prefix,distance:jw(r),isLast:!0}),r.totalDistances&&r.totalDistances.length>0&&E.jsxs("div",{className:"pt-3 mt-3 border-t border-border",children:[E.jsxs("span",{className:"text-sm text-muted-foreground",children:["Presumed unambiguous distance covered:"," "]}),E.jsx("span",{className:"text-sm font-medium",children:Nc(r.totalDistances[0])})]})]})}function am({label:r,name:a,prefix:o,distance:l,isFirst:d,isLast:f}){return E.jsxs("div",{className:"flex gap-3",children:[E.jsxs("div",{className:"flex flex-col items-center w-4 flex-shrink-0",children:[!d&&E.jsx("div",{className:"w-0.5 h-3 bg-border"}),E.jsx("div",{className:"w-3 h-3 rounded-full bg-primary flex-shrink-0"}),!f&&E.jsx("div",{className:"w-0.5 flex-1 bg-border"})]}),E.jsxs("div",{className:"pb-3 flex-1 min-w-0",children:[E.jsx("div",{className:"text-xs text-muted-foreground font-medium",children:r}),E.jsxs("div",{className:"font-medium truncate",children:[a," ",E.jsxs("span",{className:"text-muted-foreground font-mono text-sm",children:["(",o,")"]})]}),l!==null&&E.jsx("div",{className:"text-xs text-muted-foreground",children:Nc(l)})]})]})}function zw({hop:r,hopNumber:a,prevL Line truncated
`).map(($,de,fe)=>E.jsxs("span",{children:[Hw($,h),de<fe.length-1&&E.jsx("br",{})]},de)),!Y&&E.jsxs(E.Fragment,{children:[E.jsx("span",{className:"text-[10px] text-muted-foreground/50 ml-2",children:al(z.sender_timestamp||z.received_at)}),!z.outgoing&&z.path&&E.jsxs("span",{className:"text-[10px] text-muted-foreground/50 ml-1 cursor-pointer hover:text-primary hover:underline",onClick:$=>{$.stopPropagation(),C({path:z.path,senderInfo:I(z,Z,ne)})},title:"View message path",children:["(",Lu(z.path)," hop",Lu(z.path)!==1?"s":"",")"]})]}),z.outgoing&&(z.acked>0?` ✓${z.acked>1?z.acked:""}`:" ?")]})]})]},z.id)})]}),w&&E.jsx("button",{onClick:T,className:"absolute bottom-4 right-4 w-10 h-10 rounded-full bg-muted hover:bg-accent border border-border flex items-center justify-center shadow-lg transition-opacity",title:"Scroll to bottom",children:E.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"text-muted-foreground",children:E.jsx("polyline",{points:"6 9 12 15 18 9"})})}),D&&E.jsx(Iw,{open:!0,onClose:()=>C(null),path:D.path,senderInfo:D.senderInfo,contacts:a,config:x??null})]})}const lm=156,Uw=140,Zw=156,Ww=120,qw=8,Gw=F.forwardRef(function({onSend:a,disabled:o,placeholder:l,isRepeaterMode:d,conversationType:f,senderName:m},h){const[x,p]=F.useState(""),[v,y]=F.useState(!1),w=F.useRef(null);F.useImperativeHandle(h,()=>({appendText:I=>{var j;p(H=>H+I),(j=w.current)==null||j.focus()}}));const B=F.useMemo(()=>{if(f==="contact")return{warningAt:Uw,dangerAt:lm,hardLimit:lm};if(f==="channel"){const I=(m==null?void 0:m.length)??10,j=Math.max(1,Zw-I-2);return{warningAt:Ww,dangerAt:Math.max(1,j-qw),hardLimit:j}}return null},[f,m]),{limitState:D,warningMessage:C}=F.useMemo(()=>{if(!B)return{limitState:"normal",warningMessage:null};const I=x.length;return I>=B.hardLimit?{limitState:"error",warningMessage:"likely truncated by radio"}:I>=B.dangerAt?{limitState:"danger",warningMessage:"may impact multi-repeater hop delivery"}:I>=B.warningAt?{limitState:"warning",warningMessage:"may impact multi-repeater hop delivery"}:{limitState:"normal",warningMessage:null}},[x.length,B]),k=B?B.hardLimit-x.length:0,P=F.useCallback(async I=>{I.preventDefault();const j=x.trim();if(d){if(v||o)return;y(!0);try{await a(j),p("")}catch(H){console.error("Failed to request telemetry:",H),kt.error("Failed to request telemetry",{description:H instanceof Error?H.message:"Check radio connection"});return}finally{y(!1)}setTimeout(()=>{var H;return(H=w.current)==null?void 0:H.focus()},0)}else{if(!j||v||o)return;y(!0);try{await a(j),p("")}catch(H){console.error("Failed to send message:",H),kt.error("Failed to send message",{description:H instanceof Error?H.message:"Check radio connection"});return}finally{y(!1)}setTimeout(()=>{var H;return(H=w.current)==null?void 0:H.focus()},0)}},[x,v,o,a,d]),T=F.useCallback(I=>{I.key==="Enter"&&!I.shiftKey&&(I.preventDefault(),P(I))},[P]),S=d?!0:x.trim().length>0,N=!d&&B!==null;return E.jsxs("form",{className:"px-4 py-3 border-t border-border flex flex-col gap-1",onSubmit:P,children:[E.jsxs("div",{className:"flex gap-2",children:[E.jsx(Yt,{ref:w,type:d?"password":"text",autoComplete:d?"off":void 0,value:x,onChange:I=>p(I.target.value),onKeyDown:T,placeholder:l||(d?"Enter password for admin login...":"Type a message..."),disabled:o||v,className:"flex-1 min-w-0"}),E.jsx(Pn,{type:"submit",disabled:o||v||!S,className:"flex-shrink-0",children:v?d?"Logging in...":"Sending...":d?x.trim()?"Log in with password":"Log in as guest/use repeater ACLs":"Send"})]}),N&&E.jsxs("div",{className:"flex items-center justify-end gap-2 text-xs",children:[E.jsxs("span",{className:at("tabular-nums",D==="error"||D==="danger"?"text-red-500 font-medium":D==="warning"?"text-yellow-500":"text-muted-foreground"),children:[x.length,"/",B.hardLimit,k<0&&` (${k})`]}),C&&E.jsxs("span",{className:at(D==="error"?"text-red-500":"text-yellow-500"),children:["— ",C]})]})]})});function um(r){const a=Qw(r),o=F.forwardRef((l,d)=>{const{children:f,...m}=l,h=F.Children.toArray(f),x=h.find($w);if(x){const p=x.props.children,v=h.map(y=>y===x?F.Children.count(p)>1?F.Children.only(null):F.isValidElement(p)?p.props.children:null:y);return E.jsx(a,{...m,ref:d,children:F.isValidElement(p)?F.cloneElement(p,void 0,v):null})}return E.jsx(a,{...m,ref:d,children:f})});return o.displayName=`${r}.Slot`,o}function Qw(r){const a=F.forwardRef((o,l)=>{const{children:d,...f}=o;if(F.isValidElement(d)){const m=Xw(d),h=Yw(f,d.props);return d.type!==F.Fragment&&(h.ref=l?dl(l,m):m),F.cloneElement(d,h)}return F.Children.count(d)>1?F.Children.only(null):null});return a.displayName=`${r}.SlotClone`,a}var Kw=Symbol("radix.slottable");function $w(r){return F.isValidElement(r)&&typeof r.type=="function"&&"__radixId"in r.type&&r.type.__radixId===Kw}function Yw(r,a){const o={...a};for(const l in a){const d=r[l],f=a[l];/^on[A-Z]/.test(l)?d&&f?o[l]=(...h Line truncated
* Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com
* (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade
*/var W2=il.exports,fm;function q2(){return fm||(fm=1,(function(r,a){(function(o,l){l(a)})(W2,(function(o){var l="1.9.4";function d(t){var i,u,A,b;for(u=1,A=arguments.length;u<A;u++){b=arguments[u];for(i in b)t[i]=b[i]}return t}var f=Object.create||(function(){function t(){}return function(i){return t.prototype=i,new t}})();function m(t,i){var u=Array.prototype.slice;if(t.bind)return t.bind.apply(t,u.call(arguments,1));var A=u.call(arguments,2);return function(){return t.apply(i,A.length?A.concat(u.call(arguments)):arguments)}}var h=0;function x(t){return"_leaflet_id"in t||(t._leaflet_id=++h),t._leaflet_id}function p(t,i,u){var A,b,O,K;return K=function(){A=!1,b&&(O.apply(u,b),b=!1)},O=function(){A?b=arguments:(t.apply(u,arguments),setTimeout(K,i),A=!0)},O}function v(t,i,u){var A=i[1],b=i[0],O=A-b;return t===A&&u?t:((t-b)%O+O)%O+b}function y(){return!1}function w(t,i){if(i===!1)return t;var u=Math.pow(10,i===void 0?6:i);return Math.round(t*u)/u}function B(t){return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"")}function D(t){return B(t).split(/\s+/)}function C(t,i){Object.prototype.hasOwnProperty.call(t,"options")||(t.options=t.options?f(t.options):{});for(var u in i)t.options[u]=i[u];return t.options}function k(t,i,u){var A=[];for(var b in t)A.push(encodeURIComponent(u?b.toUpperCase():b)+"="+encodeURIComponent(t[b]));return(!i||i.indexOf("?")===-1?"?":"&")+A.join("&")}var P=/\{ *([\w_ -]+) *\}/g;function T(t,i){return t.replace(P,function(u,A){var b=i[A];if(b===void 0)throw new Error("No value provided for variable "+u);return typeof b=="function"&&(b=b(i)),b})}var S=Array.isArray||function(t){return Object.prototype.toString.call(t)==="[object Array]"};function N(t,i){for(var u=0;u<t.length;u++)if(t[u]===i)return u;return-1}var I="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=";function j(t){return window["webkit"+t]||window["moz"+t]||window["ms"+t]}var H=0;function z(t){var i=+new Date,u=Math.max(0,16-(i-H));return H=i+u,window.setTimeout(t,u)}var ee=window.requestAnimationFrame||j("RequestAnimationFrame")||z,Z=window.cancelAnimationFrame||j("CancelAnimationFrame")||j("CancelRequestAnimationFrame")||function(t){window.clearTimeout(t)};function V(t,i,u){if(u&&ee===z)t.call(i);else return ee.call(window,m(t,i))}function ne(t){t&&Z.call(window,t)}var J={__proto__:null,extend:d,create:f,bind:m,get lastId(){return h},stamp:x,throttle:p,wrapNum:v,falseFn:y,formatNum:w,trim:B,splitWords:D,setOptions:C,getParamString:k,template:T,isArray:S,indexOf:N,emptyImageUrl:I,requestFn:ee,cancelFn:Z,requestAnimFrame:V,cancelAnimFrame:ne};function re(){}re.extend=function(t){var i=function(){C(this),this.initialize&&this.initialize.apply(this,arguments),this.callInitHooks()},u=i.__super__=this.prototype,A=f(u);A.constructor=i,i.prototype=A;for(var b in this)Object.prototype.hasOwnProperty.call(this,b)&&b!=="prototype"&&b!=="__super__"&&(i[b]=this[b]);return t.statics&&d(i,t.statics),t.includes&&(he(t.includes),d.apply(null,[A].concat(t.includes))),d(A,t),delete A.statics,delete A.includes,A.options&&(A.options=u.options?f(u.options):{},d(A.options,t.options)),A._initHooks=[],A.callInitHooks=function(){if(!this._initHooksCalled){u.callInitHooks&&u.callInitHooks.call(this),this._initHooksCalled=!0;for(var O=0,K=A._initHooks.length;O<K;O++)A._initHooks[O].call(this)}},i},re.include=function(t){var i=this.prototype.options;return d(this.prototype,t),t.options&&(this.prototype.options=i,this.mergeOptions(t.options)),this},re.mergeOptions=function(t){return d(this.prototype.options,t),this},re.addInitHook=function(t){var i=Array.prototype.slice.call(arguments,1),u=typeof t=="function"?t:function(){this[t].apply(this,i)};return this.prototype._initHooks=this.prototype._initHooks||[],this.prototype._initHooks.push(u),this};function he(t){if(!(typeof L>"u"||!L||!L.Mixin)){t=S(t)?t:[t];for(var i=0;i<t.length;i++)t[i]===L.Mixin.Events&&console.warn("Deprecated include of L.Mixin.Events: this property will be removed in future releases, please inherit from L.Evented instead.",new Error().stack)}}var ae={on:function(t,i,u){if(typeof t=="object")for(var A in t)this._on(A,t[A],i);else{t=D(t);for(var b=0,O=t.length;b<O;b++)this._on(t[b],i,u)}return this},off:function(t,i,u){if(!arguments.length)delete this._events;else if(typeof t=="object")for(var A in t)this._off(A,t[A],i);else{t=D(t);for(var b=arguments.length===1,O=0,K=t.length;O<K;O++)b?this._off(t[O]):this._off(t[O],i,u)}return this},_on:function(t,i,u,A){if(typeof i!="function"){console.warn("wrong listener type: "+typeof i);return}if(this._listens(t,i,u)===!1){u===this&&(u=void 0);var b={fn:i,ctx:u};A&&(b.once=!0),this._events=this._events||{},this._events[t]=this._events[t]||[],this._events[t].push(b)}},_off:function(t,i,u){var A,b,O;if(this._events&&(A=this._events[t],!!A)){if(arguments.length===1){if(this._firingCount)for(b=0,O=A.length;b<O;b++)A[b].fn=y;delete this._events[t];return}if(typeof i!="function"){console.warn("wrong listener type: "+typeof i);return}var K=tLine truncated
(c) 2012 by Cédric Mesnil. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/return(function(l){var d=o,f=d.lib,m=f.WordArray,h=f.Hasher,x=d.algo,p=m.create([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13]),v=m.create([5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11]),y=m.create([11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6]),w=m.create([8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]),B=m.create([0,1518500249,1859775393,2400959708,2840853838]),D=m.create([1352829926,1548603684,1836072691,2053994217,0]),C=x.RIPEMD160=h.extend({_doReset:function(){this._hash=m.create([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(j,H){for(var z=0;z<16;z++){var ee=H+z,Z=j[ee];j[ee]=(Z<<8|Z>>>24)&16711935|(Z<<24|Z>>>8)&4278255360}var V=this._hash.words,ne=B.words,J=D.words,re=p.words,he=v.words,ae=y.words,pe=w.words,G,Y,q,R,U,Q,$,de,fe,ke;Q=G=V[0],$=Y=V[1],de=q=V[2],fe=R=V[3],ke=U=V[4];for(var ge,z=0;z<80;z+=1)ge=G+j[H+re[z]]|0,z<16?ge+=k(Y,q,R)+ne[0]:z<32?ge+=P(Y,q,R)+ne[1]:z<48?ge+=T(Y,q,R)+ne[2]:z<64?ge+=S(Y,q,R)+ne[3]:ge+=N(Y,q,R)+ne[4],ge=ge|0,ge=I(ge,ae[z]),ge=ge+U|0,G=U,U=R,R=I(q,10),q=Y,Y=ge,ge=Q+j[H+he[z]]|0,z<16?ge+=N($,de,fe)+J[0]:z<32?ge+=S($,de,fe)+J[1]:z<48?ge+=T($,de,fe)+J[2]:z<64?ge+=P($,de,fe)+J[3]:ge+=k($,de,fe)+J[4],ge=ge|0,ge=I(ge,pe[z]),ge=ge+ke|0,Q=ke,ke=fe,fe=I(de,10),de=$,$=ge;ge=V[1]+q+fe|0,V[1]=V[2]+R+ke|0,V[2]=V[3]+U+Q|0,V[3]=V[4]+G+$|0,V[4]=V[0]+Y+de|0,V[0]=ge},_doFinalize:function(){var j=this._data,H=j.words,z=this._nDataBytes*8,ee=j.sigBytes*8;H[ee>>>5]|=128<<24-ee%32,H[(ee+64>>>9<<4)+14]=(z<<8|z>>>24)&16711935|(z<<24|z>>>8)&4278255360,j.sigBytes=(H.length+1)*4,this._process();for(var Z=this._hash,V=Z.words,ne=0;ne<5;ne++){var J=V[ne];V[ne]=(J<<8|J>>>24)&16711935|(J<<24|J>>>8)&4278255360}return Z},clone:function(){var j=h.clone.call(this);return j._hash=this._hash.clone(),j}});function k(j,H,z){return j^H^z}function P(j,H,z){return j&H|~j&z}function T(j,H,z){return(j|~H)^z}function S(j,H,z){return j&z|H&~z}function N(j,H,z){return j^(H|~z)}function I(j,H){return j<<H|j>>>32-H}d.RIPEMD160=h._createHelper(C),d.HmacRIPEMD160=h._createHmacHelper(C)})(),o.RIPEMD160})})(oc)),oc.exports}var sc={exports:{}},Lb=sc.exports,Dm;function id(){return Dm||(Dm=1,(function(r,a){(function(o,l){r.exports=l(dt())})(Lb,function(o){(function(){var l=o,d=l.lib,f=d.Base,m=l.enc,h=m.Utf8,x=l.algo;x.HMAC=f.extend({init:function(p,v){p=this._hasher=new p.init,typeof v=="string"&&(v=h.parse(v));var y=p.blockSize,w=y*4;v.sigBytes>w&&(v=p.finalize(v)),v.clamp();for(var B=this._oKey=v.clone(),D=this._iKey=v.clone(),C=B.words,k=D.words,P=0;P<y;P++)C[P]^=1549556828,k[P]^=909522486;B.sigBytes=D.sigBytes=w,this.reset()},reset:function(){var p=this._hasher;p.reset(),p.update(this._iKey)},update:function(p){return this._hasher.update(p),this},finalize:function(p){var v=this._hasher,y=v.finalize(p);v.reset();var w=v.finalize(this._oKey.clone().concat(y));return w}})})()})})(sc)),sc.exports}var ac={exports:{}},Mb=ac.exports,Rm;function Ib(){return Rm||(Rm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),pl(),id())})(Mb,function(o){return(function(){var l=o,d=l.lib,f=d.Base,m=d.WordArray,h=l.algo,x=h.SHA256,p=h.HMAC,v=h.PBKDF2=f.extend({cfg:f.extend({keySize:128/32,hasher:x,iterations:25e4}),init:function(y){this.cfg=this.cfg.extend(y)},compute:function(y,w){for(var B=this.cfg,D=p.create(B.hasher,y),C=m.create(),k=m.create([1]),P=C.words,T=k.words,S=B.keySize,N=B.iterations;P.length<S;){var I=D.update(w).finalize(k);D.reset();for(var j=I.words,H=j.length,z=I,ee=1;ee<N;ee++){z=D.finalize(z),D.reset();for(var Z=z.words,V=0;V<H;V++)j[V]^=Z[V]}C.concat(I),T[0]++}return C.sigBytes=S*4,C}});l.PBKDF2=function(y,w,B){return v.create(B).compute(y,w)}})(),o.PBKDF2})})(ac)),ac.exports}var lc={exports:{}},Ob=lc.exports,Fm;function fo(){return Fm||(Fm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),_x(),id())})(Ob,function(o){return(function(){var l=o,d=l.lib,f=d.Base,m=d.WordArray,h=l.algo,x=h.MD5,p=h.EvpKDF=f.extend({cfg:f.extend({keySize:128/32,hasher:x,iterations:1}),init:function(v){this.cfg=this.cfg.extend(v)},compute:function(v,y){for(var w,B=this.cfg,D=B.hasher.create(),C=m.create(),k=C.words,P=B.keySize,T=B.iterations;k.length<P;){w&&D.update(w),w=D.update(v).finalize(y),D.reset();for(var S=1;S<T;S++)w=D.finalize(w),D.reset();C.concat(w)}return C.sigBytes=P*4,C}});l.EvpKDF=function(v,y,w){return p.create(w).compute(v,y)}})(),o.EvpKDF})})(lc)),lc.exports}var uc={exports:{}},zb=uc.exports,Line truncated
* Counter block mode compatible with Dr Brian Gladman fileenc.c
* derived from CryptoJS.mode.CTR
* Jan Hruby jhruby.web@gmail.com
*/return o.mode.CTRGladman=(function(){var l=o.lib.BlockCipherMode.extend();function d(h){if((h>>24&255)===255){var x=h>>16&255,p=h>>8&255,v=h&255;x===255?(x=0,p===255?(p=0,v===255?v=0:++v):++p):++x,h=0,h+=x<<16,h+=p<<8,h+=v}else h+=1<<24;return h}function f(h){return(h[0]=d(h[0]))===0&&(h[1]=d(h[1])),h}var m=l.Encryptor=l.extend({processBlock:function(h,x){var p=this._cipher,v=p.blockSize,y=this._iv,w=this._counter;y&&(w=this._counter=y.slice(0),this._iv=void 0),f(w);var B=w.slice(0);p.encryptBlock(B,0);for(var D=0;D<v;D++)h[x+D]^=B[D]}});return l.Decryptor=m,l})(),o.mode.CTRGladman})})(fc)),fc.exports}var hc={exports:{}},qb=hc.exports,Om;function Gb(){return Om||(Om=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(qb,function(o){return o.mode.OFB=(function(){var l=o.lib.BlockCipherMode.extend(),d=l.Encryptor=l.extend({processBlock:function(f,m){var h=this._cipher,x=h.blockSize,p=this._iv,v=this._keystream;p&&(v=this._keystream=p.slice(0),this._iv=void 0),h.encryptBlock(v,0);for(var y=0;y<x;y++)f[m+y]^=v[y]}});return l.Decryptor=d,l})(),o.mode.OFB})})(hc)),hc.exports}var pc={exports:{}},Qb=pc.exports,zm;function Kb(){return zm||(zm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(Qb,function(o){return o.mode.ECB=(function(){var l=o.lib.BlockCipherMode.extend();return l.Encryptor=l.extend({processBlock:function(d,f){this._cipher.encryptBlock(d,f)}}),l.Decryptor=l.extend({processBlock:function(d,f){this._cipher.decryptBlock(d,f)}}),l})(),o.mode.ECB})})(pc)),pc.exports}var mc={exports:{}},$b=mc.exports,jm;function Yb(){return jm||(jm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})($b,function(o){return o.pad.AnsiX923={pad:function(l,d){var f=l.sigBytes,m=d*4,h=m-f%m,x=f+h-1;l.clamp(),l.words[x>>>2]|=h<<24-x%4*8,l.sigBytes+=h},unpad:function(l){var d=l.words[l.sigBytes-1>>>2]&255;l.sigBytes-=d}},o.pad.Ansix923})})(mc)),mc.exports}var Ac={exports:{}},Xb=Ac.exports,Hm;function Jb(){return Hm||(Hm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(Xb,function(o){return o.pad.Iso10126={pad:function(l,d){var f=d*4,m=f-l.sigBytes%f;l.concat(o.lib.WordArray.random(m-1)).concat(o.lib.WordArray.create([m<<24],1))},unpad:function(l){var d=l.words[l.sigBytes-1>>>2]&255;l.sigBytes-=d}},o.pad.Iso10126})})(Ac)),Ac.exports}var gc={exports:{}},eC=gc.exports,Vm;function tC(){return Vm||(Vm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(eC,function(o){return o.pad.Iso97971={pad:function(l,d){l.concat(o.lib.WordArray.create([2147483648],1)),o.pad.ZeroPadding.pad(l,d)},unpad:function(l){o.pad.ZeroPadding.unpad(l),l.sigBytes--}},o.pad.Iso97971})})(gc)),gc.exports}var xc={exports:{}},nC=xc.exports,Um;function rC(){return Um||(Um=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(nC,function(o){return o.pad.ZeroPadding={pad:function(l,d){var f=d*4;l.clamp(),l.sigBytes+=f-(l.sigBytes%f||f)},unpad:function(l){for(var d=l.words,f=l.sigBytes-1,f=l.sigBytes-1;f>=0;f--)if(d[f>>>2]>>>24-f%4*8&255){l.sigBytes=f+1;break}}},o.pad.ZeroPadding})})(xc)),xc.exports}var vc={exports:{}},iC=vc.exports,Zm;function oC(){return Zm||(Zm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(iC,function(o){return o.pad.NoPadding={pad:function(){},unpad:function(){}},o.pad.NoPadding})})(vc)),vc.exports}var yc={exports:{}},sC=yc.exports,Wm;function aC(){return Wm||(Wm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),hn())})(sC,function(o){return(function(l){var d=o,f=d.lib,m=f.CipherParams,h=d.enc,x=h.Hex,p=d.format;p.Hex={stringify:function(v){return v.ciphertext.toString(x)},parse:function(v){var y=x.parse(v);return m.create({ciphertext:y})}}})(),o.format.Hex})})(yc)),yc.exports}var _c={exports:{}},lC=_c.exports,qm;function uC(){return qm||(qm=1,(function(r,a){(function(o,l,d){r.exports=l(dt(),Ko(),$o(),fo(),hn())})(lC,function(o){return(function(){var l=o,d=l.lib,f=d.BlockCipher,m=l.algo,h=[],x=[],p=[],v=[],y=[],w=[],B=[],D=[],C=[],k=[];(function(){for(var S=[],N=0;N<256;N++)N<128?S[N]=N<<1:S[N]=N<<1^283;for(var I=0,j=0,N=0;N<256;N++){var H=j^j<<1^j<<2^j<<3^j<<4;H=H>>>8^H&255^99,h[I]=H,x[H]=I;var z=S[I],ee=S[z],Z=S[ee],V=S[H]*257^H*16843008;p[I]=V<<24|V>>>8,v[I]=V<<16|V>>>16,y[I]=V<<8|V>>>24,w[I]=V;var V=Z*16843009^ee*65537^z*257^I*16843008;B[H]=V<<24|V>>>8,D[H]=V<<16|V>>>16,C[H]=V<<8|V>>>24,k[H]=V,I?(I=z^S[S[S[Z^z]]],j^=S[S[j]]):I=j=1}})();var P=[0,1,2,4,8,16,32,64,128,27,54],T=m.AES=f.extend({_doReset:function(){var S;if(!(this._nRounds&&this._keyPriorReset===this._key)){for(var N=this._keyPriorReset=this._key,I=N.words,j=N.sigBytes/4,H=this._nRounds=j+6,z=(H+1)*4,ee=this._keySchedule=[],Z=0;Z<z;Z++)Z<j?ee[Z]=I[Z]:(S=ee[Z-1],Z%j?j>6&&Z%j==4&&(S=h[S>>>24]<<24|h[S>>>16&255]<<16|h[S>>>8&255]<<8|h[S&255]):(S=S<<8|S>>>24,S=h[S>>>24]<<24|h[S>>>16&255]<<16|h[S>>>8&255]<<8|h[S&255],S^=P[Z/j|0]<<24),ee[Z]=ee[Z-j]^S);for(var V=this._invKeySchedule=[],ne=0;ne<z;ne++){var Z=z-ne;if(ne%4)var S=ee[Z];else var S=ee[Z-4];ne<4||Z<=4?V[ne]=S:V[ne]=B[h[S>>>24]]^D[h[S>>>16&255]]^C[h[S>>>8&255]]^k[h[S&255]Line truncated
• Timestamp (4 bytes) - send time as unix timestamp
• Request Type (1 byte) - type of request (GetStats, GetTelemetryData, etc.)
• Request Data (remaining bytes) - additional request-specific data`,startByte:h+x,endByte:h+d.length-1,value:w});const B={type:r.PayloadType.Request,version:r.PayloadVersion.Version1,isValid:!0,timestamp:0,requestType:r.RequestType.GetStats,requestData:"",destinationHash:p,sourceHash:v,cipherMac:y,ciphertext:w};return f!=null&&f.includeSegments&&(B.segments=m),B}catch(m){return{type:r.PayloadType.Request,version:r.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode request payload"],timestamp:0,requestType:r.RequestType.GetStats,requestData:"",destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:""}}}}return Ya.RequestPayloadDecoder=o,Ya}var Xa={},mA;function WC(){if(mA)return Xa;mA=1,Object.defineProperty(Xa,"__esModule",{value:!0}),Xa.ResponsePayloadDecoder=void 0;const r=sr(),a=vn();class o{static decode(d,f){try{if(d.length<4){const D={type:r.PayloadType.Response,version:r.PayloadVersion.Version1,isValid:!1,errors:["Response payload too short (minimum 4 bytes: dest + source + MAC)"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return f!=null&&f.includeSegments&&(D.segments=[{name:"Invalid Response Data",description:"Response payload too short (minimum 4 bytes required)",startByte:f.segmentOffset||0,endByte:(f.segmentOffset||0)+d.length-1,value:(0,a.bytesToHex)(d)}]),D}const m=[],h=(f==null?void 0:f.segmentOffset)||0;let x=0;const p=(0,a.byteToHex)(d[x]);f!=null&&f.includeSegments&&m.push({name:"Destination Hash",description:"First byte of destination node public key",startByte:h+x,endByte:h+x,value:p}),x+=1;const v=(0,a.byteToHex)(d[x]);f!=null&&f.includeSegments&&m.push({name:"Source Hash",description:"First byte of source node public key",startByte:h+x,endByte:h+x,value:v}),x+=1;const y=(0,a.bytesToHex)(d.subarray(x,x+2));f!=null&&f.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data in next field",startByte:h+x,endByte:h+x+1,value:y}),x+=2;const w=(0,a.bytesToHex)(d.subarray(x));f!=null&&f.includeSegments&&d.length>x&&m.push({name:"Ciphertext",description:"Encrypted response data (tag + content)",startByte:h+x,endByte:h+d.length-1,value:w});const B={type:r.PayloadType.Response,version:r.PayloadVersion.Version1,isValid:!0,destinationHash:p,sourceHash:v,cipherMac:y,ciphertext:w,ciphertextLength:d.length-4};return f!=null&&f.includeSegments&&(B.segments=m),B}catch(m){return{type:r.PayloadType.Response,version:r.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode response payload"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0}}}}return Xa.ResponsePayloadDecoder=o,Xa}var Ja={},AA;function qC(){if(AA)return Ja;AA=1,Object.defineProperty(Ja,"__esModule",{value:!0}),Ja.AnonRequestPayloadDecoder=void 0;const r=sr(),a=vn();class o{static decode(d,f){try{if(d.length<35){const D={type:r.PayloadType.AnonRequest,version:r.PayloadVersion.Version1,isValid:!1,errors:["AnonRequest payload too short (minimum 35 bytes: dest + public key + MAC)"],destinationHash:"",senderPublicKey:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return f!=null&&f.includeSegments&&(D.segments=[{name:"Invalid AnonRequest Data",description:"AnonRequest payload too short (minimum 35 bytes required: 1 for dest hash + 32 for public key + 2 for MAC)",startByte:f.segmentOffset||0,endByte:(f.segmentOffset||0)+d.length-1,value:(0,a.bytesToHex)(d)}]),D}const m=[],h=(f==null?void 0:f.segmentOffset)||0;let x=0;const p=(0,a.byteToHex)(d[0]);f!=null&&f.includeSegments&&m.push({name:"Destination Hash",description:`First byte of destination node public key: 0x${p}`,startByte:h+x,endByte:h+x,value:p}),x+=1;const v=(0,a.bytesToHex)(d.subarray(1,33));f!=null&&f.includeSegments&&m.push({name:"Sender Public Key",description:"Ed25519 public key of the sender (32 bytes)",startByte:h+x,endByte:h+x+31,value:v}),x+=32;const y=(0,a.bytesToHex)(d.subarray(33,35));f!=null&&f.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data verification (2 bytes)",startByte:h+x,endByte:h+x+1,value:y}),x+=2;const w=(0,a.bytesToHex)(d.subarray(35));f!=null&&f.includeSegments&&d.length>35&&m.push({name:"Ciphertext",description:`Encrypted message data (${d.length-35} bytes). Contains encrypted plaintext with this structure:
• Timestamp (4 bytes) - send time as unix timestamp
• Sync Timestamp (4 bytes) - room server only, sender's "sync messages SINCE x" timestamp
• Password (remaining bytes) - password for repeater/room`,startByte:h+x,endByte:h+d.length-1,value:w});const B={type:r.PayloadType.AnonRequest,version:r.PayloadVersion.Version1,isValid:!0,destinationHash:p,senderPublicKey:v,cipherMac:y,ciphertext:w,ciphertextLength:d.length-35};return f!=null&&f.includeSegments&&(B.segments=m),B}catch(m){return{type:r.PayloadType.AnonRequest,version:r.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode AnonRequest payload"],destinationHash:"",senderPublicKey:"",cipherMac:"",ciphertext:"",ciphertextLength:0}}}}return Ja.AnonRequestPayloadDecoder=o,Ja}var el={},gA;function GC(){if(gA)return el;gA=1,Object.defineProperty(el,"__esModule",{value:!0}),el.AckPayloadDecoder=void 0;const r=sr(),a=vn();class o{static decode(d,f){try{if(d.length<4){const v={type:r.PayloadType.Ack,version:r.PayloadVersion.Version1,isValid:!1,errors:["Ack payload too short (minimum 4 bytes for checksum)"],checksum:""};return f!=null&&f.includeSegments&&(v.segments=[{name:"Invalid Ack Data",description:"Ack payload too short (minimum 4 bytes required for checksum)",startByte:f.segmentOffset||0,endByte:(f.segmentOffset||0)+d.length-1,value:(0,a.bytesToHex)(d)}]),v}const m=[],h=(f==null?void 0:f.segmentOffset)||0,x=(0,a.bytesToHex)(d.subarray(0,4));f!=null&&f.includeSegments&&m.push({name:"Checksum",description:`CRC checksum of message timestamp, text, and sender pubkey: 0x${x}`,startByte:h,endByte:h+3,value:x}),f!=null&&f.includeSegments&&d.length>4&&m.push({name:"Additional Data",description:"Extra data in Ack payload",startByte:h+4,endByte:h+d.length-1,value:(0,a.bytesToHex)(d.subarray(4))});const p={type:r.PayloadType.Ack,version:r.PayloadVersion.Version1,isValid:!0,checksum:x};return f!=null&&f.includeSegments&&(p.segments=m),p}catch(m){return{type:r.PayloadType.Ack,version:r.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode Ack payload"],checksum:""}}}}return el.AckPayloadDecoder=o,el}var tl={},xA;function QC(){if(xA)return tl;xA=1,Object.defineProperty(tl,"__esModule",{value:!0}),tl.PathPayloadDecoder=void 0;const r=sr(),a=vn();class o{static decode(d){try{if(d.length<2)return{type:r.PayloadType.Path,version:r.PayloadVersion.Version1,isValid:!1,errors:["Path payload too short (minimum 2 bytes: path length + extra type)"],pathLength:0,pathHashes:[],extraType:0,extraData:""};const f=d[0];if(d.length<1+f+1)return{type:r.PayloadType.Path,version:r.PayloadVersion.Version1,isValid:!1,errors:[`Path payload too short (need ${1+f+1} bytes for path length + path + extra type)`],pathLength:f,pathHashes:[],extraType:0,extraData:""};const m=[];for(let p=0;p<f;p++)m.push((0,a.byteToHex)(d[1+p]));const h=d[1+f];let x="";return d.length>1+f+1&&(x=(0,a.bytesToHex)(d.subarray(1+f+1))),{type:r.PayloadType.Path,version:r.PayloadVersion.Version1,isValid:!0,pathLength:f,pathHashes:m,extraType:h,extraData:x}}catch(f){return{type:r.PayloadType.Path,version:r.PayloadVersion.Version1,isValid:!1,errors:[f instanceof Error?f.message:"Failed to decode Path payload"],pathLength:0,pathHashes:[],extraType:0,extraData:""}}}}return tl.PathPayloadDecoder=o,tl}var nl={},vA;function KC(){if(vA)return nl;vA=1,Object.defineProperty(nl,"__esModule",{value:!0}),nl.TextMessagePayloadDecoder=void 0;const r=sr(),a=vn();class o{static decode(d,f){try{if(d.length<4){const D={type:r.PayloadType.TextMessage,version:r.PayloadVersion.Version1,isValid:!1,errors:["TextMessage payload too short (minimum 4 bytes: dest + source + MAC)"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return f!=null&&f.includeSegments&&(D.segments=[{name:"Invalid TextMessage Data",description:"TextMessage payload too short (minimum 4 bytes required)",startByte:f.segmentOffset||0,endByte:(f.segmentOffset||0)+d.length-1,value:(0,a.bytesToHex)(d)}]),D}const m=[],h=(f==null?void 0:f.segmentOffset)||0;let x=0;const p=(0,a.byteToHex)(d[x]);f!=null&&f.includeSegments&&m.push({name:"Destination Hash",description:"First byte of destination node public key",startByte:h+x,endByte:h+x,value:p}),x+=1;const v=(0,a.byteToHex)(d[x]);f!=null&&f.includeSegments&&m.push({name:"Source Hash",description:"First byte of source node public key",startByte:h+x,endByte:h+x,value:v}),x+=1;const y=(0,a.bytesToHex)(d.subarray(x,x+2));f!=null&&f.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data in next field",startByte:h+x,endByte:h+x+1,value:y}),x+=2;const w=(0,a.bytesToHex)(d.subarray(x));f!=null&&f.includeSegments&&d.length>x&&m.push({name:"Ciphertext",description:"Encrypted message data (timestamp + message text)",startByte:h+x,endByte:h+d.length-1,value:w});const B={type:r.PayloadType.TextMessage,version:r.PayloadVersion.Version1,isValid:!0,destinationHash:p,sourceHash:v,cipherMac:y,ciphertext:w,ciphertextLength:d.length-4};return f!=null&&f.includeSegments&&(B.segments=m),B}catch(m){return{type:r.PayloadType.TextMessage,version:r.PayloadVersion.Version1,i Line truncated
// SHA256 round constants
const K: array<u32, 64> = array<u32, 64>(
0x428a2f98u, 0x71374491u, 0xb5c0fbcfu, 0xe9b5dba5u, 0x3956c25bu, 0x59f111f1u, 0x923f82a4u, 0xab1c5ed5u,
0xd807aa98u, 0x12835b01u, 0x243185beu, 0x550c7dc3u, 0x72be5d74u, 0x80deb1feu, 0x9bdc06a7u, 0xc19bf174u,
0xe49b69c1u, 0xefbe4786u, 0x0fc19dc6u, 0x240ca1ccu, 0x2de92c6fu, 0x4a7484aau, 0x5cb0a9dcu, 0x76f988dau,
0x983e5152u, 0xa831c66du, 0xb00327c8u, 0xbf597fc7u, 0xc6e00bf3u, 0xd5a79147u, 0x06ca6351u, 0x14292967u,
0x27b70a85u, 0x2e1b2138u, 0x4d2c6dfcu, 0x53380d13u, 0x650a7354u, 0x766a0abbu, 0x81c2c92eu, 0x92722c85u,
0xa2bfe8a1u, 0xa81a664bu, 0xc24b8b70u, 0xc76c51a3u, 0xd192e819u, 0xd6990624u, 0xf40e3585u, 0x106aa070u,
0x19a4c116u, 0x1e376c08u, 0x2748774cu, 0x34b0bcb5u, 0x391c0cb3u, 0x4ed8aa4au, 0x5b9cca4fu, 0x682e6ff3u,
0x748f82eeu, 0x78a5636fu, 0x84c87814u, 0x8cc70208u, 0x90befffau, 0xa4506cebu, 0xbef9a3f7u, 0xc67178f2u
);
// Character lookup table (a-z = 0-25, 0-9 = 26-35, dash = 36)
const CHARS: array<u32, 37> = array<u32, 37>(
0x61u, 0x62u, 0x63u, 0x64u, 0x65u, 0x66u, 0x67u, 0x68u, 0x69u, 0x6au, // a-j
0x6bu, 0x6cu, 0x6du, 0x6eu, 0x6fu, 0x70u, 0x71u, 0x72u, 0x73u, 0x74u, // k-t
0x75u, 0x76u, 0x77u, 0x78u, 0x79u, 0x7au, // u-z
0x30u, 0x31u, 0x32u, 0x33u, 0x34u, 0x35u, 0x36u, 0x37u, 0x38u, 0x39u, // 0-9
0x2du // dash
);
struct Params {
target_channel_hash: u32,
batch_offset: u32,
name_length: u32,
batch_size: u32,
target_mac: u32, // First 2 bytes of target MAC (in high 16 bits)
ciphertext_words: u32, // Number of 32-bit words in ciphertext
ciphertext_len_bits: u32, // Length of ciphertext in bits
verify_mac: u32, // 1 to verify MAC, 0 to skip
}
@group(0) @binding(0) var<uniform> params: Params;
@group(0) @binding(1) var<storage, read_write> match_count: atomic<u32>;
@group(0) @binding(2) var<storage, read_write> match_indices: array<u32>;
@group(0) @binding(3) var<storage, read> ciphertext: array<u32>; // Ciphertext data
fn rotr(x: u32, n: u32) -> u32 {
return (x >> n) | (x << (32u - n));
}
fn ch(x: u32, y: u32, z: u32) -> u32 {
return (x & y) ^ (~x & z);
}
fn maj(x: u32, y: u32, z: u32) -> u32 {
return (x & y) ^ (x & z) ^ (y & z);
}
fn sigma0(x: u32) -> u32 {
return rotr(x, 2u) ^ rotr(x, 13u) ^ rotr(x, 22u);
}
fn sigma1(x: u32) -> u32 {
return rotr(x, 6u) ^ rotr(x, 11u) ^ rotr(x, 25u);
}
fn gamma0(x: u32) -> u32 {
return rotr(x, 7u) ^ rotr(x, 18u) ^ (x >> 3u);
}
fn gamma1(x: u32) -> u32 {
return rotr(x, 17u) ^ rotr(x, 19u) ^ (x >> 10u);
}
// Convert index to room name bytes, returns the hash as a u32 for the first byte check
fn index_to_room_name(idx: u32, length: u32, msg: ptr<function, array<u32, 16>>) -> bool {
// Message starts with '#' (0x23)
var byte_pos = 0u;
var word_idx = 0u;
var current_word = 0x23000000u; // '#' in big-endian position 0
byte_pos = 1u;
var remaining = idx;
var prev_was_dash = false;
// Generate room name from index
for (var i = 0u; i < length; i++) {
let char_count = select(37u, 36u, i == 0u || i == length - 1u); // no dash at start/end
var char_idx = remaining % char_count;
remaining = remaining / char_count;
// Check for consecutive dashes (invalid)
let is_dash = char_idx == 36u && i > 0u && i < length - 1u;
if (is_dash && prev_was_dash) {
return false; // Invalid: consecutive dashes
}
prev_was_dash = is_dash;
// Map char index to actual character
let c = CHARS[char_idx];
// Pack byte into current word (big-endian)
let shift = (3u - byte_pos % 4u) * 8u;
if (byte_pos % 4u == 0u && byte_pos > 0u) {
(*msg)[word_idx] = current_word;
word_idx = word_idx + 1u;
current_word = 0u;
}
current_word = current_word | (c << shift);
byte_pos = byte_pos + 1u;
}
// Add padding: 0x80 followed by zeros, then length in bits
let msg_len_bits = (length + 1u) * 8u; // +1 for '#'
// Add 0x80 padding byte
let shift = (3u - byte_pos % 4u) * 8u;
if (byte_pos % 4u == 0u) {
(*msg)[word_idx] = current_word;
word_idx = word_idx + 1u;
current_word = 0x80000000u;
} else {
current_word = current_word | (0x80u << shift);
}
byte_pos = byte_pos + 1u;
// Store current word
if (byte_pos % 4u == 0u || word_idx < 14u) {
(*msg)[word_idx] = current_word;
word_idx = word_idx + 1u;
}
// Zero-fill until word 14
for (var i = word_idx; i < 14u; i++) {
(*msg)[i] = 0u;
}
// Length in bits (64-bit, but we only use lower 32 bits for short messages)
(*msg)[14u] = 0u;
(*msg)[15u] = msg_len_bits;
return true;
}
fn sha256_block(msg: ptr<function, array<u32, 16>>) -> array<u32, 8> {
// Initialize hash values
var h: array<u32, 8> = array<u32, 8>(
0x6a09e667u, 0xbb67ae85u, 0x3c6ef372u, 0xa54ff53au,
0x510e527fu, 0x9b05688cu, 0x1f83d9abu, 0x5be0cd19u
);
// Message schedule
var w: array<u32, 64>;
for (var i = 0u; i < 16u; i++) {
w[i] = (*msg)[i];
}
for (var i = 16u; i < 64u; i++) {
w[i] = gamma1(w[i-2u]) + w[i-7u] + gamma0(w[i-15u]) + w[i-16u];
}
// Compression
var a = h[0]; var b = h[1]; var c = h[2]; var d = h[3];
var e = h[4]; var f = h[5]; var g = h[6]; var hh = h[7];
for (var i = 0u; i < 64u; i++) {
let t1 = hh + sigma1(e) + ch(e, f, g) + K[i] + w[i];
let t2 = sigma0(a) + maj(a, b, c);
hh = g; g = f; f = e; e = d + t1;
d = c; c = b; b = a; a = t1 + t2;
}
h[0] = h[0] + a; h[1] = h[1] + b; h[2] = h[2] + c; h[3] = h[3] + d;
h[4] = h[4] + e; h[5] = h[5] + f; h[6] = h[6] + g; h[7] = h[7] + hh;
return h;
}
// Compute SHA256 of the key (16 bytes) to get channel hash
fn sha256_key(key: array<u32, 4>) -> u32 {
var msg: array<u32, 16>;
// Key bytes (16 bytes = 4 words)
msg[0] = key[0];
msg[1] = key[1];
msg[2] = key[2];
msg[3] = key[3];
// Padding: 0x80 followed by zeros
msg[4] = 0x80000000u;
for (var i = 5u; i < 14u; i++) {
msg[i] = 0u;
}
// Length: 128 bits
msg[14] = 0u;
msg[15] = 128u;
let hash = sha256_block(&msg);
// Return first byte of hash (big-endian)
return hash[0] >> 24u;
}
// HMAC-SHA256 for MAC verification
// Key is 16 bytes (4 words), padded to 32 bytes with zeros for MeshCore
// Returns first 2 bytes of HMAC (as u32 in high 16 bits)
fn hmac_sha256_mac(key: array<u32, 4>, ciphertext_len: u32) -> u32 {
// HMAC: H((K' ^ opad) || H((K' ^ ipad) || message))
// K' is 64 bytes (32 bytes key + 32 bytes zero padding for MeshCore, then padded to 64)
// ipad = 0x36 repeated, opad = 0x5c repeated
// Build padded key (64 bytes = 16 words)
// MeshCore uses 32-byte secret: 16-byte key + 16 zero bytes
var k_pad: array<u32, 16>;
k_pad[0] = key[0];
k_pad[1] = key[1];
k_pad[2] = key[2];
k_pad[3] = key[3];
for (var i = 4u; i < 16u; i++) {
k_pad[i] = 0u;
}
// Inner hash: SHA256((K' ^ ipad) || message)
// First block: K' ^ ipad (64 bytes)
var inner_block: array<u32, 16>;
for (var i = 0u; i < 16u; i++) {
inner_block[i] = k_pad[i] ^ 0x36363636u;
}
// Initialize hash state with first block
var h: array<u32, 8> = sha256_block(&inner_block);
// Process ciphertext blocks (continuing from h state)
let ciphertext_words = params.ciphertext_words;
var word_idx = 0u;
// Process full 64-byte blocks of ciphertext
while (word_idx + 16u <= ciphertext_words) {
var block: array<u32, 16>;
for (var i = 0u; i < 16u; i++) {
block[i] = ciphertext[word_idx + i];
}
h = sha256_block_continue(&block, h);
word_idx = word_idx + 16u;
}
// Final block with remaining ciphertext + padding
var final_block: array<u32, 16>;
var remaining = ciphertext_words - word_idx;
for (var i = 0u; i < 16u; i++) {
if (i < remaining) {
final_block[i] = ciphertext[word_idx + i];
} else if (i == remaining) {
// Add 0x80 padding
final_block[i] = 0x80000000u;
} else {
final_block[i] = 0u;
}
}
// Add length (64 bytes of ipad + ciphertext length)
let total_bits = 512u + params.ciphertext_len_bits;
if (remaining < 14u) {
final_block[14] = 0u;
final_block[15] = total_bits;
h = sha256_block_continue(&final_block, h);
} else {
// Need extra block for length
h = sha256_block_continue(&final_block, h);
var len_block: array<u32, 16>;
for (var i = 0u; i < 14u; i++) {
len_block[i] = 0u;
}
len_block[14] = 0u;
len_block[15] = total_bits;
h = sha256_block_continue(&len_block, h);
}
let inner_hash = h;
// Outer hash: SHA256((K' ^ opad) || inner_hash)
var outer_block: array<u32, 16>;
for (var i = 0u; i < 16u; i++) {
outer_block[i] = k_pad[i] ^ 0x5c5c5c5cu;
}
h = sha256_block(&outer_block);
// Second block: inner_hash (32 bytes) + padding
var hash_block: array<u32, 16>;
for (var i = 0u; i < 8u; i++) {
hash_block[i] = inner_hash[i];
}
hash_block[8] = 0x80000000u;
for (var i = 9u; i < 14u; i++) {
hash_block[i] = 0u;
}
hash_block[14] = 0u;
hash_block[15] = 512u + 256u; // 64 bytes opad + 32 bytes inner hash
h = sha256_block_continue(&hash_block, h);
// Return first 2 bytes (high 16 bits of first word)
return h[0] & 0xFFFF0000u;
}
// SHA256 block computation continuing from existing state
fn sha256_block_continue(msg: ptr<function, array<u32, 16>>, h_in: array<u32, 8>) -> array<u32, 8> {
var h = h_in;
// Message schedule
var w: array<u32, 64>;
for (var i = 0u; i < 16u; i++) {
w[i] = (*msg)[i];
}
for (var i = 16u; i < 64u; i++) {
w[i] = gamma1(w[i-2u]) + w[i-7u] + gamma0(w[i-15u]) + w[i-16u];
}
// Compression
var a = h[0]; var b = h[1]; var c = h[2]; var d = h[3];
var e = h[4]; var f = h[5]; var g = h[6]; var hh = h[7];
for (var i = 0u; i < 64u; i++) {
let t1 = hh + sigma1(e) + ch(e, f, g) + K[i] + w[i];
let t2 = sigma0(a) + maj(a, b, c);
hh = g; g = f; f = e; e = d + t1;
d = c; c = b; b = a; a = t1 + t2;
}
h[0] = h[0] + a; h[1] = h[1] + b; h[2] = h[2] + c; h[3] = h[3] + d;
h[4] = h[4] + e; h[5] = h[5] + f; h[6] = h[6] + g; h[7] = h[7] + hh;
return h;
}
// Process a single candidate and record match if found
fn process_candidate(name_idx: u32) {
// Generate message for this room name
var msg: array<u32, 16>;
let valid = index_to_room_name(name_idx, params.name_length, &msg);
if (!valid) {
return;
}
// Compute SHA256("#roomname") - this gives us the key
let key_hash = sha256_block(&msg);
// Take first 16 bytes (4 words) as the key
var key: array<u32, 4>;
key[0] = key_hash[0];
key[1] = key_hash[1];
key[2] = key_hash[2];
key[3] = key_hash[3];
// Compute SHA256(key) to get channel hash
let channel_hash = sha256_key(key);
// Check if channel hash matches target
if (channel_hash != params.target_channel_hash) {
return;
}
// Channel hash matches - verify MAC if enabled
if (params.verify_mac == 1u) {
let computed_mac = hmac_sha256_mac(key, params.ciphertext_len_bits);
if (computed_mac != params.target_mac) {
return;
}
}
// Found a match - record the index
let match_idx = atomicAdd(&match_count, 1u);
if (match_idx < 1024u) { // Limit stored matches
match_indices[match_idx] = name_idx;
}
}
// Each thread processes 32 candidates to amortize thread overhead
const CANDIDATES_PER_THREAD: u32 = 32u;
@compute @workgroup_size(256)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let base_idx = global_id.x * CANDIDATES_PER_THREAD;
for (var i = 0u; i < CANDIDATES_PER_THREAD; i++) {
let idx = base_idx + i;
if (idx >= params.batch_size) {
return;
}
let name_idx = params.batch_offset + idx;
process_candidate(name_idx);
}
}
`}async init(){if(!navigator.gpu)return console.warn("WebGPU not supported"),!1;try{const a=await navigator.gpu.requestAdapter();if(!a)return console.warn("No GPU adapter found"),!1;this.device=await a.requestDevice(),this.bindGroupLayout=this.device.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:3,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}}]}),this.paramsBuffer=this.device.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.matchCountBuffer=this.device.createBuffer({size:4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST}),this.matchIndicesBuffer=this.device.createBuffer({size:1024*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC});for(let d=0;d<2;d++)this.matchCountReadBuffers[d]=this.device.createBuffer({size:4,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),this.matchIndicesReadBuffers[d]=this.device.createBuffer({size:1024*4,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST});const o=this.device.createShaderModule({code:this.shaderCode}),l=this.device.createPipelineLayout({bindGroupLayouts:[this.bindGroupLayout]});return this.pipeline=this.device.createComputePipeline({layout:l,compute:{module:o,entryPoint:"main"}}),!0}catch(a){return console.error("WebGPU initialization failed:",a),!1}}isAvailable(){return this.device!==null&&this.pipeline!==null}indexToRoomName(a,o){return qo(o,a)}countNamesForLength(a){return ol(a)}async runBatch(a,o,l,d,f,m){if(!this.device||!this.pipeline||!this.bindGroupLayout||!this.paramsBuffer||!this.matchCountBuffer||!this.matchIndicesBuffer||!this.matchCountReadBuffers[0]||!this.matchCountReadBuffers[1]||!this.matchIndicesReadBuffers[0]||!this.matchIndicesReadBuffers[1])throw new Error("GPU not initialized");const h=this.currentReadBufferIndex;this.currentReadBufferIndex=1-this.currentReadBufferIndex;const x=this.matchCountReadBuffers[h],p=this.matchIndicesReadBuffers[h],v=f&&m?1:0;let y,w=0,B=0;if(v){const I=new Uint8Array(f.length/2);for(let Z=0;Z<I.length;Z++)I[Z]=parseInt(f.substr(Z*2,2),16);w=I.length*8;const j=Math.ceil(I.length/4)*4,H=new Uint8Array(j);H.set(I),y=new Uint32Array(j/4);for(let Z=0;Z<y.length;Z++)y[Z]=H[Z*4]<<24|H[Z*4+1]<<16|H[Z*4+2]<<8|H[Z*4+3];const z=parseInt(m.substr(0,2),16),ee=parseInt(m.substr(2,2),16);B=z<<24|ee<<16}else y=new Uint32Array([0]);const D=Math.max(y.length*4,4);(!this.ciphertextBuffer||this.ciphertextBufferSize<D)&&(this.ciphertextBuffer&&this.ciphertextBuffer.destroy(),this.ciphertextBuffer=this.device.createBuffer({size:D,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),this.ciphertextBufferSize=D,this.bindGroupDirty=!0);const C=new Uint32Array([a,l,o,d,B,y.length,w,v]);this.device.queue.writeBuffer(this.paramsBuffer,0,C),this.device.queue.writeBuffer(this.ciphertextBuffer,0,y),this.device.queue.writeBuffer(this.matchCountBuffer,0,sd.ZERO_DATA),(this.bindGroupDirty||!this.bindGroup)&&(this.bindGroup=this.device.createBindGroup({layout:this.bindGroupLayout,entries:[{binding:0,resource:{buffer:this.paramsBuffer}},{binding:1,resource:{buffer:this.matchCountBuffer}},{binding:2,resource:{buffer:this.matchIndicesBuffer}},{binding:3,resource:{buffer:this.ciphertextBuffer}}]}),this.bindGroupDirty=!1);const k=this.device.createCommandEncoder(),P=k.beginComputePass();P.setPipeline(this.pipeline),P.setBindGroup(0,this.bindGroup),P.dispatchWorkgroups(Math.ceil(d/(256*32))),P.end(),k.copyBufferToBuffer(this.matchCountBuffer,0,x,0,4),k.copyBufferToBuffer(this.matchIndicesBuffer,0,p,0,1024*4),this.device.queue.submit([k.finish()]),await x.mapAsync(GPUMapMode.READ);const S=new Uint32Array(x.getMappedRange())[0];x.unmap();const N=[];if(S>0){await p.mapAsync(GPUMapMode.READ);const I=new Uint32Array(p.getMappedRange());for(let j=0;j<Math.min(S,1024);j++)N.push(I[j]);p.unmap()}return N}destroy(){var a,o,l,d,f,m,h,x;(a=this.paramsBuffer)==null||a.destroy(),(o=this.matchCountBuffer)==null||o.destroy(),(l=this.matchIndicesBuffer)==null||l.destroy(),(d=this.ciphertextBuffer)==null||d.destroy(),(f=this.matchCountReadBuffers[0])==null||f.destroy(),(m=this.matchCountReadBuffers[1])==null||m.destroy(),(h=this.matchIndicesReadBuffers[0])==null||h.destroy(),(x=this.matchIndicesReadBuffers[1])==null||x.destroy(),this.paramsBuffer=null,this.matchCountBuffer=null,this.matchIndicesBuffer=null,this.ciphertextBuffer=null,this.ciphertextBufferSize=0,this.matchCountReadBuffers=[null,null],this.matchIndicesReadBuffers=[null,null],this.currentReadBufferIndex=0,this.bindGroup=null,this.bindGroupDirty=!0,this.device&&(this.device.destroy(),this.device=null),this.pipeline=null,this.bindGroupLayout=null}}sd.ZERO_DATA=new Uint32Array([0]);function uE(){return typeof navigator<"u"&&"gpu"in navigator}class PA{runBatch(a,o,l,d,f,m){const h=[],x=a.toString(16).padStart(2,"0 Line truncated
`).map(f=>f.trim().toLowerCase()).filter(f=>f.length>0);this.wordlist=d.filter(TA)}setWordlist(a){this.wordlist=a.map(o=>o.trim().toLowerCase()).filter(TA)}abort(){this.abortFlag=!0}isGpuAvailable(){return uE()}async decodePacket(a){var l;const o=a.trim().replace(/\s+/g,"").replace(/^0x/i,"");if(!o||!/^[0-9a-fA-F]+$/.test(o))return null;try{const f=(l=(await kA.MeshCorePacketDecoder.decodeWithVerification(o,{})).payload)==null?void 0:l.decoded;return!(f!=null&&f.channelHash)||!(f!=null&&f.ciphertext)||!(f!=null&&f.cipherMac)?null:{channelHash:f.channelHash,ciphertext:f.ciphertext,cipherMac:f.cipherMac,isGroupText:!0}}catch{return null}}async crack(a,o,l){this.abortFlag=!1,this.useTimestampFilter=(o==null?void 0:o.useTimestampFilter)??!0,this.useUtf8Filter=(o==null?void 0:o.useUtf8Filter)??!0,this.useSenderFilter=(o==null?void 0:o.useSenderFilter)??!0,this.validSeconds=(o==null?void 0:o.validSeconds)??f0,this.useCpu=(o==null?void 0:o.forceCpu)??!1;const d=(o==null?void 0:o.maxLength)??8,f=(o==null?void 0:o.startingLength)??1,m=(o==null?void 0:o.useDictionary)??!0,h=(o==null?void 0:o.startFromType)??"bruteforce",x=a.toLowerCase(),p=await this.decodePacket(x);if(!p)return{found:!1,error:"Invalid packet or not a GroupText packet"};const{channelHash:v,ciphertext:y,cipherMac:w}=p,B=parseInt(v,16);this.useCpu?this.cpuInstance||(this.cpuInstance=new PA):this.gpuInstance||(this.gpuInstance=new sd,await this.gpuInstance.init()||(this.useCpu=!0,this.cpuInstance=new PA));const D=performance.now();let C=0,k=performance.now(),P=f,T=0,S=0,N=!1;if(o!=null&&o.startFrom){const J=o.startFrom.toLowerCase();if(h==="dictionary"){const re=this.wordlist.indexOf(J);re>=0&&(S=re+1)}else{N=!0;const re=sE(J);re&&(P=Math.max(f,re.length),T=re.index+1,T>=ol(P)&&(P++,T=0))}}let I=0;m&&!N&&this.wordlist.length>0&&(I+=this.wordlist.length-S);for(let J=P;J<=d;J++)I+=ol(J);I-=T;const j=(J,re,he)=>{if(!l)return;const pe=(performance.now()-D)/1e3,G=pe>0?Math.round(C/pe):0,Y=I-C,q=G>0?Y/G:0;l({checked:C,total:I,percent:I>0?Math.min(100,C/I*100):0,rateKeysPerSec:G,etaSeconds:q,elapsedSeconds:pe,currentLength:re,currentPosition:he,phase:J})},H=J=>{if(!Ux(y,w,J))return{valid:!1};const re=kA.ChannelCrypto.decryptGroupTextMessage(y,w,J);return!re.success||!re.data?{valid:!1}:this.useTimestampFilter&&!aE(re.data.timestamp,this.validSeconds)?{valid:!1}:this.useUtf8Filter&&!lE(re.data.message)?{valid:!1}:this.useSenderFilter&&!re.data.sender?{valid:!1}:{valid:!0,message:re.data.sender?`${re.data.sender}: ${re.data.message}`:re.data.message}};if(!N&&S===0&&P===f&&T===0){j("public-key",0,d0);const J=p0(Tc);if(v===J){const re=H(Tc);if(re.valid)return{found:!0,roomName:d0,key:Tc,decryptedMessage:re.message}}}if(m&&!N&&this.wordlist.length>0)for(let J=S;J<this.wordlist.length;J++){if(this.abortFlag)return{found:!1,aborted:!0,resumeFrom:this.wordlist[J],resumeType:"dictionary"};const re=this.wordlist[J],he=h0("#"+re),ae=p0(he);if(parseInt(ae,16)===B){const G=H(he);if(G.valid)return{found:!0,roomName:re,key:he,decryptedMessage:G.message,resumeFrom:re,resumeType:"dictionary"}}C++;const pe=performance.now();pe-k>=200&&(j("wordlist",re.length,re),k=pe,await new Promise(G=>setTimeout(G,0)))}const z=this.useCpu?1024:32768,ee=(o==null?void 0:o.gpuDispatchMs)??1e3;let Z=z,V=!1;for(let J=P;J<=d;J++){if(this.abortFlag)return{found:!1,aborted:!0,resumeFrom:qo(J,0)||void 0,resumeType:"bruteforce"};const re=ol(J);let he=J===P?T:0;for(;he<re;){if(this.abortFlag)return{found:!1,aborted:!0,resumeFrom:qo(J,he)||void 0,resumeType:"bruteforce"};const ae=Math.min(Z,re-he),pe=performance.now();let G;this.useCpu?G=this.cpuInstance.runBatch(B,J,he,ae,y,w):G=await this.gpuInstance.runBatch(B,J,he,ae,y,w);const Y=performance.now()-pe;if(C+=ae,!this.useCpu&&!V&&ae>=z&&Y>0){const R=ee/Y,U=Math.round(ae*R),Q=Math.pow(2,Math.round(Math.log2(Math.max(z,U))));Z=Math.max(z,Q),V=!0}for(const R of G){const U=qo(J,R);if(!U)continue;const Q=h0("#"+U),$=H(Q);if($.valid)return{found:!0,roomName:U,key:Q,decryptedMessage:$.message,resumeFrom:U,resumeType:"bruteforce"}}he+=ae;const q=performance.now();if(q-k>=200){const R=qo(J,Math.min(he,re-1))||"";j("bruteforce",J,R),k=q,await new Promise(U=>setTimeout(U,0))}}}return{found:!1,resumeFrom:qo(d,ol(d)-1)||void 0,resumeType:"bruteforce"}}destroy(){this.gpuInstance&&(this.gpuInstance.destroy(),this.gpuInstance=null),this.cpuInstance&&(this.cpuInstance.destroy(),this.cpuInstance=null)}}var Yf,DA;function pE(){return DA||(DA=1,Yf={webm:"data:video/webm;base64,GkXfowEAAAAAAAAfQoaBAUL3gQFC8oEEQvOBCEKChHdlYm1Ch4EEQoWBAhhTgGcBAAAAAAAVkhFNm3RALE27i1OrhBVJqWZTrIHfTbuMU6uEFlSua1OsggEwTbuMU6uEHFO7a1OsghV17AEAAAAAAACkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmAQAAAAAAAEUq17GDD0JATYCNTGF2ZjU1LjMzLjEwMFdBjUxhdmY1NS4zMy4xMDBzpJBlrrXf3DCDVB8KcgbMpcr+RImIQJBgAAAAAAAWVK5rAQAAAAAAD++uAQAAAAA Line truncated
NoSleep enabled for older iOS devices. This can interrupt
active or long-running network requests from completing successfully.
See https://github.com/richtr/NoSleep.js/issues/15 for more details.
`),this.noSleepTimer=window.setInterval(()=>{document.hidden||(window.location.href=window.location.href.split("#")[0],window.setTimeout(window.stop,0))},15e3),this.enabled=!0,Promise.resolve()):this.noSleepVideo.play().then(h=>(this.enabled=!0,h)).catch(h=>{throw this.enabled=!1,h})}disable(){l()?(this._wakeLock&&this._wakeLock.release(),this._wakeLock=null):o()?this.noSleepTimer&&(console.warn(`
NoSleep now disabled for older iOS devices.
`),window.clearInterval(this.noSleepTimer),this.noSleepTimer=null):this.noSleepVideo.pause(),this.enabled=!1}}return Xf=d,Xf}var AE=mE();const gE=$s(AE);function xE(r){if(r.length<4)return null;try{const o=parseInt(r.slice(0,2),16)&3;let l=2;if(o===0||o===3){if(r.length<l+8)return null;l+=8}if(r.length<l+2)return null;const d=parseInt(r.slice(l,l+2),16);l+=2;const f=d*2;return r.length<l+f?null:(l+=f,r.slice(l))}catch{return null}}function vE({packets:r,channels:a,onChannelCreate:o,onRunningChange:l,visible:d=!1}){const[f,m]=F.useState(!1),[h,x]=F.useState(6),[p,v]=F.useState(!1),[y,w]=F.useState(!0),[B,D]=F.useState(!1),[C,k]=F.useState(null),[P,T]=F.useState(new Map),[S,N]=F.useState([]),[I,j]=F.useState(!1),[H,z]=F.useState(null),[ee,Z]=F.useState(null),[V,ne]=F.useState(0),J=F.useRef(null),re=F.useRef(null),he=F.useRef(!1),ae=F.useRef(!1),pe=F.useRef(!1),G=F.useRef(new Map),Y=F.useRef(!1),q=F.useRef(6),R=F.useRef(!0),U=F.useRef(!1),Q=F.useRef(new Set),$=F.useRef(new Set);F.useEffect(()=>{const Se=new hE;J.current=Se,z(Se.isGpuAvailable());const Ue=new gE;return re.current=Ue,()=>{Se.destroy(),J.current=null,Ue.disable(),re.current=null}},[]),F.useEffect(()=>{!d||I||db(async()=>{const{ENGLISH_WORDLIST:Se}=await import("./wordlist-BtmChKSf.js");return{ENGLISH_WORDLIST:Se}},[]).then(({ENGLISH_WORDLIST:Se})=>{J.current&&(J.current.setWordlist(Se),j(!0))}).catch(Se=>{console.error("Failed to load wordlist:",Se),kt.error("Failed to load wordlist",{description:"Cracking will not be available"})})},[d,I]),F.useEffect(()=>{const Se=()=>{st.getUndecryptedPacketCount().then(({count:lt})=>Z(lt)).catch(()=>Z(null))};Se();const Ue=setInterval(Se,3e4);return()=>clearInterval(Ue)},[]);const de=F.useMemo(()=>new Set(a.map(Se=>Se.key.toUpperCase())),[a]),fe=r.filter(Se=>Se.payload_type==="GROUP_TEXT"&&!Se.decrypted);F.useEffect(()=>{let Se=0;T(Ue=>{const lt=new Map(Ue);let Dt=!1;for(const xt of fe)if(!lt.has(xt.id)){const it=xE(xt.data);if(it&&$.current.has(it)){Se++;continue}it&&$.current.add(it),lt.set(xt.id,{packet:xt,attempts:0,lastAttemptLength:0,status:"pending"}),Dt=!0}return Dt?(G.current=lt,lt):Ue}),Se>0&&ne(Ue=>Ue+Se)},[fe.length]),F.useEffect(()=>{G.current=P},[P]),F.useEffect(()=>{Y.current=p},[p]),F.useEffect(()=>{q.current=h},[h]),F.useEffect(()=>{R.current=y},[y]),F.useEffect(()=>{U.current=B},[B]),F.useEffect(()=>{Q.current=new Set(fe.map(Se=>Se.id))},[fe]),F.useEffect(()=>{l==null||l(f)},[f,l]);const ke=Array.from(P.values()).filter(Se=>Se.status==="pending").length,ge=Array.from(P.values()).filter(Se=>Se.status==="cracked").length,Ze=Array.from(P.values()).filter(Se=>Se.status==="failed").length,$e=F.useCallback(async()=>{if(pe.current||!J.current||!he.current)return;const Se=G.current;let Ue=null,lt=null;for(const[Ke,Xe]of Se.entries())if(Xe.status==="pending"){Ue=Xe,lt=Ke;break}if(!Ue&&Y.current){const Ke=Array.from(Se.entries()).filter(([,Xe])=>Xe.status==="failed"&&Xe.lastAttemptLength<10);Ke.length>0&&(Ke.sort((Xe,xe)=>Xe[1].lastAttemptLength-xe[1].lastAttemptLength),[lt,Ue]=Ke[0])}if(!Ue||lt===null){he.current&&setTimeout(()=>$e(),1e3);return}if(!Q.current.has(lt)){T(Ke=>{const Xe=new Map(Ke);return Xe.delete(lt),Xe}),he.current&&setTimeout(()=>$e(),10);return}pe.current=!0;const Dt=q.current,xt=Ue.lastAttemptLength>0,it=xt?Ue.lastAttemptLength+1:Dt;try{const Ke=await J.current.crack(Ue.packet.data,{maxLength:it,useSenderFilter:!0,useTimestampFilter:!0,useUtf8Filter:!0,...U.current&&{gpuDispatchMs:1e4},...xt&&{useDictionary:!1,startingLength:it}},Xe=>{k(Xe)});if(ae.current){ae.current=!1,pe.current=!1,k(null);return}if(Ke.found&&Ke.roomName&&Ke.key){T(Te=>{const pt=new Map(Te),Ut=pt.get(lt);return Ut&&pt.set(lt,{...Ut,status:"cracked",attempts:Ut.attempts+1,lastAttemptLength:it}),pt});const Xe={roomName:Ke.roomName,key:Ke.key,packetId:lt,message:Ke.decryptedMessage||"",crackedAt:Date.now()};N(Te=>[...Te,Xe]);const xe=Ke.key.toUpperCase();if(!de.has(xe))try{const Te="#"+Ke.roomName;await o(Te,Ke.key),R.current&&await st.decryptHistoricalPackets({key_type:"channel",channel_name:Te})}catch(Te){console.error("Failed to create channel or decrypt historical:",Te),kt.error("Failed to save cracked channel",{description:Te instanceof Error?Te.message:"Channel discovered but could not be saved"})}}else T(Xe=>{const xe=new Map(Xe),Te=xe.get(lt);return Te&&xe.set(lt,{...Te,status:"failed",attempts:Te.attempts+1,lastAttemptLength:it}),xe})}catch(Ke){console.error("Cracking error:",Ke),T(Xe=>{const xe=new Map(Xe),Te=xe.get(lt);return Te&&xe.set(lt,{...Te,status:"failed",attempts:Te.attempts+1,lastAttemptLength:it}),xe})}pe.current=!1,k(null),he.current&&setTimeout(()=>$e(),100)},[de,o]),wt=()=>{var Se;if(!H){kt.error("WebGPU not available",{description:"Cracking requires Chrome 113+ or Edge 113+ with WebGPU support."});return}m(!0),he.current=!0,ae.current=!1,(Se=re.current)==null||Se.enable(),$e()},ft=()=>{var Se,Ue;m(!1),he.current=!1,ae.current=!0,(Se=J.current)==null||Se.abort(),(Ue=re.current)==nu Line truncated
//# sourceMappingURL=index-DlEnSqQ7.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"mappings":";;;;;;;;6CASa,IAAIA,EAAE,OAAO,IAAI,eAAe,EAAEC,EAAE,OAAO,IAAI,cAAc,EAAEC,EAAE,OAAO,IAAI,gBAAgB,EAAEC,EAAE,OAAO,IAAI,mBAAmB,EAAEC,EAAE,OAAO,IAAI,gBAAgB,EAAEC,EAAE,OAAO,IAAI,gBAAgB,EAAEC,EAAE,OAAO,IAAI,eAAe,EAAEC,EAAE,OAAO,IAAI,mBAAmB,EAAEC,EAAE,OAAO,IAAI,gBAAgB,EAAEC,EAAE,OAAO,IAAI,YAAY,EAAEC,EAAE,OAAO,IAAI,YAAY,EAAEC,EAAE,OAAO,SAAS,SAASC,EAAEC,EAAE,CAAC,OAAUA,IAAP,MAAqB,OAAOA,GAAlB,SAA2B,MAAKA,EAAEF,GAAGE,EAAEF,CAAC,GAAGE,EAAE,YAAY,EAAqB,OAAOA,GAApB,WAAsBA,EAAE,KAAI,CAC1e,IAAI,EAAE,CAAC,UAAU,UAAU,CAAC,MAAM,EAAE,EAAE,mBAAmB,UAAU,GAAG,oBAAoB,UAAU,GAAG,gBAAgB,UAAU,EAAE,EAAEC,EAAE,OAAO,OAAOC,EAAE,GAAG,SAASC,EAAEH,EAAEI,EAAEC,EAAE,CAAC,KAAK,MAAML,EAAE,KAAK,QAAQI,EAAE,KAAK,KAAKF,EAAE,KAAK,QAAQG,GAAG,CAAC,CAACF,EAAE,UAAU,iBAAiB,GACnQA,EAAE,UAAU,SAAS,SAASH,EAAEI,EAAE,CAAC,GAAc,OAAOJ,GAAlB,UAAkC,OAAOA,GAApB,YAA6BA,GAAN,KAAQ,MAAM,MAAM,uHAAuH,EAAE,KAAK,QAAQ,gBAAgB,KAAKA,EAAEI,EAAE,UAAU,CAAC,EAAED,EAAE,UAAU,YAAY,SAASH,EAAE,CAAC,KAAK,QAAQ,mBAAmB,KAAKA,EAAE,aAAa,CAAC,EAAE,SAASM,GAAG,EAAEA,EAAE,UAAUH,EAAE,UAAU,SAASI,EAAEP,EAAEI,EAAEC,EAAE,CAAC,KAAK,MAAML,EAAE,KAAK,QAAQI,EAAE,KAAK,KAAKF,EAAE,KAAK,QAAQG,GAAG,CAAC,CAAC,IAAIG,EAAED,EAAE,UAAU,IAAID,EACrfE,EAAE,YAAYD,EAAEN,EAAEO,EAAEL,EAAE,SAAS,EAAEK,EAAE,qBAAqB,GAAG,IAAIC,EAAE,MAAM,QAAQC,EAAE,OAAO,UAAU,eAAeC,EAAE,CAAC,QAAQ,IAAI,EAAEC,EAAE,CAAC,IAAI,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,EAAE,EACxK,SAASC,EAAEb,EAAEI,EAAEC,EAAE,CAAC,IAAIS,EAAEC,GAAE,GAAGC,GAAE,KAAKC,GAAE,KAAK,GAASb,GAAN,KAAQ,IAAIU,KAAcV,EAAE,MAAX,SAAiBa,GAAEb,EAAE,KAAcA,EAAE,MAAX,SAAiBY,GAAE,GAAGZ,EAAE,KAAKA,EAAEM,EAAE,KAAKN,EAAEU,CAAC,GAAG,CAACF,EAAE,eAAeE,CAAC,IAAIC,GAAED,CAAC,EAAEV,EAAEU,CAAC,GAAG,IAAII,GAAE,UAAU,OAAO,EAAE,GAAOA,KAAJ,EAAMH,GAAE,SAASV,UAAU,EAAEa,GAAE,CAAC,QAAQC,GAAE,MAAMD,EAAC,EAAEE,GAAE,EAAEA,GAAEF,GAAEE,KAAID,GAAEC,EAAC,EAAE,UAAUA,GAAE,CAAC,EAAEL,GAAE,SAASI,EAAC,CAAC,GAAGnB,GAAGA,EAAE,aAAa,IAAIc,KAAKI,GAAElB,EAAE,aAAakB,GAAWH,GAAED,CAAC,IAAZ,SAAgBC,GAAED,CAAC,EAAEI,GAAEJ,CAAC,GAAG,MAAM,CAAC,SAAS3B,EAAE,KAAKa,EAAE,IAAIgB,GAAE,IAAIC,GAAE,MAAMF,GAAE,OAAOJ,EAAE,OAAO,CAAC,CAC7a,SAASU,GAAErB,EAAEI,EAAE,CAAC,MAAM,CAAC,SAASjB,EAAE,KAAKa,EAAE,KAAK,IAAII,EAAE,IAAIJ,EAAE,IAAI,MAAMA,EAAE,MAAM,OAAOA,EAAE,MAAM,CAAC,CAAC,SAASsB,EAAEtB,EAAE,CAAC,OAAiB,OAAOA,GAAlB,UAA4BA,IAAP,MAAUA,EAAE,WAAWb,CAAC,CAAC,SAASoC,EAAOvB,EAAE,CAAC,IAAII,EAAE,CAAC,IAAI,KAAK,IAAI,IAAI,EAAE,MAAM,IAAIJ,EAAE,QAAQ,QAAQ,SAASA,EAAE,CAAC,OAAOI,EAAEJ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAIwB,GAAE,OAAO,SAASC,EAAEzB,EAAEI,EAAE,CAAC,OAAiB,OAAOJ,GAAlB,UAA4BA,IAAP,MAAgBA,EAAE,KAAR,KAAYuB,EAAO,GAAGvB,EAAE,GAAG,EAAEI,EAAE,SAAS,EAAE,CAAC,CAC/W,SAASsB,GAAE1B,EAAEI,EAAEC,EAAES,EAAEC,GAAE,CAAC,IAAIC,GAAE,OAAOhB,GAAmBgB,KAAd,aAA6BA,KAAZ,aAAchB,EAAE,MAAK,IAAIiB,GAAE,GAAG,GAAUjB,IAAP,KAASiB,GAAE,OAAQ,QAAOD,GAAC,CAAE,IAAK,SAAS,IAAK,SAASC,GAAE,GAAG,MAAM,IAAK,SAAS,OAAOjB,EAAE,SAAQ,CAAE,KAAKb,EAAE,KAAKC,EAAE6B,GAAE,EAAE,CAAC,CAAC,GAAGA,GAAE,OAAOA,GAAEjB,EAAEe,GAAEA,GAAEE,EAAC,EAAEjB,EAAOc,IAAL,GAAO,IAAIW,EAAER,GAAE,CAAC,EAAEH,EAAEL,EAAEM,EAAC,GAAGV,EAAE,GAASL,GAAN,OAAUK,EAAEL,EAAE,QAAQwB,GAAE,KAAK,EAAE,KAAKE,GAAEX,GAAEX,EAAEC,EAAE,GAAG,SAASL,GAAE,CAAC,OAAOA,EAAC,CAAC,GAASe,IAAN,OAAUO,EAAEP,EAAC,IAAIA,GAAEM,GAAEN,GAAEV,GAAG,CAACU,GAAE,KAAKE,IAAGA,GAAE,MAAMF,GAAE,IAAI,IAAI,GAAGA,GAAE,KAAK,QAAQS,GAAE,KAAK,EAAE,KAAKxB,CAAC,GAAGI,EAAE,KAAKW,EAAC,GAAG,EAAyB,GAAvBE,GAAE,EAAEH,EAAOA,IAAL,GAAO,IAAIA,EAAE,IAAOL,EAAET,CAAC,EAAE,QAAQkB,GAAE,EAAEA,GAAElB,EAAE,OAAOkB,KAAI,CAACF,GACrfhB,EAAEkB,EAAC,EAAE,IAAIC,GAAEL,EAAEW,EAAET,GAAEE,EAAC,EAAED,IAAGS,GAAEV,GAAEZ,EAAEC,EAAEc,GAAEJ,EAAC,CAAC,SAASI,GAAEpB,EAAEC,CAAC,EAAe,OAAOmB,IAApB,WAAsB,IAAInB,EAAEmB,GAAE,KAAKnB,CAAC,EAAEkB,GAAE,EAAE,EAAEF,GAAEhB,EAAE,KAAI,GAAI,MAAMgB,GAAEA,GAAE,MAAMG,GAAEL,EAAEW,EAAET,GAAEE,IAAG,EAAED,IAAGS,GAAEV,GAAEZ,EAAEC,EAAEc,GAAEJ,EAAC,UAAqBC,KAAX,SAAa,MAAMZ,EAAE,OAAOJ,CAAC,EAAE,MAAM,mDAAuEI,IAApB,kBAAsB,qBAAqB,OAAO,KAAKJ,CAAC,EAAE,KAAK,IAAI,EAAE,IAAII,GAAG,2EAA2E,EAAE,OAAOa,EAAC,CACzZ,SAASU,GAAE3B,EAAEI,EAAEC,EAAE,CAAC,GAASL,GAAN,KAAQ,OAAOA,EAAE,IAAIc,EAAE,GAAGC,GAAE,EAAE,OAAAW,GAAE1B,EAAEc,EAAE,GAAG,GAAG,SAASd,GAAE,CAAC,OAAOI,EAAE,KAAKC,EAAEL,GAAEe,IAAG,CAAC,CAAC,EAASD,CAAC,CAAC,SAASc,GAAE5B,EAAE,CAAC,GAAQA,EAAE,UAAP,GAAe,CAAC,IAAII,EAAEJ,EAAE,QAAQI,EAAEA,EAAC,EAAGA,EAAE,KAAK,SAASA,EAAE,EAAQJ,EAAE,UAAN,GAAoBA,EAAE,UAAP,MAAeA,EAAE,QAAQ,EAAEA,EAAE,QAAQI,EAAC,EAAE,SAASA,EAAE,EAAQJ,EAAE,UAAN,GAAoBA,EAAE,UAAP,MAAeA,EAAE,QAAQ,EAAEA,EAAE,QAAQI,EAAC,CAAC,EAAOJ,EAAE,UAAP,KAAiBA,EAAE,QAAQ,EAAEA,EAAE,QAAQI,EAAE,CAAC,GAAOJ,EAAE,UAAN,EAAc,OAAOA,EAAE,QAAQ,QAAQ,MAAMA,EAAE,OAAQ,CAC5Z,IAAI6B,GAAE,CAAC,QAAQ,IAAI,EAAEC,EAAE,CAAC,WAAW,IAAI,EAAEC,EAAE,CAAC,uBAAuBF,GAAE,wBAAwBC,EAAE,kBAAkBnB,CAAC,EAAE,SAASqB,GAAG,CAAC,MAAM,MAAM,0DAA0D,CAAE,CACzM,OAAAC,GAAA,SAAiB,CAAC,IAAIN,GAAE,QAAQ,SAAS3B,EAAEI,EAAEC,EAAE,CAACsB,GAAE3B,EAAE,UAAU,CAACI,EAAE,MAAM,KAAK,SAAS,CAAC,EAAEC,CAAC,CAAC,EAAE,MAAM,SAASL,EAAE,CAAC,IAAII,EAAE,EAAE,OAAAuB,GAAE3B,EAAE,UAAU,CAACI,GAAG,CAAC,EAASA,CAAC,EAAE,QAAQ,SAASJ,EAAE,CAAC,OAAO2B,GAAE3B,EAAE,SAASA,EAAE,CAAC,OAAOA,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,SAASA,EAAE,CAAC,GAAG,CAACsB,EAAEtB,CAAC,EAAE,MAAM,MLine truncated
@@ -1 +1 @@
.leaflet-pane,.leaflet-tile,.leaflet-marker-icon,.leaflet-marker-shadow,.leaflet-tile-container,.leaflet-pane>svg,.leaflet-pane>canvas,.leaflet-zoom-box,.leaflet-image-layer,.leaflet-layer{position:absolute;left:0;top:0}.leaflet-container{overflow:hidden}.leaflet-tile,.leaflet-marker-icon,.leaflet-marker-shadow{-webkit-user-select:none;-moz-user-select:none;user-select:none;-webkit-user-drag:none}.leaflet-tile::-moz-selection{background:transparent}.leaflet-tile::selection{background:transparent}.leaflet-safari .leaflet-tile{image-rendering:-webkit-optimize-contrast}.leaflet-safari .leaflet-tile-container{width:1600px;height:1600px;-webkit-transform-origin:0 0}.leaflet-marker-icon,.leaflet-marker-shadow{display:block}.leaflet-container .leaflet-overlay-pane svg{max-width:none!important;max-height:none!important}.leaflet-container .leaflet-marker-pane img,.leaflet-container .leaflet-shadow-pane img,.leaflet-container .leaflet-tile-pane img,.leaflet-container img.leaflet-image-layer,.leaflet-container .leaflet-tile{max-width:none!important;max-height:none!important;width:auto;padding:0}.leaflet-container img.leaflet-tile{mix-blend-mode:plus-lighter}.leaflet-container.leaflet-touch-zoom{touch-action:pan-x pan-y}.leaflet-container.leaflet-touch-drag{touch-action:none;touch-action:pinch-zoom}.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom{touch-action:none}.leaflet-container{-webkit-tap-highlight-color:transparent}.leaflet-container a{-webkit-tap-highlight-color:rgba(51,181,229,.4)}.leaflet-tile{filter:inherit;visibility:hidden}.leaflet-tile-loaded{visibility:inherit}.leaflet-zoom-box{width:0;height:0;box-sizing:border-box;z-index:800}.leaflet-overlay-pane svg{-moz-user-select:none}.leaflet-pane{z-index:400}.leaflet-tile-pane{z-index:200}.leaflet-overlay-pane{z-index:400}.leaflet-shadow-pane{z-index:500}.leaflet-marker-pane{z-index:600}.leaflet-tooltip-pane{z-index:650}.leaflet-popup-pane{z-index:700}.leaflet-map-pane canvas{z-index:100}.leaflet-map-pane svg{z-index:200}.leaflet-vml-shape{width:1px;height:1px}.lvml{behavior:url(#default#VML);display:inline-block;position:absolute}.leaflet-control{position:relative;z-index:800;pointer-events:visiblePainted;pointer-events:auto}.leaflet-top,.leaflet-bottom{position:absolute;z-index:1000;pointer-events:none}.leaflet-top{top:0}.leaflet-right{right:0}.leaflet-bottom{bottom:0}.leaflet-left{left:0}.leaflet-control{float:left;clear:both}.leaflet-right .leaflet-control{float:right}.leaflet-top .leaflet-control{margin-top:10px}.leaflet-bottom .leaflet-control{margin-bottom:10px}.leaflet-left .leaflet-control{margin-left:10px}.leaflet-right .leaflet-control{margin-right:10px}.leaflet-fade-anim .leaflet-popup{opacity:0;transition:opacity .2s linear}.leaflet-fade-anim .leaflet-map-pane .leaflet-popup{opacity:1}.leaflet-zoom-animated{transform-origin:0 0}svg.leaflet-zoom-animated{will-change:transform}.leaflet-zoom-anim .leaflet-zoom-animated{transition:transform .25s cubic-bezier(0,0,.25,1)}.leaflet-zoom-anim .leaflet-tile,.leaflet-pan-anim .leaflet-tile{transition:none}.leaflet-zoom-anim .leaflet-zoom-hide{visibility:hidden}.leaflet-interactive{cursor:pointer}.leaflet-grab{cursor:grab}.leaflet-crosshair,.leaflet-crosshair .leaflet-interactive{cursor:crosshair}.leaflet-popup-pane,.leaflet-control{cursor:auto}.leaflet-dragging .leaflet-grab,.leaflet-dragging .leaflet-grab .leaflet-interactive,.leaflet-dragging .leaflet-marker-draggable{cursor:move;cursor:grabbing}.leaflet-marker-icon,.leaflet-marker-shadow,.leaflet-image-layer,.leaflet-pane>svg path,.leaflet-tile-container{pointer-events:none}.leaflet-marker-icon.leaflet-interactive,.leaflet-image-layer.leaflet-interactive,.leaflet-pane>svg path.leaflet-interactive,svg.leaflet-image-layer.leaflet-interactive path{pointer-events:visiblePainted;pointer-events:auto}.leaflet-container{background:#ddd;outline-offset:1px}.leaflet-container a{color:#0078a8}.leaflet-zoom-box{border:2px dotted #38f;background:#ffffff80}.leaflet-container{font-family:Helvetica Neue,Arial,Helvetica,sans-serif;font-size:12px;font-size:.75rem;line-height:1.5}.leaflet-bar{box-shadow:0 1px 5px #000000a6;border-radius:4px}.leaflet-bar a{background-color:#fff;border-bottom:1px solid #ccc;width:26px;height:26px;line-height:26px;display:block;text-align:center;text-decoration:none;color:#000}.leaflet-bar a,.leaflet-control-layers-toggle{background-position:50% 50%;background-repeat:no-repeat;display:block}.leaflet-bar a:hover,.leaflet-bar a:focus{background-color:#f4f4f4}.leaflet-bar a:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.leaflet-bar a:last-child{border-bottom-left-radius:4px;border-bottom-right-radius:4px;border-bottom:none}.leaflet-bar a.leaflet-disabled{cursor:default;background-color:#f4f4f4;color:#bbb}.leaflet-touch .leaflet-bar a{width:30px;height:30px;line-height:30px}.leaflet-touch .leaflet-bar a:first-child{border-top-left-radius:2px;border-top-right-radius:2px}.leaflet-touch .leaflet-bar a:last-child{border-bottLine truncated
.leaflet-pane,.leaflet-tile,.leaflet-marker-icon,.leaflet-marker-shadow,.leaflet-tile-container,.leaflet-pane>svg,.leaflet-pane>canvas,.leaflet-zoom-box,.leaflet-image-layer,.leaflet-layer{position:absolute;left:0;top:0}.leaflet-container{overflow:hidden}.leaflet-tile,.leaflet-marker-icon,.leaflet-marker-shadow{-webkit-user-select:none;-moz-user-select:none;user-select:none;-webkit-user-drag:none}.leaflet-tile::-moz-selection{background:transparent}.leaflet-tile::selection{background:transparent}.leaflet-safari .leaflet-tile{image-rendering:-webkit-optimize-contrast}.leaflet-safari .leaflet-tile-container{width:1600px;height:1600px;-webkit-transform-origin:0 0}.leaflet-marker-icon,.leaflet-marker-shadow{display:block}.leaflet-container .leaflet-overlay-pane svg{max-width:none!important;max-height:none!important}.leaflet-container .leaflet-marker-pane img,.leaflet-container .leaflet-shadow-pane img,.leaflet-container .leaflet-tile-pane img,.leaflet-container img.leaflet-image-layer,.leaflet-container .leaflet-tile{max-width:none!important;max-height:none!important;width:auto;padding:0}.leaflet-container img.leaflet-tile{mix-blend-mode:plus-lighter}.leaflet-container.leaflet-touch-zoom{touch-action:pan-x pan-y}.leaflet-container.leaflet-touch-drag{touch-action:none;touch-action:pinch-zoom}.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom{touch-action:none}.leaflet-container{-webkit-tap-highlight-color:transparent}.leaflet-container a{-webkit-tap-highlight-color:rgba(51,181,229,.4)}.leaflet-tile{filter:inherit;visibility:hidden}.leaflet-tile-loaded{visibility:inherit}.leaflet-zoom-box{width:0;height:0;box-sizing:border-box;z-index:800}.leaflet-overlay-pane svg{-moz-user-select:none}.leaflet-pane{z-index:400}.leaflet-tile-pane{z-index:200}.leaflet-overlay-pane{z-index:400}.leaflet-shadow-pane{z-index:500}.leaflet-marker-pane{z-index:600}.leaflet-tooltip-pane{z-index:650}.leaflet-popup-pane{z-index:700}.leaflet-map-pane canvas{z-index:100}.leaflet-map-pane svg{z-index:200}.leaflet-vml-shape{width:1px;height:1px}.lvml{behavior:url(#default#VML);display:inline-block;position:absolute}.leaflet-control{position:relative;z-index:800;pointer-events:visiblePainted;pointer-events:auto}.leaflet-top,.leaflet-bottom{position:absolute;z-index:1000;pointer-events:none}.leaflet-top{top:0}.leaflet-right{right:0}.leaflet-bottom{bottom:0}.leaflet-left{left:0}.leaflet-control{float:left;clear:both}.leaflet-right .leaflet-control{float:right}.leaflet-top .leaflet-control{margin-top:10px}.leaflet-bottom .leaflet-control{margin-bottom:10px}.leaflet-left .leaflet-control{margin-left:10px}.leaflet-right .leaflet-control{margin-right:10px}.leaflet-fade-anim .leaflet-popup{opacity:0;transition:opacity .2s linear}.leaflet-fade-anim .leaflet-map-pane .leaflet-popup{opacity:1}.leaflet-zoom-animated{transform-origin:0 0}svg.leaflet-zoom-animated{will-change:transform}.leaflet-zoom-anim .leaflet-zoom-animated{transition:transform .25s cubic-bezier(0,0,.25,1)}.leaflet-zoom-anim .leaflet-tile,.leaflet-pan-anim .leaflet-tile{transition:none}.leaflet-zoom-anim .leaflet-zoom-hide{visibility:hidden}.leaflet-interactive{cursor:pointer}.leaflet-grab{cursor:grab}.leaflet-crosshair,.leaflet-crosshair .leaflet-interactive{cursor:crosshair}.leaflet-popup-pane,.leaflet-control{cursor:auto}.leaflet-dragging .leaflet-grab,.leaflet-dragging .leaflet-grab .leaflet-interactive,.leaflet-dragging .leaflet-marker-draggable{cursor:move;cursor:grabbing}.leaflet-marker-icon,.leaflet-marker-shadow,.leaflet-image-layer,.leaflet-pane>svg path,.leaflet-tile-container{pointer-events:none}.leaflet-marker-icon.leaflet-interactive,.leaflet-image-layer.leaflet-interactive,.leaflet-pane>svg path.leaflet-interactive,svg.leaflet-image-layer.leaflet-interactive path{pointer-events:visiblePainted;pointer-events:auto}.leaflet-container{background:#ddd;outline-offset:1px}.leaflet-container a{color:#0078a8}.leaflet-zoom-box{border:2px dotted #38f;background:#ffffff80}.leaflet-container{font-family:Helvetica Neue,Arial,Helvetica,sans-serif;font-size:12px;font-size:.75rem;line-height:1.5}.leaflet-bar{box-shadow:0 1px 5px #000000a6;border-radius:4px}.leaflet-bar a{background-color:#fff;border-bottom:1px solid #ccc;width:26px;height:26px;line-height:26px;display:block;text-align:center;text-decoration:none;color:#000}.leaflet-bar a,.leaflet-control-layers-toggle{background-position:50% 50%;background-repeat:no-repeat;display:block}.leaflet-bar a:hover,.leaflet-bar a:focus{background-color:#f4f4f4}.leaflet-bar a:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.leaflet-bar a:last-child{border-bottom-left-radius:4px;border-bottom-right-radius:4px;border-bottom:none}.leaflet-bar a.leaflet-disabled{cursor:default;background-color:#f4f4f4;color:#bbb}.leaflet-touch .leaflet-bar a{width:30px;height:30px;line-height:30px}.leaflet-touch .leaflet-bar a:first-child{border-top-left-radius:2px;border-top-right-radius:2px}.leaflet-touch .leaflet-bar a:last-child{border-bottLine truncated
+2 -2
View File
@@ -13,8 +13,8 @@
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="manifest" href="/site.webmanifest" />
<script type="module" crossorigin src="/assets/index-DRuKVg0T.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-D9NEpiho.css">
<script type="module" crossorigin src="/assets/index-DlEnSqQ7.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-aLTdJARH.css">
</head>
<body>
<div id="root"></div>
+1
View File
@@ -705,6 +705,7 @@ export function App() {
}
onLoadOlder={fetchOlderMessages}
radioName={config?.name}
config={config}
/>
<MessageInput
ref={messageInputRef}
+91 -4
View File
@@ -1,9 +1,11 @@
import { useEffect, useLayoutEffect, useRef, useCallback, useState, type ReactNode } from 'react';
import type { Contact, Message } from '../types';
import type { Contact, Message, RadioConfig } from '../types';
import { CONTACT_TYPE_REPEATER } from '../types';
import { formatTime, parseSenderFromText } from '../utils/messageParser';
import { pubkeysMatch } from '../utils/pubkey';
import { getHopCount, type SenderInfo } from '../utils/pathUtils';
import { ContactAvatar } from './ContactAvatar';
import { PathModal } from './PathModal';
import { cn } from '@/lib/utils';
interface MessageListProps {
@@ -15,6 +17,7 @@ interface MessageListProps {
onSenderClick?: (sender: string) => void;
onLoadOlder?: () => void;
radioName?: string;
config?: RadioConfig | null;
}
// Helper to render text with highlighted @[Name] mentions
@@ -68,11 +71,16 @@ export function MessageList({
onSenderClick,
onLoadOlder,
radioName,
config,
}: MessageListProps) {
const listRef = useRef<HTMLDivElement>(null);
const prevMessagesLengthRef = useRef<number>(0);
const isInitialLoadRef = useRef<boolean>(true);
const [showScrollToBottom, setShowScrollToBottom] = useState(false);
const [selectedPath, setSelectedPath] = useState<{
path: string;
senderInfo: SenderInfo;
} | null>(null);
// Capture scroll state in the scroll handler BEFORE any state updates
const scrollStateRef = useRef({
@@ -170,6 +178,41 @@ export function MessageList({
return contacts.find((c) => c.name === name) || null;
};
// Build sender info for path modal
const getSenderInfo = (
msg: Message,
contact: Contact | null,
parsedSender: string | null
): SenderInfo => {
if (msg.type === 'PRIV' && contact) {
return {
name: contact.name || contact.public_key.slice(0, 12),
publicKeyOrPrefix: contact.public_key,
lat: contact.lat,
lon: contact.lon,
};
}
// For channel messages, try to find contact by parsed sender name
if (parsedSender) {
const senderContact = getContactByName(parsedSender);
if (senderContact) {
return {
name: parsedSender,
publicKeyOrPrefix: senderContact.public_key,
lat: senderContact.lat,
lon: senderContact.lon,
};
}
}
// Fallback: unknown sender
return {
name: parsedSender || 'Unknown',
publicKeyOrPrefix: msg.conversation_key || '',
lat: null,
lon: null,
};
};
if (loading) {
return (
<div className="flex-1 overflow-y-auto p-5 text-center text-muted-foreground">
@@ -293,6 +336,21 @@ export function MessageList({
<span className="font-normal text-muted-foreground/70 ml-2 text-[11px]">
{formatTime(msg.sender_timestamp || msg.received_at)}
</span>
{!msg.outgoing && msg.path && (
<span
className="font-normal text-muted-foreground/70 ml-1 text-[11px] cursor-pointer hover:text-primary hover:underline"
onClick={(e) => {
e.stopPropagation();
setSelectedPath({
path: msg.path!,
senderInfo: getSenderInfo(msg, contact, sender),
});
}}
title="View message path"
>
({getHopCount(msg.path)} hop{getHopCount(msg.path) !== 1 ? 's' : ''})
</span>
)}
</div>
)}
<div className="break-words whitespace-pre-wrap">
@@ -303,9 +361,26 @@ export function MessageList({
</span>
))}
{!showAvatar && (
<span className="text-[10px] text-muted-foreground/50 ml-2">
{formatTime(msg.sender_timestamp || msg.received_at)}
</span>
<>
<span className="text-[10px] text-muted-foreground/50 ml-2">
{formatTime(msg.sender_timestamp || msg.received_at)}
</span>
{!msg.outgoing && msg.path && (
<span
className="text-[10px] text-muted-foreground/50 ml-1 cursor-pointer hover:text-primary hover:underline"
onClick={(e) => {
e.stopPropagation();
setSelectedPath({
path: msg.path!,
senderInfo: getSenderInfo(msg, contact, sender),
});
}}
title="View message path"
>
({getHopCount(msg.path)} hop{getHopCount(msg.path) !== 1 ? 's' : ''})
</span>
)}
</>
)}
{msg.outgoing && (msg.acked > 0 ? ` ✓${msg.acked > 1 ? msg.acked : ''}` : ' ?')}
</div>
@@ -338,6 +413,18 @@ export function MessageList({
</svg>
</button>
)}
{/* Path modal */}
{selectedPath && (
<PathModal
open={true}
onClose={() => setSelectedPath(null)}
path={selectedPath.path}
senderInfo={selectedPath.senderInfo}
contacts={contacts}
config={config ?? null}
/>
)}
</div>
);
}
+284
View File
@@ -0,0 +1,284 @@
import type { Contact, RadioConfig } from '../types';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogFooter,
} from './ui/dialog';
import { Button } from './ui/button';
import {
resolvePath,
calculateDistance,
isValidLocation,
type SenderInfo,
type ResolvedPath,
type PathHop,
} from '../utils/pathUtils';
interface PathModalProps {
open: boolean;
onClose: () => void;
path: string;
senderInfo: SenderInfo;
contacts: Contact[];
config: RadioConfig | null;
}
export function PathModal({ open, onClose, path, senderInfo, contacts, config }: PathModalProps) {
const resolved = resolvePath(path, senderInfo, contacts, config);
return (
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && onClose()}>
<DialogContent className="max-w-md max-h-[80vh] flex flex-col">
<DialogHeader>
<DialogTitle>Message Path</DialogTitle>
<DialogDescription>
This shows <em>one route</em> that this message traveled through the mesh network. Flood
messages may arrive via multiple paths, and routers may be incorrectly identified due to
prefix collisions between heard and non-heard router advertisements.
</DialogDescription>
</DialogHeader>
<div className="flex-1 overflow-y-auto py-2">
<PathVisualization resolved={resolved} />
</div>
<DialogFooter>
<Button onClick={onClose}>Close</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
interface PathVisualizationProps {
resolved: ResolvedPath;
}
function PathVisualization({ resolved }: PathVisualizationProps) {
// Track previous location for each hop to calculate distances
// Returns null if previous hop was ambiguous or has invalid location
const getPrevLocation = (hopIndex: number): { lat: number | null; lon: number | null } | null => {
if (hopIndex === 0) {
// Check if sender has valid location
if (!isValidLocation(resolved.sender.lat, resolved.sender.lon)) {
return null;
}
return { lat: resolved.sender.lat, lon: resolved.sender.lon };
}
const prevHop = resolved.hops[hopIndex - 1];
// If previous hop was ambiguous, we can't show meaningful distances
if (prevHop.matches.length > 1) {
return null;
}
// If previous hop was unknown, we also can't calculate
if (prevHop.matches.length === 0) {
return null;
}
// Check if previous hop has valid location
if (isValidLocation(prevHop.matches[0].lat, prevHop.matches[0].lon)) {
return { lat: prevHop.matches[0].lat, lon: prevHop.matches[0].lon };
}
return null;
};
return (
<div className="space-y-0">
{/* Sender */}
<PathNode
label="Sender"
name={resolved.sender.name}
prefix={resolved.sender.prefix}
distance={null}
isFirst
/>
{/* Hops */}
{resolved.hops.map((hop, index) => (
<HopNode
key={index}
hop={hop}
hopNumber={index + 1}
prevLocation={getPrevLocation(index)}
/>
))}
{/* Receiver */}
<PathNode
label="Receiver (me)"
name={resolved.receiver.name}
prefix={resolved.receiver.prefix}
distance={calculateReceiverDistance(resolved)}
isLast
/>
{/* Total distance */}
{resolved.totalDistances && resolved.totalDistances.length > 0 && (
<div className="pt-3 mt-3 border-t border-border">
<span className="text-sm text-muted-foreground">
Presumed unambiguous distance covered:{' '}
</span>
<span className="text-sm font-medium">{formatDistance(resolved.totalDistances[0])}</span>
</div>
)}
</div>
);
}
interface PathNodeProps {
label: string;
name: string;
prefix: string;
distance: number | null;
isFirst?: boolean;
isLast?: boolean;
}
function PathNode({ label, name, prefix, distance, isFirst, isLast }: PathNodeProps) {
return (
<div className="flex gap-3">
{/* Vertical line and dot column */}
<div className="flex flex-col items-center w-4 flex-shrink-0">
{!isFirst && <div className="w-0.5 h-3 bg-border" />}
<div className="w-3 h-3 rounded-full bg-primary flex-shrink-0" />
{!isLast && <div className="w-0.5 flex-1 bg-border" />}
</div>
{/* Content */}
<div className="pb-3 flex-1 min-w-0">
<div className="text-xs text-muted-foreground font-medium">{label}</div>
<div className="font-medium truncate">
{name} <span className="text-muted-foreground font-mono text-sm">({prefix})</span>
</div>
{distance !== null && (
<div className="text-xs text-muted-foreground">{formatDistance(distance)}</div>
)}
</div>
</div>
);
}
interface HopNodeProps {
hop: PathHop;
hopNumber: number;
prevLocation: { lat: number | null; lon: number | null } | null;
}
function HopNode({ hop, hopNumber, prevLocation }: HopNodeProps) {
const isAmbiguous = hop.matches.length > 1;
const isUnknown = hop.matches.length === 0;
// Calculate distance from previous location for a contact
// Returns null if prev location unknown/ambiguous or contact has no valid location
const getDistanceForContact = (contact: {
lat: number | null;
lon: number | null;
}): number | null => {
if (!prevLocation || prevLocation.lat === null || prevLocation.lon === null) {
return null;
}
// Check if contact has valid location
if (!isValidLocation(contact.lat, contact.lon)) {
return null;
}
return calculateDistance(prevLocation.lat, prevLocation.lon, contact.lat, contact.lon);
};
return (
<div className="flex gap-3">
{/* Vertical line and dot column */}
<div className="flex flex-col items-center w-4 flex-shrink-0">
<div className="w-0.5 h-3 bg-border" />
<div className="w-3 h-3 rounded-full bg-muted-foreground flex-shrink-0" />
<div className="w-0.5 flex-1 bg-border" />
</div>
{/* Content */}
<div className="pb-3 flex-1 min-w-0">
<div className="text-xs text-muted-foreground font-medium">
Hop {hopNumber}
{isAmbiguous && <span className="text-yellow-500 ml-1">(ambiguous)</span>}
</div>
{isUnknown ? (
<div className="font-medium text-muted-foreground/70">
&lt;UNKNOWN <span className="font-mono text-sm">{hop.prefix}</span>&gt;
</div>
) : isAmbiguous ? (
<div>
{hop.matches.map((contact) => {
const dist = getDistanceForContact(contact);
return (
<div key={contact.public_key} className="font-medium truncate">
{contact.name || contact.public_key.slice(0, 12)}{' '}
<span className="text-muted-foreground font-mono text-sm">
({contact.public_key.slice(0, 2).toUpperCase()})
</span>
{dist !== null && (
<span className="text-xs text-muted-foreground ml-1">
- {formatDistance(dist)}
</span>
)}
</div>
);
})}
</div>
) : (
<div className="font-medium truncate">
{hop.matches[0].name || hop.matches[0].public_key.slice(0, 12)}{' '}
<span className="text-muted-foreground font-mono text-sm">({hop.prefix})</span>
{hop.distanceFromPrev !== null && (
<span className="text-xs text-muted-foreground ml-1">
- {formatDistance(hop.distanceFromPrev)}
</span>
)}
</div>
)}
</div>
</div>
);
}
function formatDistance(km: number): string {
if (km < 1) {
return `${Math.round(km * 1000)}m`;
}
return `${km.toFixed(1)}km`;
}
function calculateReceiverDistance(resolved: ResolvedPath): number | null {
// Get last hop's location (if any)
let prevLat: number | null = null;
let prevLon: number | null = null;
if (resolved.hops.length > 0) {
const lastHop = resolved.hops[resolved.hops.length - 1];
// Only use last hop if it's unambiguous and has valid location
if (
lastHop.matches.length === 1 &&
isValidLocation(lastHop.matches[0].lat, lastHop.matches[0].lon)
) {
prevLat = lastHop.matches[0].lat;
prevLon = lastHop.matches[0].lon;
}
} else {
// No hops, calculate from sender to receiver (if sender has valid location)
if (isValidLocation(resolved.sender.lat, resolved.sender.lon)) {
prevLat = resolved.sender.lat;
prevLon = resolved.sender.lon;
}
}
if (prevLat === null || prevLon === null) {
return null;
}
// Check receiver has valid location
if (!isValidLocation(resolved.receiver.lat, resolved.receiver.lon)) {
return null;
}
return calculateDistance(prevLat, prevLon, resolved.receiver.lat, resolved.receiver.lon);
}
+476
View File
@@ -0,0 +1,476 @@
import { describe, it, expect } from 'vitest';
import {
parsePathHops,
findContactsByPrefix,
calculateDistance,
sortContactsByDistance,
getHopCount,
resolvePath,
} from '../utils/pathUtils';
import type { Contact, RadioConfig } from '../types';
import { CONTACT_TYPE_REPEATER, CONTACT_TYPE_CLIENT } from '../types';
// Helper to create mock contacts
function createContact(overrides: Partial<Contact> = {}): Contact {
return {
public_key: 'AAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCDDDDDDDDDDDDEEEEEEEEEEEE',
name: 'Test Contact',
type: CONTACT_TYPE_REPEATER,
flags: 0,
last_path: null,
last_path_len: -1,
last_advert: null,
lat: null,
lon: null,
last_seen: null,
on_radio: false,
last_contacted: null,
last_read_at: null,
...overrides,
};
}
// Helper to create mock config
function createConfig(overrides: Partial<RadioConfig> = {}): RadioConfig {
return {
public_key: 'FFFFFFFFFFFFEEEEEEEEEEEEDDDDDDDDDDDDCCCCCCCCCCCCBBBBBBBBBBBB',
name: 'MyRadio',
lat: 40.7128,
lon: -74.006,
tx_power: 10,
max_tx_power: 20,
radio: { freq: 915, bw: 250, sf: 10, cr: 8 },
...overrides,
};
}
describe('parsePathHops', () => {
it('returns empty array for null/empty path', () => {
expect(parsePathHops(null)).toEqual([]);
expect(parsePathHops(undefined)).toEqual([]);
expect(parsePathHops('')).toEqual([]);
});
it('parses single hop', () => {
expect(parsePathHops('1A')).toEqual(['1A']);
});
it('parses multiple hops', () => {
expect(parsePathHops('1A2B3C')).toEqual(['1A', '2B', '3C']);
});
it('converts to uppercase', () => {
expect(parsePathHops('1a2b')).toEqual(['1A', '2B']);
});
it('handles odd length by ignoring last character', () => {
expect(parsePathHops('1A2B3')).toEqual(['1A', '2B']);
});
});
describe('findContactsByPrefix', () => {
const contacts: Contact[] = [
createContact({
public_key: '1AAAAA' + 'A'.repeat(52),
name: 'Repeater1',
type: CONTACT_TYPE_REPEATER,
}),
createContact({
public_key: '1ABBBB' + 'B'.repeat(52),
name: 'Repeater2',
type: CONTACT_TYPE_REPEATER,
}),
createContact({
public_key: '2BAAAA' + 'A'.repeat(52),
name: 'Repeater3',
type: CONTACT_TYPE_REPEATER,
}),
createContact({
public_key: '1ACCCC' + 'C'.repeat(52),
name: 'Client1',
type: CONTACT_TYPE_CLIENT,
}),
];
it('finds matching repeaters', () => {
const matches = findContactsByPrefix('1A', contacts, true);
expect(matches).toHaveLength(2);
expect(matches.map((c) => c.name)).toContain('Repeater1');
expect(matches.map((c) => c.name)).toContain('Repeater2');
});
it('returns empty array for no match', () => {
expect(findContactsByPrefix('XX', contacts, true)).toEqual([]);
});
it('is case insensitive', () => {
expect(findContactsByPrefix('1a', contacts, true)).toHaveLength(2);
});
it('excludes non-repeaters when repeatersOnly is true', () => {
const matches = findContactsByPrefix('1A', contacts, true);
expect(matches.every((c) => c.type === CONTACT_TYPE_REPEATER)).toBe(true);
expect(matches.map((c) => c.name)).not.toContain('Client1');
});
it('includes all types when repeatersOnly is false', () => {
const matches = findContactsByPrefix('1A', contacts, false);
expect(matches).toHaveLength(3);
expect(matches.map((c) => c.name)).toContain('Client1');
});
});
describe('calculateDistance', () => {
it('returns null for null coordinates', () => {
expect(calculateDistance(null, 0, 0, 0)).toBeNull();
expect(calculateDistance(0, null, 0, 0)).toBeNull();
expect(calculateDistance(0, 0, null, 0)).toBeNull();
expect(calculateDistance(0, 0, 0, null)).toBeNull();
});
it('returns 0 for same point', () => {
expect(calculateDistance(40.7128, -74.006, 40.7128, -74.006)).toBe(0);
});
it('calculates known distances approximately correctly', () => {
// NYC (40.7128, -74.0060) to LA (34.0522, -118.2437) is approximately 3944 km
const distance = calculateDistance(40.7128, -74.006, 34.0522, -118.2437);
expect(distance).not.toBeNull();
expect(distance).toBeGreaterThan(3900);
expect(distance).toBeLessThan(4000);
});
it('handles short distances', () => {
// About 1km apart in NYC
const distance = calculateDistance(40.7128, -74.006, 40.7218, -74.006);
expect(distance).not.toBeNull();
expect(distance).toBeGreaterThan(0.9);
expect(distance).toBeLessThan(1.1);
});
});
describe('sortContactsByDistance', () => {
const contactClose = createContact({
public_key: 'AA' + 'A'.repeat(62),
name: 'Close',
lat: 40.7228,
lon: -74.006,
});
const contactFar = createContact({
public_key: 'BB' + 'B'.repeat(62),
name: 'Far',
lat: 40.9,
lon: -74.006,
});
const contactNoLocation = createContact({
public_key: 'CC' + 'C'.repeat(62),
name: 'NoLoc',
lat: null,
lon: null,
});
it('sorts by distance ascending', () => {
const sorted = sortContactsByDistance([contactFar, contactClose], 40.7128, -74.006);
expect(sorted[0].name).toBe('Close');
expect(sorted[1].name).toBe('Far');
});
it('places contacts without location at end', () => {
const sorted = sortContactsByDistance(
[contactNoLocation, contactClose, contactFar],
40.7128,
-74.006
);
expect(sorted[0].name).toBe('Close');
expect(sorted[1].name).toBe('Far');
expect(sorted[2].name).toBe('NoLoc');
});
it('returns unsorted if reference is null', () => {
const contacts = [contactFar, contactClose];
const sorted = sortContactsByDistance(contacts, null, -74.006);
expect(sorted[0].name).toBe(contacts[0].name);
});
});
describe('getHopCount', () => {
it('returns 0 for null/empty', () => {
expect(getHopCount(null)).toBe(0);
expect(getHopCount(undefined)).toBe(0);
expect(getHopCount('')).toBe(0);
});
it('counts hops correctly', () => {
expect(getHopCount('1A')).toBe(1);
expect(getHopCount('1A2B')).toBe(2);
expect(getHopCount('1A2B3C')).toBe(3);
});
});
describe('resolvePath', () => {
const repeater1 = createContact({
public_key: '1A' + 'A'.repeat(62),
name: 'Repeater1',
type: CONTACT_TYPE_REPEATER,
lat: 40.75,
lon: -74.0,
});
const repeater2 = createContact({
public_key: '2B' + 'B'.repeat(62),
name: 'Repeater2',
type: CONTACT_TYPE_REPEATER,
lat: 40.8,
lon: -73.95,
});
const contacts = [repeater1, repeater2];
const sender = {
name: 'Sender',
publicKeyOrPrefix: '5E' + 'E'.repeat(62),
lat: 40.7,
lon: -74.05,
};
const config = createConfig({
public_key: 'FF' + 'F'.repeat(62),
name: 'MyRadio',
lat: 40.85,
lon: -73.9,
});
it('resolves simple path with known repeaters', () => {
const result = resolvePath('1A2B', sender, contacts, config);
expect(result.sender.name).toBe('Sender');
expect(result.sender.prefix).toBe('5E');
expect(result.hops).toHaveLength(2);
expect(result.hops[0].prefix).toBe('1A');
expect(result.hops[0].matches).toHaveLength(1);
expect(result.hops[0].matches[0].name).toBe('Repeater1');
expect(result.hops[1].prefix).toBe('2B');
expect(result.hops[1].matches).toHaveLength(1);
expect(result.hops[1].matches[0].name).toBe('Repeater2');
expect(result.receiver.name).toBe('MyRadio');
expect(result.receiver.prefix).toBe('FF');
});
it('handles unknown repeaters (no matches)', () => {
const result = resolvePath('XX', sender, contacts, config);
expect(result.hops).toHaveLength(1);
expect(result.hops[0].prefix).toBe('XX');
expect(result.hops[0].matches).toHaveLength(0);
});
it('handles ambiguous repeaters (multiple matches)', () => {
// Create two repeaters with same prefix
const ambiguousContacts = [
createContact({
public_key: '1A' + 'A'.repeat(62),
name: 'Repeater1A',
type: CONTACT_TYPE_REPEATER,
lat: 40.75,
lon: -74.0,
}),
createContact({
public_key: '1A' + 'B'.repeat(62),
name: 'Repeater1B',
type: CONTACT_TYPE_REPEATER,
lat: 40.76,
lon: -73.99,
}),
];
const result = resolvePath('1A', sender, ambiguousContacts, config);
expect(result.hops).toHaveLength(1);
expect(result.hops[0].matches).toHaveLength(2);
// Should be sorted by distance from sender
expect(result.hops[0].matches[0].name).toBe('Repeater1A');
});
it('calculates total distance when all locations known', () => {
const result = resolvePath('1A2B', sender, contacts, config);
expect(result.totalDistances).not.toBeNull();
expect(result.totalDistances!.length).toBeGreaterThan(0);
expect(result.totalDistances![0]).toBeGreaterThan(0);
});
it('returns null totalDistances when locations unknown', () => {
const unknownRepeater = createContact({
public_key: 'XX' + 'X'.repeat(62),
name: 'Unknown',
type: CONTACT_TYPE_REPEATER,
lat: null,
lon: null,
});
const result = resolvePath('XX', sender, [unknownRepeater], config);
expect(result.totalDistances).toBeNull();
});
it('handles empty path', () => {
const result = resolvePath('', sender, contacts, config);
expect(result.hops).toHaveLength(0);
expect(result.sender.name).toBe('Sender');
expect(result.receiver.name).toBe('MyRadio');
});
it('handles null config gracefully', () => {
const result = resolvePath('1A', sender, contacts, null);
expect(result.receiver.name).toBe('Unknown');
expect(result.receiver.prefix).toBe('??');
});
it('excludes receiver distance when receiver location is (0, 0)', () => {
const configAtOrigin = createConfig({
public_key: 'FF' + 'F'.repeat(62),
name: 'MyRadio',
lat: 0,
lon: 0,
});
const result = resolvePath('1A', sender, contacts, configAtOrigin);
// Total distance should NOT include the final leg to receiver
// It should only be sender -> repeater1
expect(result.totalDistances).not.toBeNull();
const senderToRepeater = calculateDistance(
sender.lat,
sender.lon,
repeater1.lat,
repeater1.lon
);
expect(result.totalDistances![0]).toBeCloseTo(senderToRepeater!, 1);
});
it('skips distance after ambiguous hops', () => {
// Create two repeaters with same prefix (ambiguous)
const ambiguousContacts = [
createContact({
public_key: '1A' + 'A'.repeat(62),
name: 'Repeater1A',
type: CONTACT_TYPE_REPEATER,
lat: 40.75,
lon: -74.0,
}),
createContact({
public_key: '1A' + 'B'.repeat(62),
name: 'Repeater1B',
type: CONTACT_TYPE_REPEATER,
lat: 40.76,
lon: -73.99,
}),
// Known repeater after the ambiguous one
createContact({
public_key: '2B' + 'B'.repeat(62),
name: 'Repeater2',
type: CONTACT_TYPE_REPEATER,
lat: 40.8,
lon: -73.95,
}),
];
const result = resolvePath('1A2B', sender, ambiguousContacts, config);
// First hop is ambiguous, second hop is known
expect(result.hops[0].matches).toHaveLength(2);
expect(result.hops[1].matches).toHaveLength(1);
// First hop is ambiguous, so no single distanceFromPrev
// (UI shows individual distances for each match via getDistanceForContact)
expect(result.hops[0].distanceFromPrev).toBeNull();
// Second hop should also NOT have distanceFromPrev because previous hop was ambiguous
expect(result.hops[1].distanceFromPrev).toBeNull();
});
it('calculates partial distance when sender has no location', () => {
const senderNoLocation = {
name: 'SenderNoLoc',
publicKeyOrPrefix: '5E' + 'E'.repeat(62),
lat: null,
lon: null,
};
const result = resolvePath('1A2B', senderNoLocation, contacts, config);
// First hop has no distance (can't calculate from unknown sender location)
expect(result.hops[0].distanceFromPrev).toBeNull();
// Second hop has distance (from first hop to second hop)
expect(result.hops[1].distanceFromPrev).not.toBeNull();
// Total distance should start from first known hop
expect(result.totalDistances).not.toBeNull();
expect(result.totalDistances![0]).toBeGreaterThan(0);
});
it('returns null totalDistances when all hops have no location', () => {
const noLocationContacts = [
createContact({
public_key: '1A' + 'A'.repeat(62),
name: 'NoLoc1',
type: CONTACT_TYPE_REPEATER,
lat: null,
lon: null,
}),
createContact({
public_key: '2B' + 'B'.repeat(62),
name: 'NoLoc2',
type: CONTACT_TYPE_REPEATER,
lat: null,
lon: null,
}),
];
const senderNoLocation = {
name: 'SenderNoLoc',
publicKeyOrPrefix: '5E' + 'E'.repeat(62),
lat: null,
lon: null,
};
const result = resolvePath('1A2B', senderNoLocation, noLocationContacts, config);
expect(result.totalDistances).toBeNull();
});
it('treats contact at (0, 0) as having no location', () => {
const contactAtOrigin = createContact({
public_key: '1A' + 'A'.repeat(62),
name: 'AtOrigin',
type: CONTACT_TYPE_REPEATER,
lat: 0,
lon: 0,
});
const result = resolvePath('1A', sender, [contactAtOrigin], config);
// Hop should match but have no distance (0, 0 treated as invalid)
expect(result.hops).toHaveLength(1);
expect(result.hops[0].matches).toHaveLength(1);
expect(result.hops[0].distanceFromPrev).toBeNull();
});
it('treats sender at (0, 0) as having no location', () => {
const senderAtOrigin = {
name: 'SenderAtOrigin',
publicKeyOrPrefix: '5E' + 'E'.repeat(62),
lat: 0,
lon: 0,
};
const result = resolvePath('1A2B', senderAtOrigin, contacts, config);
// First hop should have no distance (sender at 0,0 treated as invalid)
expect(result.hops[0].distanceFromPrev).toBeNull();
// But second hop CAN have distance (from first hop)
expect(result.hops[1].distanceFromPrev).not.toBeNull();
});
});
+325
View File
@@ -0,0 +1,325 @@
import type { Contact, RadioConfig } from '../types';
import { CONTACT_TYPE_REPEATER } from '../types';
export interface PathHop {
prefix: string; // 2-char hex prefix (e.g., "1A")
matches: Contact[]; // Matched repeaters (empty=unknown, multiple=ambiguous)
distanceFromPrev: number | null; // km from previous hop
}
export interface ResolvedPath {
sender: { name: string; prefix: string; lat: number | null; lon: number | null };
hops: PathHop[];
receiver: { name: string; prefix: string; lat: number | null; lon: number | null };
totalDistances: number[] | null; // Single-element array with sum of unambiguous distances
}
export interface SenderInfo {
name: string;
publicKeyOrPrefix: string;
lat: number | null;
lon: number | null;
}
/**
* Split hex string into 2-char hops
*/
export function parsePathHops(path: string | null | undefined): string[] {
if (!path || path.length === 0) {
return [];
}
const normalized = path.toUpperCase();
const hops: string[] = [];
for (let i = 0; i < normalized.length; i += 2) {
if (i + 1 < normalized.length) {
hops.push(normalized.slice(i, i + 2));
}
}
return hops;
}
/**
* Find contacts matching first 2 chars of public key (repeaters only for intermediate hops)
*/
export function findContactsByPrefix(
prefix: string,
contacts: Contact[],
repeatersOnly: boolean = true
): Contact[] {
const normalizedPrefix = prefix.toUpperCase();
return contacts.filter((c) => {
if (repeatersOnly && c.type !== CONTACT_TYPE_REPEATER) {
return false;
}
return c.public_key.toUpperCase().startsWith(normalizedPrefix);
});
}
/**
* Calculate distance between two points using Haversine formula
* @returns Distance in km, or null if coordinates are missing
*/
export function calculateDistance(
lat1: number | null,
lon1: number | null,
lat2: number | null,
lon2: number | null
): number | null {
if (lat1 === null || lon1 === null || lat2 === null || lon2 === null) {
return null;
}
const R = 6371; // Earth's radius in km
const dLat = toRad(lat2 - lat1);
const dLon = toRad(lon2 - lon1);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
function toRad(deg: number): number {
return (deg * Math.PI) / 180;
}
/**
* Check if coordinates represent a valid location
* Returns false for null or (0, 0) which indicates unset location
*/
export function isValidLocation(lat: number | null, lon: number | null): boolean {
if (lat === null || lon === null) {
return false;
}
// (0, 0) is in the Atlantic Ocean - treat as unset
if (lat === 0 && lon === 0) {
return false;
}
return true;
}
/**
* Sort contacts by distance from a reference point
* Contacts without location are placed at the end
*/
export function sortContactsByDistance(
contacts: Contact[],
fromLat: number | null,
fromLon: number | null
): Contact[] {
if (fromLat === null || fromLon === null) {
return contacts;
}
return [...contacts].sort((a, b) => {
const distA = calculateDistance(fromLat, fromLon, a.lat, a.lon);
const distB = calculateDistance(fromLat, fromLon, b.lat, b.lon);
// Null distances go to the end
if (distA === null && distB === null) return 0;
if (distA === null) return 1;
if (distB === null) return -1;
return distA - distB;
});
}
/**
* Get simple hop count from path string
*/
export function getHopCount(path: string | null | undefined): number {
if (!path || path.length === 0) {
return 0;
}
return Math.floor(path.length / 2);
}
/**
* Build complete path resolution with sender, hops, and receiver
*/
export function resolvePath(
path: string | null | undefined,
sender: SenderInfo,
contacts: Contact[],
config: RadioConfig | null
): ResolvedPath {
const hopPrefixes = parsePathHops(path);
// Build sender info
const senderPrefix = sender.publicKeyOrPrefix.toUpperCase().slice(0, 2);
const resolvedSender = {
name: sender.name,
prefix: senderPrefix,
lat: sender.lat,
lon: sender.lon,
};
// Build receiver info from radio config
const receiverPrefix = config?.public_key?.toUpperCase().slice(0, 2) || '??';
const resolvedReceiver = {
name: config?.name || 'Unknown',
prefix: receiverPrefix,
lat: config?.lat ?? null,
lon: config?.lon ?? null,
};
// Build hops
const hops: PathHop[] = [];
let prevLat = sender.lat;
let prevLon = sender.lon;
// Start uncertain if sender has no valid location
let prevHopUncertain = !isValidLocation(sender.lat, sender.lon);
for (const prefix of hopPrefixes) {
const matches = findContactsByPrefix(prefix, contacts, true);
const sortedMatches = sortContactsByDistance(matches, prevLat, prevLon);
// Calculate distance from previous hop
// Can't calculate if previous hop was uncertain (unknown/ambiguous/no location) or current hop is unknown/invalid
let distanceFromPrev: number | null = null;
const currentHasValidLocation =
sortedMatches.length === 1 && isValidLocation(sortedMatches[0].lat, sortedMatches[0].lon);
if (!prevHopUncertain && currentHasValidLocation) {
distanceFromPrev = calculateDistance(
prevLat,
prevLon,
sortedMatches[0].lat,
sortedMatches[0].lon
);
}
hops.push({
prefix,
matches: sortedMatches,
distanceFromPrev,
});
// Update previous location for next hop
if (sortedMatches.length === 0) {
// Unknown hop - can't calculate distance for next hop
prevHopUncertain = true;
prevLat = null;
prevLon = null;
} else if (sortedMatches.length > 1) {
// Ambiguous hop - can't calculate distance for next hop (too many combinations)
prevHopUncertain = true;
// Use first match's location for sorting purposes, but distance won't be shown
if (isValidLocation(sortedMatches[0].lat, sortedMatches[0].lon)) {
prevLat = sortedMatches[0].lat;
prevLon = sortedMatches[0].lon;
} else {
prevLat = null;
prevLon = null;
}
} else if (isValidLocation(sortedMatches[0].lat, sortedMatches[0].lon)) {
prevHopUncertain = false;
prevLat = sortedMatches[0].lat;
prevLon = sortedMatches[0].lon;
} else {
// Known hop but no valid location - treat as uncertain for distance purposes
prevHopUncertain = true;
prevLat = null;
prevLon = null;
}
}
// Calculate total distances (can be multiple if ambiguous)
const totalDistances = calculateTotalDistances(resolvedSender, hops, resolvedReceiver);
return {
sender: resolvedSender,
hops,
receiver: resolvedReceiver,
totalDistances,
};
}
/**
* Calculate total distance(s) for the path
* Returns array for ambiguous paths, null if any segment can't be calculated
* If sender has no location, starts calculating from first hop with location
*/
function calculateTotalDistances(
sender: { lat: number | null; lon: number | null },
hops: PathHop[],
receiver: { lat: number | null; lon: number | null }
): number[] | null {
// Simple case: no hops
if (hops.length === 0) {
if (!isValidLocation(sender.lat, sender.lon) || !isValidLocation(receiver.lat, receiver.lon)) {
return null;
}
const dist = calculateDistance(sender.lat, sender.lon, receiver.lat, receiver.lon);
return dist !== null ? [dist] : null;
}
// Start from sender if it has valid location, otherwise find first hop with valid location
let prevLat = sender.lat;
let prevLon = sender.lon;
let startHopIndex = 0;
if (!isValidLocation(prevLat, prevLon)) {
// Find first hop with a known, unambiguous, valid location
for (let i = 0; i < hops.length; i++) {
const hop = hops[i];
if (hop.matches.length === 1 && isValidLocation(hop.matches[0].lat, hop.matches[0].lon)) {
prevLat = hop.matches[0].lat;
prevLon = hop.matches[0].lon;
startHopIndex = i + 1;
break;
}
}
// If no hop has valid location, can't calculate
if (!isValidLocation(prevLat, prevLon)) {
return null;
}
}
// Sum up only unambiguous segments (where both endpoints are known and unambiguous)
let totalDistance = 0;
let hasAnyDistance = false;
let lastUnambiguousHopIndex = -1; // Track last unambiguous hop for receiver distance
for (let i = startHopIndex; i < hops.length; i++) {
const hop = hops[i];
// Skip if hop is unknown or ambiguous or has no valid location
if (hop.matches.length !== 1 || !isValidLocation(hop.matches[0].lat, hop.matches[0].lon)) {
// Can't include this segment - reset prevLat/prevLon for next potential segment
prevLat = null;
prevLon = null;
continue;
}
// Only calculate distance if previous location is known (unambiguous)
if (prevLat !== null && prevLon !== null) {
const dist = calculateDistance(prevLat, prevLon, hop.matches[0].lat, hop.matches[0].lon);
if (dist !== null) {
totalDistance += dist;
hasAnyDistance = true;
}
}
// Update for next iteration
prevLat = hop.matches[0].lat;
prevLon = hop.matches[0].lon;
lastUnambiguousHopIndex = i;
}
// Add final leg to receiver only if last hop was unambiguous and receiver has valid location
if (lastUnambiguousHopIndex === hops.length - 1 && prevLat !== null && prevLon !== null) {
if (isValidLocation(receiver.lat, receiver.lon)) {
const finalDist = calculateDistance(prevLat, prevLon, receiver.lat, receiver.lon);
if (finalDist !== null) {
totalDistance += finalDist;
hasAnyDistance = true;
}
}
}
// Return total if we calculated any distance
return hasAnyDistance ? [totalDistance] : null;
}