Add server-side read management

This commit is contained in:
Jack Kingsman committed 2026-01-12 23:26:02 -08:00
1 parent 1e1b1e2bb5
commit 5ce5a988c7
20 files changed
+887 -102

No files matched your search

+30 -3
View File
@@ -152,7 +152,8 @@ Key test files:
- `tests/test_decoder.py` - Channel + direct message decryption, key exchange
- `tests/test_keystore.py` - Ephemeral key store
- `tests/test_event_handlers.py` - ACK tracking, repeat detection
- `tests/test_api.py` - API endpoints
- `tests/test_api.py` - API endpoints, read state tracking
- `tests/test_migrations.py` - Database migration system
### Frontend (Vitest)
@@ -165,6 +166,23 @@ npm run test:run
Open `integration_test.html` in a browser with the backend running.
### Before Completing Changes
**Always run both backend and frontend validation before finishing any changes:**
```bash
# From project root - run backend tests
PYTHONPATH=. uv run pytest tests/ -v
# From project root - run frontend tests and build
cd frontend && npm run test:run && npm run build
```
This catches:
- Type mismatches between frontend and backend (e.g., missing fields in TypeScript interfaces)
- Breaking changes to shared types or API contracts
- Runtime errors that only surface during compilation
## API Summary
All endpoints are prefixed with `/api` (e.g., `/api/health`).
@@ -188,6 +206,9 @@ All endpoints are prefixed with `/api` (e.g., `/api/health`).
| POST | `/api/messages/direct` | Send direct message |
| POST | `/api/messages/channel` | Send channel message |
| POST | `/api/packets/decrypt/historical` | Decrypt stored packets |
| POST | `/api/contacts/{key}/mark-read` | Mark contact conversation as read |
| POST | `/api/channels/{key}/mark-read` | Mark channel as read |
| POST | `/api/read-state/mark-all-read` | Mark all conversations as read |
| GET | `/api/settings` | Get app settings |
| PATCH | `/api/settings` | Update app settings |
| WS | `/api/ws` | Real-time updates |
@@ -219,9 +240,15 @@ All endpoints are prefixed with `/api` (e.g., `/api/health`).
- `CHAN` - Channel messages
- Both use `conversation_key` (user pubkey for PRIV, channel key for CHAN)
### State Tracking Keys (Frontend)
### Read State Tracking
Generated by `getStateKey()` for unread tracking and message times:
Read state (`last_read_at`) is tracked **server-side** for consistency across devices:
- Stored as Unix timestamp in `contacts.last_read_at` and `channels.last_read_at`
- Updated via `POST /api/contacts/{key}/mark-read` and `POST /api/channels/{key}/mark-read`
- Bulk update via `POST /api/read-state/mark-all-read`
- Frontend compares `last_read_at` with message `received_at` to count unreads
**State Tracking Keys (Frontend)**: Generated by `getStateKey()` for message times (sidebar sorting):
- Channels: `channel-{channel_key}`
- Contacts: `contact-{12-char-pubkey-prefix}`
+59 -6
View File
@@ -17,7 +17,8 @@ This document provides context for AI assistants and developers working on the F
app/
├── main.py # FastAPI app, lifespan, router registration, static file serving
├── config.py # Pydantic settings (env vars: MESHCORE_*)
├── database.py # SQLite schema, connection management
├── database.py # SQLite schema, connection management, runs migrations
├── migrations.py # Database migrations using SQLite user_version pragma
├── models.py # Pydantic models for API request/response
├── repository.py # Database CRUD (ContactRepository, ChannelRepository, etc.)
├── radio.py # RadioManager - serial connection to MeshCore device
@@ -30,10 +31,11 @@ app/
└── routers/ # All routes prefixed with /api
├── health.py # GET /api/health
├── radio.py # Radio config, advertise, private key, reboot
├── contacts.py # Contact CRUD and radio sync
├── channels.py # Channel CRUD and radio sync
├── contacts.py # Contact CRUD, radio sync, mark-read
├── channels.py # Channel CRUD, radio sync, mark-read
├── messages.py # Message list and send (direct/channel)
├── packets.py # Raw packet endpoints, historical decryption
├── read_state.py # Bulk read state operations (mark-all-read)
├── settings.py # App settings (max_radio_contacts)
└── ws.py # WebSocket endpoint at /api/ws
```
@@ -138,14 +140,16 @@ contacts (
lat REAL, lon REAL,
last_seen INTEGER,
on_radio INTEGER DEFAULT 0, -- Boolean: contact loaded on radio
last_contacted INTEGER -- Unix timestamp of last message sent/received
last_contacted INTEGER, -- Unix timestamp of last message sent/received
last_read_at INTEGER -- Unix timestamp when conversation was last read
)
channels (
key TEXT PRIMARY KEY, -- 32-char hex channel key
name TEXT NOT NULL,
is_hashtag INTEGER DEFAULT 0, -- Key derived from SHA256(name)[:16]
on_radio INTEGER DEFAULT 0
on_radio INTEGER DEFAULT 0,
last_read_at INTEGER -- Unix timestamp when channel was last read
)
messages (
@@ -175,6 +179,49 @@ raw_packets (
)
```
## Database Migrations (`migrations.py`)
Schema migrations use SQLite's `user_version` pragma for version tracking:
```python
from app.migrations import get_version, set_version, run_migrations
# Check current schema version
version = await get_version(conn) # Returns int (0 for new/unmigrated DB)
# Run pending migrations (called automatically on startup)
applied = await run_migrations(conn) # Returns number of migrations applied
```
### How It Works
1. `database.py` calls `run_migrations()` after schema initialization
2. Each migration checks `user_version` and runs if needed
3. Migrations are idempotent (safe to run multiple times)
4. `ALTER TABLE ADD COLUMN` handles existing columns gracefully
### Adding a New Migration
```python
# In migrations.py
async def run_migrations(conn: aiosqlite.Connection) -> int:
version = await get_version(conn)
applied = 0
if version < 1:
await _migrate_001_add_last_read_at(conn)
await set_version(conn, 1)
applied += 1
# Add new migrations here:
# if version < 2:
# await _migrate_002_something(conn)
# await set_version(conn, 2)
# applied += 1
return applied
```
## Packet Decryption (`decoder.py`)
The decoder handles MeshCore packet decryption for historical packet analysis:
@@ -326,6 +373,7 @@ All endpoints are prefixed with `/api`.
- `POST /api/contacts/sync` - Pull from radio to database
- `POST /api/contacts/{key}/add-to-radio` - Push to radio
- `POST /api/contacts/{key}/remove-from-radio` - Remove from radio
- `POST /api/contacts/{key}/mark-read` - Mark conversation as read (updates last_read_at)
- `POST /api/contacts/{key}/telemetry` - Request telemetry from repeater (see below)
### Channels
@@ -333,8 +381,12 @@ All endpoints are prefixed with `/api`.
- `GET /api/channels/{key}` - Get by channel key
- `POST /api/channels` - Create (hashtag if name starts with # or no key provided)
- `POST /api/channels/sync` - Pull from radio
- `POST /api/channels/{key}/mark-read` - Mark channel as read (updates last_read_at)
- `DELETE /api/channels/{key}` - Delete channel
### Read State
- `POST /api/read-state/mark-all-read` - Mark all contacts and channels as read
### Messages
- `GET /api/messages?type=&conversation_key=&limit=&offset=` - List with filters
- `POST /api/messages/direct` - Send direct message
@@ -368,7 +420,8 @@ Key test files:
- `tests/test_decoder.py` - Channel + direct message decryption, key exchange, real-world test vectors
- `tests/test_keystore.py` - Ephemeral key store operations
- `tests/test_event_handlers.py` - ACK tracking, repeat detection, CLI response filtering
- `tests/test_api.py` - API endpoint tests
- `tests/test_api.py` - API endpoint tests, read state tracking
- `tests/test_migrations.py` - Migration system, schema versioning
## Common Tasks
+4
View File
@@ -77,6 +77,10 @@ class Database:
await self._connection.commit()
logger.debug("Database schema initialized")
# Run any pending migrations
from app.migrations import run_migrations
await run_migrations(self._connection)
async def disconnect(self) -> None:
if self._connection:
await self._connection.close()
+2 -1
View File
@@ -19,7 +19,7 @@ from app.radio_sync import (
stop_periodic_sync,
sync_and_offload_all,
)
from app.routers import channels, contacts, health, messages, packets, radio, settings, ws
from app.routers import channels, contacts, health, messages, packets, radio, read_state, settings, ws
setup_logging()
logger = logging.getLogger(__name__)
@@ -100,6 +100,7 @@ app.include_router(contacts.router, prefix="/api")
app.include_router(channels.router, prefix="/api")
app.include_router(messages.router, prefix="/api")
app.include_router(packets.router, prefix="/api")
app.include_router(read_state.router, prefix="/api")
app.include_router(settings.router, prefix="/api")
app.include_router(ws.router, prefix="/api")
+90
View File
@@ -0,0 +1,90 @@
"""
Database migrations using SQLite's user_version pragma.
Migrations run automatically on startup. The user_version pragma tracks
which migrations have been applied (defaults to 0 for existing databases).
This approach is safe for existing users - their databases have user_version=0,
so all migrations run in order on first startup after upgrade.
"""
import logging
import aiosqlite
logger = logging.getLogger(__name__)
async def get_version(conn: aiosqlite.Connection) -> int:
"""Get current schema version from SQLite user_version pragma."""
cursor = await conn.execute("PRAGMA user_version")
row = await cursor.fetchone()
return row[0] if row else 0
async def set_version(conn: aiosqlite.Connection, version: int) -> None:
"""Set schema version using SQLite user_version pragma."""
await conn.execute(f"PRAGMA user_version = {version}")
async def run_migrations(conn: aiosqlite.Connection) -> int:
"""
Run all pending migrations.
Returns the number of migrations applied.
"""
version = await get_version(conn)
applied = 0
# Migration 1: Add last_read_at columns for server-side read tracking
if version < 1:
logger.info("Applying migration 1: add last_read_at columns")
await _migrate_001_add_last_read_at(conn)
await set_version(conn, 1)
applied += 1
# Future migrations go here:
# if version < 2:
# await _migrate_002_something(conn)
# await set_version(conn, 2)
# applied += 1
if applied > 0:
logger.info("Applied %d migration(s), schema now at version %d", applied, await get_version(conn))
else:
logger.debug("Schema up to date at version %d", version)
return applied
async def _migrate_001_add_last_read_at(conn: aiosqlite.Connection) -> None:
"""
Add last_read_at column to contacts and channels tables.
This enables server-side read state tracking, replacing the localStorage
approach for consistent read state across devices.
ALTER TABLE ADD COLUMN is safe - it preserves existing data and handles
the "column already exists" case gracefully.
"""
# Add to contacts table
try:
await conn.execute("ALTER TABLE contacts ADD COLUMN last_read_at INTEGER")
logger.debug("Added last_read_at to contacts table")
except aiosqlite.OperationalError as e:
if "duplicate column name" in str(e).lower():
logger.debug("contacts.last_read_at already exists, skipping")
else:
raise
# Add to channels table
try:
await conn.execute("ALTER TABLE channels ADD COLUMN last_read_at INTEGER")
logger.debug("Added last_read_at to channels table")
except aiosqlite.OperationalError as e:
if "duplicate column name" in str(e).lower():
logger.debug("channels.last_read_at already exists, skipping")
else:
raise
await conn.commit()
+2
View File
@@ -14,6 +14,7 @@ class Contact(BaseModel):
last_seen: int | None = None
on_radio: bool = False
last_contacted: int | None = None # Last time we sent/received a message
last_read_at: int | None = None # Server-side read state tracking
def to_radio_dict(self) -> dict:
"""Convert to the dict format expected by meshcore radio commands.
@@ -63,6 +64,7 @@ class Channel(BaseModel):
name: str
is_hashtag: bool = False
on_radio: bool = False
last_read_at: int | None = None # Server-side read state tracking
class Message(BaseModel):
+35 -3
View File
@@ -59,6 +59,7 @@ class ContactRepository:
last_seen=row["last_seen"],
on_radio=bool(row["on_radio"]),
last_contacted=row["last_contacted"],
last_read_at=row["last_read_at"],
)
@staticmethod
@@ -169,6 +170,20 @@ class ContactRepository:
)
await db.conn.commit()
@staticmethod
async def update_last_read_at(public_key: str, timestamp: int | None = None) -> bool:
"""Update the last_read_at timestamp for a contact.
Returns True if a row was updated, False if contact not found.
"""
ts = timestamp or int(time.time())
cursor = await db.conn.execute(
"UPDATE contacts SET last_read_at = ? WHERE public_key = ?",
(ts, public_key),
)
await db.conn.commit()
return cursor.rowcount > 0
class ChannelRepository:
@staticmethod
@@ -191,7 +206,7 @@ class ChannelRepository:
async def get_by_key(key: str) -> Channel | None:
"""Get a channel by its key (32-char hex string)."""
cursor = await db.conn.execute(
"SELECT key, name, is_hashtag, on_radio FROM channels WHERE key = ?",
"SELECT key, name, is_hashtag, on_radio, last_read_at FROM channels WHERE key = ?",
(key.upper(),)
)
row = await cursor.fetchone()
@@ -201,13 +216,14 @@ class ChannelRepository:
name=row["name"],
is_hashtag=bool(row["is_hashtag"]),
on_radio=bool(row["on_radio"]),
last_read_at=row["last_read_at"],
)
return None
@staticmethod
async def get_all() -> list[Channel]:
cursor = await db.conn.execute(
"SELECT key, name, is_hashtag, on_radio FROM channels ORDER BY name"
"SELECT key, name, is_hashtag, on_radio, last_read_at FROM channels ORDER BY name"
)
rows = await cursor.fetchall()
return [
@@ -216,6 +232,7 @@ class ChannelRepository:
name=row["name"],
is_hashtag=bool(row["is_hashtag"]),
on_radio=bool(row["on_radio"]),
last_read_at=row["last_read_at"],
)
for row in rows
]
@@ -224,7 +241,7 @@ class ChannelRepository:
async def get_by_name(name: str) -> Channel | None:
"""Get a channel by name."""
cursor = await db.conn.execute(
"SELECT key, name, is_hashtag, on_radio FROM channels WHERE name = ?", (name,)
"SELECT key, name, is_hashtag, on_radio, last_read_at FROM channels WHERE name = ?", (name,)
)
row = await cursor.fetchone()
if row:
@@ -233,6 +250,7 @@ class ChannelRepository:
name=row["name"],
is_hashtag=bool(row["is_hashtag"]),
on_radio=bool(row["on_radio"]),
last_read_at=row["last_read_at"],
)
return None
@@ -245,6 +263,20 @@ class ChannelRepository:
)
await db.conn.commit()
@staticmethod
async def update_last_read_at(key: str, timestamp: int | None = None) -> bool:
"""Update the last_read_at timestamp for a channel.
Returns True if a row was updated, False if channel not found.
"""
ts = timestamp or int(time.time())
cursor = await db.conn.execute(
"UPDATE channels SET last_read_at = ? WHERE key = ?",
(ts, key.upper()),
)
await db.conn.commit()
return cursor.rowcount > 0
class MessageRepository:
@staticmethod
+14
View File
@@ -118,6 +118,20 @@ async def sync_channels_from_radio(
return {"synced": count}
@router.post("/{key}/mark-read")
async def mark_channel_read(key: str) -> dict:
"""Mark a channel as read (update last_read_at timestamp)."""
channel = await ChannelRepository.get_by_key(key)
if not channel:
raise HTTPException(status_code=404, detail="Channel not found")
updated = await ChannelRepository.update_last_read_at(key)
if not updated:
raise HTTPException(status_code=500, detail="Failed to update read state")
return {"status": "ok", "key": channel.key}
@router.delete("/{key}")
async def delete_channel(key: str) -> dict:
"""Delete a channel from the database by key.
+14
View File
@@ -214,6 +214,20 @@ async def add_contact_to_radio(public_key: str) -> dict:
return {"status": "ok"}
@router.post("/{public_key}/mark-read")
async def mark_contact_read(public_key: str) -> dict:
"""Mark a contact conversation as read (update last_read_at timestamp)."""
contact = await ContactRepository.get_by_key_or_prefix(public_key)
if not contact:
raise HTTPException(status_code=404, detail="Contact not found")
updated = await ContactRepository.update_last_read_at(contact.public_key)
if not updated:
raise HTTPException(status_code=500, detail="Failed to update read state")
return {"status": "ok", "public_key": contact.public_key}
@router.delete("/{public_key}")
async def delete_contact(public_key: str) -> dict:
"""Delete a contact from the database (and radio if present)."""
+35
View File
@@ -0,0 +1,35 @@
"""Read state management endpoints."""
import logging
import time
from fastapi import APIRouter
from app.database import db
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/read-state", tags=["read-state"])
@router.post("/mark-all-read")
async def mark_all_read() -> dict:
"""Mark all contacts and channels as read.
Updates last_read_at to current timestamp for all contacts and channels
in a single database transaction.
"""
now = int(time.time())
# Update all contacts and channels in one transaction
await db.conn.execute(
"UPDATE contacts SET last_read_at = ?",
(now,)
)
await db.conn.execute(
"UPDATE channels SET last_read_at = ?",
(now,)
)
await db.conn.commit()
logger.info("Marked all contacts and channels as read at %d", now)
return {"status": "ok", "timestamp": now}
+27 -6
View File
@@ -26,7 +26,7 @@ frontend/
│ ├── styles.css # Dark theme CSS
│ ├── utils/
│ │ ├── messageParser.ts # Text parsing utilities
│ │ ├── conversationState.ts # localStorage for unread tracking
│ │ ├── conversationState.ts # localStorage for message times (sidebar sorting)
│ │ ├── pubkey.ts # Public key utilities (prefix matching, display names)
│ │ └── contactAvatar.ts # Avatar generation (colors, initials/emoji)
│ ├── components/
@@ -342,7 +342,7 @@ const activeConv = activeConversationRef.current;
### State Tracking Keys
State tracking keys (for unread counts and message times) are generated by `getStateKey()`:
State tracking keys (for message times used in sidebar sorting) are generated by `getStateKey()`:
```typescript
import { getStateKey } from './utils/conversationState';
@@ -355,7 +355,26 @@ getStateKey('contact', publicKey) // e.g., "contact-abc123def456"
```
**Note:** `getStateKey()` is NOT the same as `Message.conversation_key`. The state key is prefixed
for localStorage tracking, while `conversation_key` is the raw database field.
for local state tracking, while `conversation_key` is the raw database field.
### Read State (Server-Side)
Unread tracking uses server-side `last_read_at` timestamps for cross-device consistency:
```typescript
// Contacts and channels include last_read_at from server
interface Contact {
// ...
last_read_at: number | null; // Unix timestamp when conversation was last read
}
// Mark as read via API (called automatically when viewing conversation)
await api.markContactRead(publicKey);
await api.markChannelRead(channelKey);
await api.markAllRead(); // Bulk mark all as read
```
Unread count = messages where `received_at > last_read_at`.
## Utility Functions
@@ -389,17 +408,19 @@ getContactDisplayName(name, publicKey) // name or first 12 chars of key
### Conversation State (`utils/conversationState.ts`)
```typescript
import { getStateKey, setLastMessageTime, setLastReadTime } from './utils/conversationState';
import { getStateKey, setLastMessageTime, getLastMessageTimes } from './utils/conversationState';
// Generate state tracking key (NOT the same as Message.conversation_key)
getStateKey('channel', channelKey)
getStateKey('contact', publicKey)
// Track message times for unread detection
// Track message times for sidebar sorting (stored in localStorage)
setLastMessageTime(stateKey, timestamp)
setLastReadTime(stateKey, timestamp)
getLastMessageTimes() // Returns all tracked message times
```
**Note:** Read state (`last_read_at`) is tracked server-side, not in localStorage.
### Contact Avatar (`utils/contactAvatar.ts`)
Generates consistent profile "images" for contacts using hash-based colors:
@@ -1,4 +1,4 @@
var ik=Object.defineProperty;var ak=(a,o,r)=>o in a?ik(a,o,{enumerable:!0,configurable:!0,writable:!0,value:r}):a[o]=r;var Ln=(a,o,r)=>ak(a,typeof o!="symbol"?o+"":o,r);function nk(a,o){for(var r=0;r<o.length;r++){const s=o[r];if(typeof s!="string"&&!Array.isArray(s)){for(const c in s)if(c!=="default"&&!(c in a)){const l=Object.getOwnPropertyDescriptor(s,c);l&&Object.defineProperty(a,c,l.get?l:{enumerable:!0,get:()=>s[c]})}}}return Object.freeze(Object.defineProperty(a,Symbol.toStringTag,{value:"Module"}))}(function(){const o=document.createElement("link").relList;if(o&&o.supports&&o.supports("modulepreload"))return;for(const c of document.querySelectorAll('link[rel="modulepreload"]'))s(c);new MutationObserver(c=>{for(const l of c)if(l.type==="childList")for(const m of l.addedNodes)m.tagName==="LINK"&&m.rel==="modulepreload"&&s(m)}).observe(document,{childList:!0,subtree:!0});function r(c){const l={};return c.integrity&&(l.integrity=c.integrity),c.referrerPolicy&&(l.referrerPolicy=c.referrerPolicy),c.crossOrigin==="use-credentials"?l.credentials="include":c.crossOrigin==="anonymous"?l.credentials="omit":l.credentials="same-origin",l}function s(c){if(c.ep)return;c.ep=!0;const l=r(c);fetch(c.href,l)}})();var eu=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function Fr(a){return a&&a.__esModule&&Object.prototype.hasOwnProperty.call(a,"default")?a.default:a}function Gg(a){if(Object.prototype.hasOwnProperty.call(a,"__esModule"))return a;var o=a.default;if(typeof o=="function"){var r=function s(){return this instanceof s?Reflect.construct(o,arguments,this.constructor):o.apply(this,arguments)};r.prototype=o.prototype}else r={};return Object.defineProperty(r,"__esModule",{value:!0}),Object.keys(a).forEach(function(s){var c=Object.getOwnPropertyDescriptor(a,s);Object.defineProperty(r,s,c.get?c:{enumerable:!0,get:function(){return a[s]}})}),r}var iu={exports:{}},fo={},au={exports:{}},Ie={};/**
var Xv=Object.defineProperty;var Jv=(a,o,r)=>o in a?Xv(a,o,{enumerable:!0,configurable:!0,writable:!0,value:r}):a[o]=r;var Ln=(a,o,r)=>Jv(a,typeof o!="symbol"?o+"":o,r);function ek(a,o){for(var r=0;r<o.length;r++){const s=o[r];if(typeof s!="string"&&!Array.isArray(s)){for(const c in s)if(c!=="default"&&!(c in a)){const l=Object.getOwnPropertyDescriptor(s,c);l&&Object.defineProperty(a,c,l.get?l:{enumerable:!0,get:()=>s[c]})}}}return Object.freeze(Object.defineProperty(a,Symbol.toStringTag,{value:"Module"}))}(function(){const o=document.createElement("link").relList;if(o&&o.supports&&o.supports("modulepreload"))return;for(const c of document.querySelectorAll('link[rel="modulepreload"]'))s(c);new MutationObserver(c=>{for(const l of c)if(l.type==="childList")for(const m of l.addedNodes)m.tagName==="LINK"&&m.rel==="modulepreload"&&s(m)}).observe(document,{childList:!0,subtree:!0});function r(c){const l={};return c.integrity&&(l.integrity=c.integrity),c.referrerPolicy&&(l.referrerPolicy=c.referrerPolicy),c.crossOrigin==="use-credentials"?l.credentials="include":c.crossOrigin==="anonymous"?l.credentials="omit":l.credentials="same-origin",l}function s(c){if(c.ep)return;c.ep=!0;const l=r(c);fetch(c.href,l)}})();var Xc=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function Fr(a){return a&&a.__esModule&&Object.prototype.hasOwnProperty.call(a,"default")?a.default:a}function Ug(a){if(Object.prototype.hasOwnProperty.call(a,"__esModule"))return a;var o=a.default;if(typeof o=="function"){var r=function s(){return this instanceof s?Reflect.construct(o,arguments,this.constructor):o.apply(this,arguments)};r.prototype=o.prototype}else r={};return Object.defineProperty(r,"__esModule",{value:!0}),Object.keys(a).forEach(function(s){var c=Object.getOwnPropertyDescriptor(a,s);Object.defineProperty(r,s,c.get?c:{enumerable:!0,get:function(){return a[s]}})}),r}var Jc={exports:{}},fo={},eu={exports:{}},Ie={};/**
* @license React
* react.production.min.js
*
@@ -6,7 +6,7 @@ var ik=Object.defineProperty;var ak=(a,o,r)=>o in a?ik(a,o,{enumerable:!0,config
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var Hm;function rk(){if(Hm)return Ie;Hm=1;var a=Symbol.for("react.element"),o=Symbol.for("react.portal"),r=Symbol.for("react.fragment"),s=Symbol.for("react.strict_mode"),c=Symbol.for("react.profiler"),l=Symbol.for("react.provider"),m=Symbol.for("react.context"),u=Symbol.for("react.forward_ref"),h=Symbol.for("react.suspense"),d=Symbol.for("react.memo"),g=Symbol.for("react.lazy"),y=Symbol.iterator;function f(q){return q===null||typeof q!="object"?null:(q=y&&q[y]||q["@@iterator"],typeof q=="function"?q:null)}var w={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},k=Object.assign,z={};function v(q,I,L){this.props=q,this.context=I,this.refs=z,this.updater=L||w}v.prototype.isReactComponent={},v.prototype.setState=function(q,I){if(typeof q!="object"&&typeof q!="function"&&q!=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,q,I,"setState")},v.prototype.forceUpdate=function(q){this.updater.enqueueForceUpdate(this,q,"forceUpdate")};function j(){}j.prototype=v.prototype;function A(q,I,L){this.props=q,this.context=I,this.refs=z,this.updater=L||w}var x=A.prototype=new j;x.constructor=A,k(x,v.prototype),x.isPureReactComponent=!0;var _=Array.isArray,C=Object.prototype.hasOwnProperty,D={current:null},F={key:!0,ref:!0,__self:!0,__source:!0};function R(q,I,L){var $,te={},pe=null,ge=null;if(I!=null)for($ in I.ref!==void 0&&(ge=I.ref),I.key!==void 0&&(pe=""+I.key),I)C.call(I,$)&&!F.hasOwnProperty($)&&(te[$]=I[$]);var re=arguments.length-2;if(re===1)te.children=L;else if(1<re){for(var Se=Array(re),Me=0;Me<re;Me++)Se[Me]=arguments[Me+2];te.children=Se}if(q&&q.defaultProps)for($ in re=q.defaultProps,re)te[$]===void 0&&(te[$]=re[$]);return{$$typeof:a,type:q,key:pe,ref:ge,props:te,_owner:D.current}}function M(q,I){return{$$typeof:a,type:q.type,key:I,ref:q.ref,props:q.props,_owner:q._owner}}function N(q){return typeof q=="object"&&q!==null&&q.$$typeof===a}function T(q){var I={"=":"=0",":":"=2"};return"$"+q.replace(/[=:]/g,function(L){return I[L]})}var U=/\/+/g;function H(q,I){return typeof q=="object"&&q!==null&&q.key!=null?T(""+q.key):I.toString(36)}function K(q,I,L,$,te){var pe=typeof q;(pe==="undefined"||pe==="boolean")&&(q=null);var ge=!1;if(q===null)ge=!0;else switch(pe){case"string":case"number":ge=!0;break;case"object":switch(q.$$typeof){case a:case o:ge=!0}}if(ge)return ge=q,te=te(ge),q=$===""?"."+H(ge,0):$,_(te)?(L="",q!=null&&(L=q.replace(U,"$&/")+"/"),K(te,I,L,"",function(Me){return Me})):te!=null&&(N(te)&&(te=M(te,L+(!te.key||ge&&ge.key===te.key?"":(""+te.key).replace(U,"$&/")+"/")+q)),I.push(te)),1;if(ge=0,$=$===""?".":$+":",_(q))for(var re=0;re<q.length;re++){pe=q[re];var Se=$+H(pe,re);ge+=K(pe,I,L,Se,te)}else if(Se=f(q),typeof Se=="function")for(q=Se.call(q),re=0;!(pe=q.next()).done;)pe=pe.value,Se=$+H(pe,re++),ge+=K(pe,I,L,Se,te);else if(pe==="object")throw I=String(q),Error("Objects are not valid as a React child (found: "+(I==="[object Object]"?"object with keys {"+Object.keys(q).join(", ")+"}":I)+"). If you meant to render a collection of children, use an array instead.");return ge}function ie(q,I,L){if(q==null)return q;var $=[],te=0;return K(q,$,"","",function(pe){return I.call(L,pe,te++)}),$}function Z(q){if(q._status===-1){var I=q._result;I=I(),I.then(function(L){(q._status===0||q._status===-1)&&(q._status=1,q._result=L)},function(L){(q._status===0||q._status===-1)&&(q._status=2,q._result=L)}),q._status===-1&&(q._status=0,q._result=I)}if(q._status===1)return q._result.default;throw q._result}var ae={current:null},W={transition:null},ne={ReactCurrentDispatcher:ae,ReactCurrentBatchConfig:W,ReactCurrentOwner:D};function X(){throw Error("act(...) is not supported in production builds of React.")}return Ie.Children={map:ie,forEach:function(q,I,L){ie(q,function(){I.apply(this,arguments)},L)},count:function(q){var I=0;return ie(q,function(){I++}),I},toArray:function(q){return ie(q,function(I){return I})||[]},only:function(q){if(!N(q))throw Error("React.Children.only expected to receive a single React element child.");return q}},Ie.Component=v,Ie.Fragment=r,Ie.Profiler=c,Ie.PureComponent=A,Ie.StrictMode=s,Ie.Suspense=h,Ie.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=ne,Ie.act=X,Ie.cloneElement=function(q,I,L){if(q==null)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+q+".");var $=k({},q.props),te=q.key,pe=q.ref,ge=q._owner;if(I!=null){if(I.ref!==void 0&&(pe=I.ref,ge=D.current),I.key!==void 0&&(te=""+I.key),q.type&&q.type.defaultProps)var re=q.type.defaultProps;for(Se in I)C.call(I,Se)&&!F.hasOwnProperty(Se)&&($[Se]=I[Se]===void 0&&re!==void 0?re[Se]:I[Se])}var Se=arguments.length-2;if(Se===1)$.children=L;else if(1<Se){re=Array(Se);for(var Me=0;Me<Se;Me++)re[Me]=arguments[Me+2];$.children=re}return{$$typeof:a,type:q.type,key:te,ref:pe,props:$,_owner:ge}},Ie.createContexLine truncated
*/var Mm;function ik(){if(Mm)return Ie;Mm=1;var a=Symbol.for("react.element"),o=Symbol.for("react.portal"),r=Symbol.for("react.fragment"),s=Symbol.for("react.strict_mode"),c=Symbol.for("react.profiler"),l=Symbol.for("react.provider"),m=Symbol.for("react.context"),u=Symbol.for("react.forward_ref"),h=Symbol.for("react.suspense"),d=Symbol.for("react.memo"),g=Symbol.for("react.lazy"),y=Symbol.iterator;function f(A){return A===null||typeof A!="object"?null:(A=y&&A[y]||A["@@iterator"],typeof A=="function"?A:null)}var w={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},k=Object.assign,z={};function v(A,I,L){this.props=A,this.context=I,this.refs=z,this.updater=L||w}v.prototype.isReactComponent={},v.prototype.setState=function(A,I){if(typeof A!="object"&&typeof A!="function"&&A!=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,A,I,"setState")},v.prototype.forceUpdate=function(A){this.updater.enqueueForceUpdate(this,A,"forceUpdate")};function j(){}j.prototype=v.prototype;function q(A,I,L){this.props=A,this.context=I,this.refs=z,this.updater=L||w}var x=q.prototype=new j;x.constructor=q,k(x,v.prototype),x.isPureReactComponent=!0;var _=Array.isArray,C=Object.prototype.hasOwnProperty,D={current:null},R={key:!0,ref:!0,__self:!0,__source:!0};function F(A,I,L){var $,te={},pe=null,ge=null;if(I!=null)for($ in I.ref!==void 0&&(ge=I.ref),I.key!==void 0&&(pe=""+I.key),I)C.call(I,$)&&!R.hasOwnProperty($)&&(te[$]=I[$]);var re=arguments.length-2;if(re===1)te.children=L;else if(1<re){for(var Se=Array(re),Me=0;Me<re;Me++)Se[Me]=arguments[Me+2];te.children=Se}if(A&&A.defaultProps)for($ in re=A.defaultProps,re)te[$]===void 0&&(te[$]=re[$]);return{$$typeof:a,type:A,key:pe,ref:ge,props:te,_owner:D.current}}function M(A,I){return{$$typeof:a,type:A.type,key:I,ref:A.ref,props:A.props,_owner:A._owner}}function P(A){return typeof A=="object"&&A!==null&&A.$$typeof===a}function T(A){var I={"=":"=0",":":"=2"};return"$"+A.replace(/[=:]/g,function(L){return I[L]})}var U=/\/+/g;function H(A,I){return typeof A=="object"&&A!==null&&A.key!=null?T(""+A.key):I.toString(36)}function K(A,I,L,$,te){var pe=typeof A;(pe==="undefined"||pe==="boolean")&&(A=null);var ge=!1;if(A===null)ge=!0;else switch(pe){case"string":case"number":ge=!0;break;case"object":switch(A.$$typeof){case a:case o:ge=!0}}if(ge)return ge=A,te=te(ge),A=$===""?"."+H(ge,0):$,_(te)?(L="",A!=null&&(L=A.replace(U,"$&/")+"/"),K(te,I,L,"",function(Me){return Me})):te!=null&&(P(te)&&(te=M(te,L+(!te.key||ge&&ge.key===te.key?"":(""+te.key).replace(U,"$&/")+"/")+A)),I.push(te)),1;if(ge=0,$=$===""?".":$+":",_(A))for(var re=0;re<A.length;re++){pe=A[re];var Se=$+H(pe,re);ge+=K(pe,I,L,Se,te)}else if(Se=f(A),typeof Se=="function")for(A=Se.call(A),re=0;!(pe=A.next()).done;)pe=pe.value,Se=$+H(pe,re++),ge+=K(pe,I,L,Se,te);else if(pe==="object")throw I=String(A),Error("Objects are not valid as a React child (found: "+(I==="[object Object]"?"object with keys {"+Object.keys(A).join(", ")+"}":I)+"). If you meant to render a collection of children, use an array instead.");return ge}function ie(A,I,L){if(A==null)return A;var $=[],te=0;return K(A,$,"","",function(pe){return I.call(L,pe,te++)}),$}function Z(A){if(A._status===-1){var I=A._result;I=I(),I.then(function(L){(A._status===0||A._status===-1)&&(A._status=1,A._result=L)},function(L){(A._status===0||A._status===-1)&&(A._status=2,A._result=L)}),A._status===-1&&(A._status=0,A._result=I)}if(A._status===1)return A._result.default;throw A._result}var ae={current:null},W={transition:null},ne={ReactCurrentDispatcher:ae,ReactCurrentBatchConfig:W,ReactCurrentOwner:D};function X(){throw Error("act(...) is not supported in production builds of React.")}return Ie.Children={map:ie,forEach:function(A,I,L){ie(A,function(){I.apply(this,arguments)},L)},count:function(A){var I=0;return ie(A,function(){I++}),I},toArray:function(A){return ie(A,function(I){return I})||[]},only:function(A){if(!P(A))throw Error("React.Children.only expected to receive a single React element child.");return A}},Ie.Component=v,Ie.Fragment=r,Ie.Profiler=c,Ie.PureComponent=q,Ie.StrictMode=s,Ie.Suspense=h,Ie.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=ne,Ie.act=X,Ie.cloneElement=function(A,I,L){if(A==null)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+A+".");var $=k({},A.props),te=A.key,pe=A.ref,ge=A._owner;if(I!=null){if(I.ref!==void 0&&(pe=I.ref,ge=D.current),I.key!==void 0&&(te=""+I.key),A.type&&A.type.defaultProps)var re=A.type.defaultProps;for(Se in I)C.call(I,Se)&&!R.hasOwnProperty(Se)&&($[Se]=I[Se]===void 0&&re!==void 0?re[Se]:I[Se])}var Se=arguments.length-2;if(Se===1)$.children=L;else if(1<Se){re=Array(Se);for(var Me=0;Me<Se;Me++)re[Me]=arguments[Me+2];$.children=re}return{$$typeof:a,type:A.type,key:te,ref:pe,props:$,_owner:ge}},Ie.createContexLine truncated
* @license React
* react-jsx-runtime.production.min.js
*
@@ -14,7 +14,7 @@ var ik=Object.defineProperty;var ak=(a,o,r)=>o in a?ik(a,o,{enumerable:!0,config
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var Um;function ok(){if(Um)return fo;Um=1;var a=Iu(),o=Symbol.for("react.element"),r=Symbol.for("react.fragment"),s=Object.prototype.hasOwnProperty,c=a.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,l={key:!0,ref:!0,__self:!0,__source:!0};function m(u,h,d){var g,y={},f=null,w=null;d!==void 0&&(f=""+d),h.key!==void 0&&(f=""+h.key),h.ref!==void 0&&(w=h.ref);for(g in h)s.call(h,g)&&!l.hasOwnProperty(g)&&(y[g]=h[g]);if(u&&u.defaultProps)for(g in h=u.defaultProps,h)y[g]===void 0&&(y[g]=h[g]);return{$$typeof:o,type:u,key:f,ref:w,props:y,_owner:c.current}}return fo.Fragment=r,fo.jsx=m,fo.jsxs=m,fo}var Wm;function sk(){return Wm||(Wm=1,iu.exports=ok()),iu.exports}var B=sk(),E=Iu();const de=Fr(E),Mu=nk({__proto__:null,default:de},[E]);var Ys={},nu={exports:{}},aa={},ru={exports:{}},ou={};/**
*/var Lm;function ak(){if(Lm)return fo;Lm=1;var a=Tu(),o=Symbol.for("react.element"),r=Symbol.for("react.fragment"),s=Object.prototype.hasOwnProperty,c=a.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,l={key:!0,ref:!0,__self:!0,__source:!0};function m(u,h,d){var g,y={},f=null,w=null;d!==void 0&&(f=""+d),h.key!==void 0&&(f=""+h.key),h.ref!==void 0&&(w=h.ref);for(g in h)s.call(h,g)&&!l.hasOwnProperty(g)&&(y[g]=h[g]);if(u&&u.defaultProps)for(g in h=u.defaultProps,h)y[g]===void 0&&(y[g]=h[g]);return{$$typeof:o,type:u,key:f,ref:w,props:y,_owner:c.current}}return fo.Fragment=r,fo.jsx=m,fo.jsxs=m,fo}var Hm;function nk(){return Hm||(Hm=1,Jc.exports=ak()),Jc.exports}var B=nk(),E=Tu();const de=Fr(E),Pu=ek({__proto__:null,default:de},[E]);var Ys={},iu={exports:{}},aa={},au={exports:{}},nu={};/**
* @license React
* scheduler.production.min.js
*
@@ -22,7 +22,7 @@ var ik=Object.defineProperty;var ak=(a,o,r)=>o in a?ik(a,o,{enumerable:!0,config
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var $m;function tk(){return $m||($m=1,(function(a){function o(W,ne){var X=W.length;W.push(ne);e:for(;0<X;){var q=X-1>>>1,I=W[q];if(0<c(I,ne))W[q]=ne,W[X]=I,X=q;else break e}}function r(W){return W.length===0?null:W[0]}function s(W){if(W.length===0)return null;var ne=W[0],X=W.pop();if(X!==ne){W[0]=X;e:for(var q=0,I=W.length,L=I>>>1;q<L;){var $=2*(q+1)-1,te=W[$],pe=$+1,ge=W[pe];if(0>c(te,X))pe<I&&0>c(ge,te)?(W[q]=ge,W[pe]=X,q=pe):(W[q]=te,W[$]=X,q=$);else if(pe<I&&0>c(ge,X))W[q]=ge,W[pe]=X,q=pe;else break e}}return ne}function c(W,ne){var X=W.sortIndex-ne.sortIndex;return X!==0?X:W.id-ne.id}if(typeof performance=="object"&&typeof performance.now=="function"){var l=performance;a.unstable_now=function(){return l.now()}}else{var m=Date,u=m.now();a.unstable_now=function(){return m.now()-u}}var h=[],d=[],g=1,y=null,f=3,w=!1,k=!1,z=!1,v=typeof setTimeout=="function"?setTimeout:null,j=typeof clearTimeout=="function"?clearTimeout:null,A=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function x(W){for(var ne=r(d);ne!==null;){if(ne.callback===null)s(d);else if(ne.startTime<=W)s(d),ne.sortIndex=ne.expirationTime,o(h,ne);else break;ne=r(d)}}function _(W){if(z=!1,x(W),!k)if(r(h)!==null)k=!0,Z(C);else{var ne=r(d);ne!==null&&ae(_,ne.startTime-W)}}function C(W,ne){k=!1,z&&(z=!1,j(R),R=-1),w=!0;var X=f;try{for(x(ne),y=r(h);y!==null&&(!(y.expirationTime>ne)||W&&!T());){var q=y.callback;if(typeof q=="function"){y.callback=null,f=y.priorityLevel;var I=q(y.expirationTime<=ne);ne=a.unstable_now(),typeof I=="function"?y.callback=I:y===r(h)&&s(h),x(ne)}else s(h);y=r(h)}if(y!==null)var L=!0;else{var $=r(d);$!==null&&ae(_,$.startTime-ne),L=!1}return L}finally{y=null,f=X,w=!1}}var D=!1,F=null,R=-1,M=5,N=-1;function T(){return!(a.unstable_now()-N<M)}function U(){if(F!==null){var W=a.unstable_now();N=W;var ne=!0;try{ne=F(!0,W)}finally{ne?H():(D=!1,F=null)}}else D=!1}var H;if(typeof A=="function")H=function(){A(U)};else if(typeof MessageChannel<"u"){var K=new MessageChannel,ie=K.port2;K.port1.onmessage=U,H=function(){ie.postMessage(null)}}else H=function(){v(U,0)};function Z(W){F=W,D||(D=!0,H())}function ae(W,ne){R=v(function(){W(a.unstable_now())},ne)}a.unstable_IdlePriority=5,a.unstable_ImmediatePriority=1,a.unstable_LowPriority=4,a.unstable_NormalPriority=3,a.unstable_Profiling=null,a.unstable_UserBlockingPriority=2,a.unstable_cancelCallback=function(W){W.callback=null},a.unstable_continueExecution=function(){k||w||(k=!0,Z(C))},a.unstable_forceFrameRate=function(W){0>W||125<W?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):M=0<W?Math.floor(1e3/W):5},a.unstable_getCurrentPriorityLevel=function(){return f},a.unstable_getFirstCallbackNode=function(){return r(h)},a.unstable_next=function(W){switch(f){case 1:case 2:case 3:var ne=3;break;default:ne=f}var X=f;f=ne;try{return W()}finally{f=X}},a.unstable_pauseExecution=function(){},a.unstable_requestPaint=function(){},a.unstable_runWithPriority=function(W,ne){switch(W){case 1:case 2:case 3:case 4:case 5:break;default:W=3}var X=f;f=W;try{return ne()}finally{f=X}},a.unstable_scheduleCallback=function(W,ne,X){var q=a.unstable_now();switch(typeof X=="object"&&X!==null?(X=X.delay,X=typeof X=="number"&&0<X?q+X:q):X=q,W){case 1:var I=-1;break;case 2:I=250;break;case 5:I=1073741823;break;case 4:I=1e4;break;default:I=5e3}return I=X+I,W={id:g++,callback:ne,priorityLevel:W,startTime:X,expirationTime:I,sortIndex:-1},X>q?(W.sortIndex=X,o(d,W),r(h)===null&&W===r(d)&&(z?(j(R),R=-1):z=!0,ae(_,X-q))):(W.sortIndex=I,o(h,W),k||w||(k=!0,Z(C))),W},a.unstable_shouldYield=T,a.unstable_wrapCallback=function(W){var ne=f;return function(){var X=f;f=ne;try{return W.apply(this,arguments)}finally{f=X}}}})(ou)),ou}var Gm;function lk(){return Gm||(Gm=1,ru.exports=tk()),ru.exports}/**
*/var Vm;function rk(){return Vm||(Vm=1,(function(a){function o(W,ne){var X=W.length;W.push(ne);e:for(;0<X;){var A=X-1>>>1,I=W[A];if(0<c(I,ne))W[A]=ne,W[X]=I,X=A;else break e}}function r(W){return W.length===0?null:W[0]}function s(W){if(W.length===0)return null;var ne=W[0],X=W.pop();if(X!==ne){W[0]=X;e:for(var A=0,I=W.length,L=I>>>1;A<L;){var $=2*(A+1)-1,te=W[$],pe=$+1,ge=W[pe];if(0>c(te,X))pe<I&&0>c(ge,te)?(W[A]=ge,W[pe]=X,A=pe):(W[A]=te,W[$]=X,A=$);else if(pe<I&&0>c(ge,X))W[A]=ge,W[pe]=X,A=pe;else break e}}return ne}function c(W,ne){var X=W.sortIndex-ne.sortIndex;return X!==0?X:W.id-ne.id}if(typeof performance=="object"&&typeof performance.now=="function"){var l=performance;a.unstable_now=function(){return l.now()}}else{var m=Date,u=m.now();a.unstable_now=function(){return m.now()-u}}var h=[],d=[],g=1,y=null,f=3,w=!1,k=!1,z=!1,v=typeof setTimeout=="function"?setTimeout:null,j=typeof clearTimeout=="function"?clearTimeout:null,q=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function x(W){for(var ne=r(d);ne!==null;){if(ne.callback===null)s(d);else if(ne.startTime<=W)s(d),ne.sortIndex=ne.expirationTime,o(h,ne);else break;ne=r(d)}}function _(W){if(z=!1,x(W),!k)if(r(h)!==null)k=!0,Z(C);else{var ne=r(d);ne!==null&&ae(_,ne.startTime-W)}}function C(W,ne){k=!1,z&&(z=!1,j(F),F=-1),w=!0;var X=f;try{for(x(ne),y=r(h);y!==null&&(!(y.expirationTime>ne)||W&&!T());){var A=y.callback;if(typeof A=="function"){y.callback=null,f=y.priorityLevel;var I=A(y.expirationTime<=ne);ne=a.unstable_now(),typeof I=="function"?y.callback=I:y===r(h)&&s(h),x(ne)}else s(h);y=r(h)}if(y!==null)var L=!0;else{var $=r(d);$!==null&&ae(_,$.startTime-ne),L=!1}return L}finally{y=null,f=X,w=!1}}var D=!1,R=null,F=-1,M=5,P=-1;function T(){return!(a.unstable_now()-P<M)}function U(){if(R!==null){var W=a.unstable_now();P=W;var ne=!0;try{ne=R(!0,W)}finally{ne?H():(D=!1,R=null)}}else D=!1}var H;if(typeof q=="function")H=function(){q(U)};else if(typeof MessageChannel<"u"){var K=new MessageChannel,ie=K.port2;K.port1.onmessage=U,H=function(){ie.postMessage(null)}}else H=function(){v(U,0)};function Z(W){R=W,D||(D=!0,H())}function ae(W,ne){F=v(function(){W(a.unstable_now())},ne)}a.unstable_IdlePriority=5,a.unstable_ImmediatePriority=1,a.unstable_LowPriority=4,a.unstable_NormalPriority=3,a.unstable_Profiling=null,a.unstable_UserBlockingPriority=2,a.unstable_cancelCallback=function(W){W.callback=null},a.unstable_continueExecution=function(){k||w||(k=!0,Z(C))},a.unstable_forceFrameRate=function(W){0>W||125<W?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):M=0<W?Math.floor(1e3/W):5},a.unstable_getCurrentPriorityLevel=function(){return f},a.unstable_getFirstCallbackNode=function(){return r(h)},a.unstable_next=function(W){switch(f){case 1:case 2:case 3:var ne=3;break;default:ne=f}var X=f;f=ne;try{return W()}finally{f=X}},a.unstable_pauseExecution=function(){},a.unstable_requestPaint=function(){},a.unstable_runWithPriority=function(W,ne){switch(W){case 1:case 2:case 3:case 4:case 5:break;default:W=3}var X=f;f=W;try{return ne()}finally{f=X}},a.unstable_scheduleCallback=function(W,ne,X){var A=a.unstable_now();switch(typeof X=="object"&&X!==null?(X=X.delay,X=typeof X=="number"&&0<X?A+X:A):X=A,W){case 1:var I=-1;break;case 2:I=250;break;case 5:I=1073741823;break;case 4:I=1e4;break;default:I=5e3}return I=X+I,W={id:g++,callback:ne,priorityLevel:W,startTime:X,expirationTime:I,sortIndex:-1},X>A?(W.sortIndex=X,o(d,W),r(h)===null&&W===r(d)&&(z?(j(F),F=-1):z=!0,ae(_,X-A))):(W.sortIndex=I,o(h,W),k||w||(k=!0,Z(C))),W},a.unstable_shouldYield=T,a.unstable_wrapCallback=function(W){var ne=f;return function(){var X=f;f=ne;try{return W.apply(this,arguments)}finally{f=X}}}})(nu)),nu}var Um;function ok(){return Um||(Um=1,au.exports=rk()),au.exports}/**
* @license React
* react-dom.production.min.js
*
@@ -30,56 +30,56 @@ var ik=Object.defineProperty;var ak=(a,o,r)=>o in a?ik(a,o,{enumerable:!0,config
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var Qm;function ck(){if(Qm)return aa;Qm=1;var a=Iu(),o=lk();function r(e){for(var i="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)i+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+i+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var s=new Set,c={};function l(e,i){m(e,i),m(e+"Capture",i)}function m(e,i){for(c[e]=i,e=0;e<i.length;e++)s.add(i[e])}var u=!(typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),h=Object.prototype.hasOwnProperty,d=/^[: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]*$/,g={},y={};function f(e){return h.call(y,e)?!0:h.call(g,e)?!1:d.test(e)?y[e]=!0:(g[e]=!0,!1)}function w(e,i,n,t){if(n!==null&&n.type===0)return!1;switch(typeof i){case"function":case"symbol":return!0;case"boolean":return t?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function k(e,i,n,t){if(i===null||typeof i>"u"||w(e,i,n,t))return!0;if(t)return!1;if(n!==null)switch(n.type){case 3:return!i;case 4:return i===!1;case 5:return isNaN(i);case 6:return isNaN(i)||1>i}return!1}function z(e,i,n,t,p,b,S){this.acceptsBooleans=i===2||i===3||i===4,this.attributeName=t,this.attributeNamespace=p,this.mustUseProperty=n,this.propertyName=e,this.type=i,this.sanitizeURL=b,this.removeEmptyString=S}var v={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){v[e]=new z(e,0,!1,e,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var i=e[0];v[i]=new z(i,1,!1,e[1],null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){v[e]=new z(e,2,!1,e.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){v[e]=new z(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){v[e]=new z(e,3,!1,e.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(e){v[e]=new z(e,3,!0,e,null,!1,!1)}),["capture","download"].forEach(function(e){v[e]=new z(e,4,!1,e,null,!1,!1)}),["cols","rows","size","span"].forEach(function(e){v[e]=new z(e,6,!1,e,null,!1,!1)}),["rowSpan","start"].forEach(function(e){v[e]=new z(e,5,!1,e.toLowerCase(),null,!1,!1)});var j=/[\-:]([a-z])/g;function A(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 i=e.replace(j,A);v[i]=new z(i,1,!1,e,null,!1,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var i=e.replace(j,A);v[i]=new z(i,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(e){var i=e.replace(j,A);v[i]=new z(i,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(e){v[e]=new z(e,1,!1,e.toLowerCase(),null,!1,!1)}),v.xlinkHref=new z("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(e){v[e]=new z(e,1,!1,e.toLowerCase(),null,!0,!0)});function x(e,i,n,t){var p=v.hasOwnProperty(i)?v[i]:null;(p!==null?p.type!==0:t||!(2<i.length)||i[0]!=="o"&&i[0]!=="O"||i[1]!=="n"&&i[1]!= Line truncated
`+q+e}var L=!1;function $(e,i){if(!e||L)return"";L=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(i)if(i=function(){throw Error()},Object.defineProperty(i.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(i,[])}catch(Y){var t=Y}Reflect.construct(e,[],i)}else{try{i.call()}catch(Y){t=Y}e.call(i.prototype)}else{try{throw Error()}catch(Y){t=Y}e()}}catch(Y){if(Y&&t&&typeof Y.stack=="string"){for(var p=Y.stack.split(`
*/var Wm;function sk(){if(Wm)return aa;Wm=1;var a=Tu(),o=ok();function r(e){for(var i="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)i+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+i+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var s=new Set,c={};function l(e,i){m(e,i),m(e+"Capture",i)}function m(e,i){for(c[e]=i,e=0;e<i.length;e++)s.add(i[e])}var u=!(typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),h=Object.prototype.hasOwnProperty,d=/^[: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]*$/,g={},y={};function f(e){return h.call(y,e)?!0:h.call(g,e)?!1:d.test(e)?y[e]=!0:(g[e]=!0,!1)}function w(e,i,n,t){if(n!==null&&n.type===0)return!1;switch(typeof i){case"function":case"symbol":return!0;case"boolean":return t?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function k(e,i,n,t){if(i===null||typeof i>"u"||w(e,i,n,t))return!0;if(t)return!1;if(n!==null)switch(n.type){case 3:return!i;case 4:return i===!1;case 5:return isNaN(i);case 6:return isNaN(i)||1>i}return!1}function z(e,i,n,t,p,b,S){this.acceptsBooleans=i===2||i===3||i===4,this.attributeName=t,this.attributeNamespace=p,this.mustUseProperty=n,this.propertyName=e,this.type=i,this.sanitizeURL=b,this.removeEmptyString=S}var v={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){v[e]=new z(e,0,!1,e,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var i=e[0];v[i]=new z(i,1,!1,e[1],null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){v[e]=new z(e,2,!1,e.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){v[e]=new z(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){v[e]=new z(e,3,!1,e.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(e){v[e]=new z(e,3,!0,e,null,!1,!1)}),["capture","download"].forEach(function(e){v[e]=new z(e,4,!1,e,null,!1,!1)}),["cols","rows","size","span"].forEach(function(e){v[e]=new z(e,6,!1,e,null,!1,!1)}),["rowSpan","start"].forEach(function(e){v[e]=new z(e,5,!1,e.toLowerCase(),null,!1,!1)});var j=/[\-:]([a-z])/g;function q(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 i=e.replace(j,q);v[i]=new z(i,1,!1,e,null,!1,!1)}),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var i=e.replace(j,q);v[i]=new z(i,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(e){var i=e.replace(j,q);v[i]=new z(i,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(e){v[e]=new z(e,1,!1,e.toLowerCase(),null,!1,!1)}),v.xlinkHref=new z("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(e){v[e]=new z(e,1,!1,e.toLowerCase(),null,!0,!0)});function x(e,i,n,t){var p=v.hasOwnProperty(i)?v[i]:null;(p!==null?p.type!==0:t||!(2<i.length)||i[0]!=="o"&&i[0]!=="O"||i[1]!=="n"&&i[1]!= Line truncated
`+A+e}var L=!1;function $(e,i){if(!e||L)return"";L=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(i)if(i=function(){throw Error()},Object.defineProperty(i.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(i,[])}catch(Y){var t=Y}Reflect.construct(e,[],i)}else{try{i.call()}catch(Y){t=Y}e.call(i.prototype)}else{try{throw Error()}catch(Y){t=Y}e()}}catch(Y){if(Y&&t&&typeof Y.stack=="string"){for(var p=Y.stack.split(`
`),b=t.stack.split(`
`),S=p.length-1,P=b.length-1;1<=S&&0<=P&&p[S]!==b[P];)P--;for(;1<=S&&0<=P;S--,P--)if(p[S]!==b[P]){if(S!==1||P!==1)do if(S--,P--,0>P||p[S]!==b[P]){var O=`
`+p[S].replace(" at new "," at ");return e.displayName&&O.includes("<anonymous>")&&(O=O.replace("<anonymous>",e.displayName)),O}while(1<=S&&0<=P);break}}}finally{L=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?I(e):""}function te(e){switch(e.tag){case 5:return I(e.type);case 16:return I("Lazy");case 13:return I("Suspense");case 19:return I("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 pe(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 F:return"Fragment";case D:return"Portal";case M:return"Profiler";case R:return"StrictMode";case H:return"Suspense";case K:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case T:return(e.displayName||"Context")+".Consumer";case N:return(e._context.displayName||"Context")+".Provider";case U:var i=e.render;return e=e.displayName,e||(e=i.displayName||i.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case ie:return i=e.displayName||null,i!==null?i:pe(e.type)||"Memo";case Z:i=e._payload,e=e._init;try{return pe(e(i))}catch{}}return null}function ge(e){var i=e.type;switch(e.tag){case 24:return"Cache";case 9:return(i.displayName||"Context")+".Consumer";case 10:return(i._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=i.render,e=e.displayName||e.name||"",i.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return i;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return pe(i);case 8:return i===R?"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 i=="function")return i.displayName||i.name||null;if(typeof i=="string")return i}return null}function re(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Se(e){var i=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(i==="checkbox"||i==="radio")}function Me(e){var i=Se(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,i),t=""+e[i];if(!e.hasOwnProperty(i)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var p=n.get,b=n.set;return Object.defineProperty(e,i,{configurable:!0,get:function(){return p.call(this)},set:function(S){t=""+S,b.call(this,S)}}),Object.defineProperty(e,i,{enumerable:n.enumerable}),{getValue:function(){return t},setValue:function(S){t=""+S},stopTracking:function(){e._valueTracker=null,delete e[i]}}}}function pi(e){e._valueTracker||(e._valueTracker=Me(e))}function he(e){if(!e)return!1;var i=e._valueTracker;if(!i)return!0;var n=i.getValue(),t="";return e&&(t=Se(e)?e.checked?"true":"false":e.value),e=t,e!==n?(i.setValue(e),!0):!1}function Be(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 Ae(e,i){var n=i.checked;return X({},i,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function ji(e,i){var n=i.defaultValue==null?"":i.defaultValue,t=i.checked!=null?i.checked:i.defaultChecked;n=re(i.value!=null?i.value:n),e._wrapperState={initialChecked:t,initialValue:n,controlled:i.type==="checkbox"||i.type==="radio"?i.checked!=null:i.value!=null}}function ti(e,i){i=i.checked,i!=null&&x(e,"checked",i,!1)}function ei(e,i){ti(e,i);var n=re(i.value),t=i.type;if(n!=null)t==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(t==="submit"||t==="reset"){e.removeAttribute("value");return}i.hasOwnProperty("value")?Te(e,i.type,n):i.hasOwnProperty("defaultValue")&&Te(e,i.type,re(i.defaultValue)),i.checked==null&&i.defaultChecked!=null&&(e.defaultChecked=!!i.defaultChecked)}function Ue(e,i,n){if(i.hasOwnProperty("value")||i.hasOwnProperty("defaultValue")){var t=i.type;if(!(t!=="submit"&&t!=="reset"||i.value!==void 0&&i.value!==null))return;i=""+e._wrapperState.initialValue,n||i===e.value||(e.value=i),e.defaultValue=i}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Te(e,i,n){(i!=="number"||Be(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var ii=Array.isArray;function Re(e,i,n,t){if(e=e.options,i){i={};for(var p=0;p<n.length;p++)i["$"+n[p]]=!0;for(n=0;n<e.length;n++)p=i.hasOwnProperty("$"+e[n].value),e[n].selected!==p&&(e[n].selected=p),p&&t&&(e[n].defaultSelected=!0)}else{for(n=""+re(n),i=null,p=0;p<e.length;p++){if(e[p].value===n){e[p].selected=!0,t&&(e[p].defaultSelected=!0);return}i!==null||e[p].disabled||(i=e[p])}i!==null&&(i.selected=!0)}}function Ne(e,i){if(i.dangerouslySetInnerHTML!= Line truncated
`).replace(hv,"")}function cs(e,i,n){if(i=tp(i),tp(e)!==i&&n)throw Error(r(425))}function us(){}var Wl=null,$l=null;function Gl(e,i){return e==="textarea"||e==="noscript"||typeof i.children=="string"||typeof i.children=="number"||typeof i.dangerouslySetInnerHTML=="object"&&i.dangerouslySetInnerHTML!==null&&i.dangerouslySetInnerHTML.__html!=null}var Ql=typeof setTimeout=="function"?setTimeout:void 0,gv=typeof clearTimeout=="function"?clearTimeout:void 0,lp=typeof Promise=="function"?Promise:void 0,yv=typeof queueMicrotask=="function"?queueMicrotask:typeof lp<"u"?function(e){return lp.resolve(null).then(e).catch(bv)}:Ql;function bv(e){setTimeout(function(){throw e})}function Kl(e,i){var n=i,t=0;do{var p=n.nextSibling;if(e.removeChild(n),p&&p.nodeType===8)if(n=p.data,n==="/$"){if(t===0){e.removeChild(p),Ur(i);return}t--}else n!=="$"&&n!=="$?"&&n!=="$!"||t++;n=p}while(n);Ur(i)}function un(e){for(;e!=null;e=e.nextSibling){var i=e.nodeType;if(i===1||i===3)break;if(i===8){if(i=e.data,i==="$"||i==="$!"||i==="$?")break;if(i==="/$")return null}}return e}function cp(e){e=e.previousSibling;for(var i=0;e;){if(e.nodeType===8){var n=e.data;if(n==="$"||n==="$!"||n==="$?"){if(i===0)return e;i--}else n==="/$"&&i++}e=e.previousSibling}return null}var tr=Math.random().toString(36).slice(2),Ra="__reactFiber$"+tr,io="__reactProps$"+tr,Ua="__reactContainer$"+tr,Yl="__reactEvents$"+tr,fv="__reactListeners$"+tr,vv="__reactHandles$"+tr;function Sn(e){var i=e[Ra];if(i)return i;for(var n=e.parentNode;n;){if(i=n[Ua]||n[Ra]){if(n=i.alternate,i.child!==null||n!==null&&n.child!==null)for(e=cp(e);e!==null;){if(n=e[Ra])return n;e=cp(e)}return i}e=n,n=e.parentNode}return null}function ao(e){return e=e[Ra]||e[Ua],!e||e.tag!==5&&e.tag!==6&&e.tag!==13&&e.tag!==3?null:e}function lr(e){if(e.tag===5||e.tag===6)return e.stateNode;throw Error(r(33))}function ds(e){return e[io]||null}var Zl=[],cr=-1;function dn(e){return{current:e}}function ui(e){0>cr||(e.current=Zl[cr],Zl[cr]=null,cr--)}function si(e,i){cr++,Zl[cr]=e.current,e.current=i}var pn={},Oi=dn(pn),Zi=dn(!1),Bn=pn;function ur(e,i){var n=e.type.contextTypes;if(!n)return pn;var t=e.stateNode;if(t&&t.__reactInternalMemoizedUnmaskedChildContext===i)return t.__reactInternalMemoizedMaskedChildContext;var p={},b;for(b in n)p[b]=i[b];return t&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=i,e.__reactInternalMemoizedMaskedChildContext=p),p}function Xi(e){return e=e.childContextTypes,e!=null}function ps(){ui(Zi),ui(Oi)}function up(e,i,n){if(Oi.current!==pn)throw Error(r(168));si(Oi,i),si(Zi,n)}function dp(e,i,n){var t=e.stateNode;if(i=i.childContextTypes,typeof t.getChildContext!="function")return n;t=t.getChildContext();for(var p in t)if(!(p in i))throw Error(r(108,ge(e)||"Unknown",p));return X({},n,t)}function ms(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||pn,Bn=Oi.current,si(Oi,e),si(Zi,Zi.current),!0}function pp(e,i,n){var t=e.stateNode;if(!t)throw Error(r(169));n?(e=dp(e,i,Bn),t.__reactInternalMemoizedMergedChildContext=e,ui(Zi),ui(Oi),si(Oi,e)):ui(Zi),si(Zi,n)}var Wa=null,hs=!1,Xl=!1;function mp(e){Wa===null?Wa=[e]:Wa.push(e)}function kv(e){hs=!0,mp(e)}function mn(){if(!Xl&&Wa!==null){Xl=!0;var e=0,i=ai;try{var n=Wa;for(ai=1;e<n.length;e++){var t=n[e];do t=t(!0);while(t!==null)}Wa=null,hs=!1}catch(p){throw Wa!==null&&(Wa=Wa.slice(e+1)),gd(kl,mn),p}finally{ai=i,Xl=!1}}return null}var dr=[],pr=0,gs=null,ys=0,pa=[],ma=0,_n=null,$a=1,Ga="";function Dn(e,i){dr[pr++]=ys,dr[pr++]=gs,gs=e,ys=i}function hp(e,i,n){pa[ma++]=$a,pa[ma++]=Ga,pa[ma++]=_n,_n=e;var t=$a;e=Ga;var p=32-xa(t)-1;t&=~(1<<p),n+=1;var b=32-xa(i)+p;if(30<b){var S=p-p%5;b=(t&(1<<S)-1).toString(32),t>>=S,p-=S,$a=1<<32-xa(i)+p|n<<p|t,Ga=b+e}else $a=1<<b|n<<p|t,Ga=e}function Jl(e){e.return!==null&&(Dn(e,1),hp(e,1,0))}function ec(e){for(;e===gs;)gs=dr[--pr],dr[pr]=null,ys=dr[--pr],dr[pr]=null;for(;e===_n;)_n=pa[--ma],pa[ma]=null,Ga=pa[--ma],pa[ma]=null,$a=pa[--ma],pa[ma]=null}var sa=null,ta=null,di=!1,qa=null;function gp(e,i){var n=ba(5,null,null,0);n.elementType="DELETED",n.stateNode=i,n.return=e,i=e.deletions,i===null?(e.deletions=[n],e.flags|=16):i.push(n)}function yp(e,i){switch(e.tag){case 5:var n=e.type;return i=i.nodeType!==1||n.toLowerCase()!==i.nodeName.toLowerCase()?null:i,i!==null?(e.stateNode=i,sa=e,ta=un(i.firstChild),!0):!1;case 6:return i=e.pendingProps===""||i.nodeType!==3?null:i,i!==null?(e.stateNode=i,sa=e,ta=null,!0):!1;case 13:return i=i.nodeType!==8?null:i,i!==null?(n=_n!==null?{id:$a,overflow:Ga}:null,e.memoizedState={dehydrated:i,treeContext:n,retryLane:1073741824},n=ba(18,null,null,0),n.stateNode=i,n.return=e,e.child=n,sa=e,ta=null,!0):!1;default:return!1}}function ic(e){return(e.mode&1)!==0&&(e.flags&128)===0}function ac(e){if(di){var i=ta;if(i){var n=i;if(!yp(e,i)){if(ic(e))throw Error(r(418));i=un(n.nextSibling);var t=sa;i&&yp(e,i)?gp(t,n):(e.flags=e.flags&-4097|2,di=!1,sa=e)}}else{if(ic(e))throw Error(r(418));e.flags=e.flags&-4097|2,di=!1,sa=e}}}function bp(e){for(e=e. Line truncated
`),S=p.length-1,N=b.length-1;1<=S&&0<=N&&p[S]!==b[N];)N--;for(;1<=S&&0<=N;S--,N--)if(p[S]!==b[N]){if(S!==1||N!==1)do if(S--,N--,0>N||p[S]!==b[N]){var O=`
`+p[S].replace(" at new "," at ");return e.displayName&&O.includes("<anonymous>")&&(O=O.replace("<anonymous>",e.displayName)),O}while(1<=S&&0<=N);break}}}finally{L=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?I(e):""}function te(e){switch(e.tag){case 5:return I(e.type);case 16:return I("Lazy");case 13:return I("Suspense");case 19:return I("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 pe(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 R:return"Fragment";case D:return"Portal";case M:return"Profiler";case F:return"StrictMode";case H:return"Suspense";case K:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case T:return(e.displayName||"Context")+".Consumer";case P:return(e._context.displayName||"Context")+".Provider";case U:var i=e.render;return e=e.displayName,e||(e=i.displayName||i.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case ie:return i=e.displayName||null,i!==null?i:pe(e.type)||"Memo";case Z:i=e._payload,e=e._init;try{return pe(e(i))}catch{}}return null}function ge(e){var i=e.type;switch(e.tag){case 24:return"Cache";case 9:return(i.displayName||"Context")+".Consumer";case 10:return(i._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=i.render,e=e.displayName||e.name||"",i.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return i;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return pe(i);case 8:return i===F?"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 i=="function")return i.displayName||i.name||null;if(typeof i=="string")return i}return null}function re(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Se(e){var i=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(i==="checkbox"||i==="radio")}function Me(e){var i=Se(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,i),t=""+e[i];if(!e.hasOwnProperty(i)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var p=n.get,b=n.set;return Object.defineProperty(e,i,{configurable:!0,get:function(){return p.call(this)},set:function(S){t=""+S,b.call(this,S)}}),Object.defineProperty(e,i,{enumerable:n.enumerable}),{getValue:function(){return t},setValue:function(S){t=""+S},stopTracking:function(){e._valueTracker=null,delete e[i]}}}}function pi(e){e._valueTracker||(e._valueTracker=Me(e))}function he(e){if(!e)return!1;var i=e._valueTracker;if(!i)return!0;var n=i.getValue(),t="";return e&&(t=Se(e)?e.checked?"true":"false":e.value),e=t,e!==n?(i.setValue(e),!0):!1}function Be(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 Ae(e,i){var n=i.checked;return X({},i,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function ji(e,i){var n=i.defaultValue==null?"":i.defaultValue,t=i.checked!=null?i.checked:i.defaultChecked;n=re(i.value!=null?i.value:n),e._wrapperState={initialChecked:t,initialValue:n,controlled:i.type==="checkbox"||i.type==="radio"?i.checked!=null:i.value!=null}}function ti(e,i){i=i.checked,i!=null&&x(e,"checked",i,!1)}function ii(e,i){ti(e,i);var n=re(i.value),t=i.type;if(n!=null)t==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(t==="submit"||t==="reset"){e.removeAttribute("value");return}i.hasOwnProperty("value")?Te(e,i.type,n):i.hasOwnProperty("defaultValue")&&Te(e,i.type,re(i.defaultValue)),i.checked==null&&i.defaultChecked!=null&&(e.defaultChecked=!!i.defaultChecked)}function Ue(e,i,n){if(i.hasOwnProperty("value")||i.hasOwnProperty("defaultValue")){var t=i.type;if(!(t!=="submit"&&t!=="reset"||i.value!==void 0&&i.value!==null))return;i=""+e._wrapperState.initialValue,n||i===e.value||(e.value=i),e.defaultValue=i}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Te(e,i,n){(i!=="number"||Be(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var ai=Array.isArray;function Re(e,i,n,t){if(e=e.options,i){i={};for(var p=0;p<n.length;p++)i["$"+n[p]]=!0;for(n=0;n<e.length;n++)p=i.hasOwnProperty("$"+e[n].value),e[n].selected!==p&&(e[n].selected=p),p&&t&&(e[n].defaultSelected=!0)}else{for(n=""+re(n),i=null,p=0;p<e.length;p++){if(e[p].value===n){e[p].selected=!0,t&&(e[p].defaultSelected=!0);return}i!==null||e[p].disabled||(i=e[p])}i!==null&&(i.selected=!0)}}function Ne(e,i){if(i.dangerouslySetInnerHTML!= Line truncated
`).replace(dv,"")}function cs(e,i,n){if(i=rp(i),rp(e)!==i&&n)throw Error(r(425))}function us(){}var Vl=null,Ul=null;function Wl(e,i){return e==="textarea"||e==="noscript"||typeof i.children=="string"||typeof i.children=="number"||typeof i.dangerouslySetInnerHTML=="object"&&i.dangerouslySetInnerHTML!==null&&i.dangerouslySetInnerHTML.__html!=null}var $l=typeof setTimeout=="function"?setTimeout:void 0,pv=typeof clearTimeout=="function"?clearTimeout:void 0,op=typeof Promise=="function"?Promise:void 0,mv=typeof queueMicrotask=="function"?queueMicrotask:typeof op<"u"?function(e){return op.resolve(null).then(e).catch(hv)}:$l;function hv(e){setTimeout(function(){throw e})}function Gl(e,i){var n=i,t=0;do{var p=n.nextSibling;if(e.removeChild(n),p&&p.nodeType===8)if(n=p.data,n==="/$"){if(t===0){e.removeChild(p),Ur(i);return}t--}else n!=="$"&&n!=="$?"&&n!=="$!"||t++;n=p}while(n);Ur(i)}function un(e){for(;e!=null;e=e.nextSibling){var i=e.nodeType;if(i===1||i===3)break;if(i===8){if(i=e.data,i==="$"||i==="$!"||i==="$?")break;if(i==="/$")return null}}return e}function sp(e){e=e.previousSibling;for(var i=0;e;){if(e.nodeType===8){var n=e.data;if(n==="$"||n==="$!"||n==="$?"){if(i===0)return e;i--}else n==="/$"&&i++}e=e.previousSibling}return null}var tr=Math.random().toString(36).slice(2),Fa="__reactFiber$"+tr,io="__reactProps$"+tr,Ua="__reactContainer$"+tr,Ql="__reactEvents$"+tr,gv="__reactListeners$"+tr,yv="__reactHandles$"+tr;function Sn(e){var i=e[Fa];if(i)return i;for(var n=e.parentNode;n;){if(i=n[Ua]||n[Fa]){if(n=i.alternate,i.child!==null||n!==null&&n.child!==null)for(e=sp(e);e!==null;){if(n=e[Fa])return n;e=sp(e)}return i}e=n,n=e.parentNode}return null}function ao(e){return e=e[Fa]||e[Ua],!e||e.tag!==5&&e.tag!==6&&e.tag!==13&&e.tag!==3?null:e}function lr(e){if(e.tag===5||e.tag===6)return e.stateNode;throw Error(r(33))}function ds(e){return e[io]||null}var Kl=[],cr=-1;function dn(e){return{current:e}}function ui(e){0>cr||(e.current=Kl[cr],Kl[cr]=null,cr--)}function si(e,i){cr++,Kl[cr]=e.current,e.current=i}var pn={},Oi=dn(pn),Zi=dn(!1),Bn=pn;function ur(e,i){var n=e.type.contextTypes;if(!n)return pn;var t=e.stateNode;if(t&&t.__reactInternalMemoizedUnmaskedChildContext===i)return t.__reactInternalMemoizedMaskedChildContext;var p={},b;for(b in n)p[b]=i[b];return t&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=i,e.__reactInternalMemoizedMaskedChildContext=p),p}function Xi(e){return e=e.childContextTypes,e!=null}function ps(){ui(Zi),ui(Oi)}function tp(e,i,n){if(Oi.current!==pn)throw Error(r(168));si(Oi,i),si(Zi,n)}function lp(e,i,n){var t=e.stateNode;if(i=i.childContextTypes,typeof t.getChildContext!="function")return n;t=t.getChildContext();for(var p in t)if(!(p in i))throw Error(r(108,ge(e)||"Unknown",p));return X({},n,t)}function ms(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||pn,Bn=Oi.current,si(Oi,e),si(Zi,Zi.current),!0}function cp(e,i,n){var t=e.stateNode;if(!t)throw Error(r(169));n?(e=lp(e,i,Bn),t.__reactInternalMemoizedMergedChildContext=e,ui(Zi),ui(Oi),si(Oi,e)):ui(Zi),si(Zi,n)}var Wa=null,hs=!1,Yl=!1;function up(e){Wa===null?Wa=[e]:Wa.push(e)}function bv(e){hs=!0,up(e)}function mn(){if(!Yl&&Wa!==null){Yl=!0;var e=0,i=ni;try{var n=Wa;for(ni=1;e<n.length;e++){var t=n[e];do t=t(!0);while(t!==null)}Wa=null,hs=!1}catch(p){throw Wa!==null&&(Wa=Wa.slice(e+1)),pd(fl,mn),p}finally{ni=i,Yl=!1}}return null}var dr=[],pr=0,gs=null,ys=0,pa=[],ma=0,_n=null,$a=1,Ga="";function Dn(e,i){dr[pr++]=ys,dr[pr++]=gs,gs=e,ys=i}function dp(e,i,n){pa[ma++]=$a,pa[ma++]=Ga,pa[ma++]=_n,_n=e;var t=$a;e=Ga;var p=32-za(t)-1;t&=~(1<<p),n+=1;var b=32-za(i)+p;if(30<b){var S=p-p%5;b=(t&(1<<S)-1).toString(32),t>>=S,p-=S,$a=1<<32-za(i)+p|n<<p|t,Ga=b+e}else $a=1<<b|n<<p|t,Ga=e}function Zl(e){e.return!==null&&(Dn(e,1),dp(e,1,0))}function Xl(e){for(;e===gs;)gs=dr[--pr],dr[pr]=null,ys=dr[--pr],dr[pr]=null;for(;e===_n;)_n=pa[--ma],pa[ma]=null,Ga=pa[--ma],pa[ma]=null,$a=pa[--ma],pa[ma]=null}var sa=null,ta=null,di=!1,ja=null;function pp(e,i){var n=ba(5,null,null,0);n.elementType="DELETED",n.stateNode=i,n.return=e,i=e.deletions,i===null?(e.deletions=[n],e.flags|=16):i.push(n)}function mp(e,i){switch(e.tag){case 5:var n=e.type;return i=i.nodeType!==1||n.toLowerCase()!==i.nodeName.toLowerCase()?null:i,i!==null?(e.stateNode=i,sa=e,ta=un(i.firstChild),!0):!1;case 6:return i=e.pendingProps===""||i.nodeType!==3?null:i,i!==null?(e.stateNode=i,sa=e,ta=null,!0):!1;case 13:return i=i.nodeType!==8?null:i,i!==null?(n=_n!==null?{id:$a,overflow:Ga}:null,e.memoizedState={dehydrated:i,treeContext:n,retryLane:1073741824},n=ba(18,null,null,0),n.stateNode=i,n.return=e,e.child=n,sa=e,ta=null,!0):!1;default:return!1}}function Jl(e){return(e.mode&1)!==0&&(e.flags&128)===0}function ec(e){if(di){var i=ta;if(i){var n=i;if(!mp(e,i)){if(Jl(e))throw Error(r(418));i=un(n.nextSibling);var t=sa;i&&mp(e,i)?pp(t,n):(e.flags=e.flags&-4097|2,di=!1,sa=e)}}else{if(Jl(e))throw Error(r(418));e.flags=e.flags&-4097|2,di=!1,sa=e}}}function hp(e){for(e=e. Line truncated
Error generating stack: `+b.message+`
`+b.stack}return{value:e,source:i,stack:p,digest:null}}function jc(e,i,n){return{value:e,source:null,stack:n??null,digest:i??null}}function qc(e,i){try{console.error(i.value)}catch(n){setTimeout(function(){throw n})}}var Sv=typeof WeakMap=="function"?WeakMap:Map;function Zp(e,i,n){n=Ka(-1,n),n.tag=3,n.payload={element:null};var t=i.value;return n.callback=function(){Ps||(Ps=!0,Oc=t),qc(e,i)},n}function Xp(e,i,n){n=Ka(-1,n),n.tag=3;var t=e.type.getDerivedStateFromError;if(typeof t=="function"){var p=i.value;n.payload=function(){return t(p)},n.callback=function(){qc(e,i)}}var b=e.stateNode;return b!==null&&typeof b.componentDidCatch=="function"&&(n.callback=function(){qc(e,i),typeof t!="function"&&(bn===null?bn=new Set([this]):bn.add(this));var S=i.stack;this.componentDidCatch(i.value,{componentStack:S!==null?S:""})}),n}function Jp(e,i,n){var t=e.pingCache;if(t===null){t=e.pingCache=new Sv;var p=new Set;t.set(i,p)}else p=t.get(i),p===void 0&&(p=new Set,t.set(i,p));p.has(n)||(p.add(n),e=Vv.bind(null,e,i,n),i.then(e,e))}function em(e){do{var i;if((i=e.tag===13)&&(i=e.memoizedState,i=i!==null?i.dehydrated!==null:!0),i)return e;e=e.return}while(e!==null);return null}function im(e,i,n,t,p){return(e.mode&1)===0?(e===i?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,n.tag===1&&(n.alternate===null?n.tag=17:(i=Ka(-1,1),i.tag=2,gn(n,i,1))),n.lanes|=1),e):(e.flags|=65536,e.lanes=p,e)}var Bv=_.ReactCurrentOwner,Ji=!1;function $i(e,i,n,t){i.child=e===null?wp(i,null,n,t):hr(i,e.child,n,t)}function am(e,i,n,t,p){n=n.render;var b=i.ref;return yr(i,p),t=yc(e,i,n,t,b,p),n=bc(),e!==null&&!Ji?(i.updateQueue=e.updateQueue,i.flags&=-2053,e.lanes&=~p,Ya(e,i,p)):(di&&n&&Jl(i),i.flags|=1,$i(e,i,t,p),i.child)}function nm(e,i,n,t,p){if(e===null){var b=n.type;return typeof b=="function"&&!Gc(b)&&b.defaultProps===void 0&&n.compare===null&&n.defaultProps===void 0?(i.tag=15,i.type=b,rm(e,i,b,t,p)):(e=Hs(n.type,null,t,i,i.mode,p),e.ref=i.ref,e.return=i,i.child=e)}if(b=e.child,(e.lanes&p)===0){var S=b.memoizedProps;if(n=n.compare,n=n!==null?n:Yr,n(S,t)&&e.ref===i.ref)return Ya(e,i,p)}return i.flags|=1,e=wn(b,t),e.ref=i.ref,e.return=i,i.child=e}function rm(e,i,n,t,p){if(e!==null){var b=e.memoizedProps;if(Yr(b,t)&&e.ref===i.ref)if(Ji=!1,i.pendingProps=t=b,(e.lanes&p)!==0)(e.flags&131072)!==0&&(Ji=!0);else return i.lanes=e.lanes,Ya(e,i,p)}return Ac(e,i,n,t,p)}function om(e,i,n){var t=i.pendingProps,p=t.children,b=e!==null?e.memoizedState:null;if(t.mode==="hidden")if((i.mode&1)===0)i.memoizedState={baseLanes:0,cachePool:null,transitions:null},si(kr,la),la|=n;else{if((n&1073741824)===0)return e=b!==null?b.baseLanes|n:n,i.lanes=i.childLanes=1073741824,i.memoizedState={baseLanes:e,cachePool:null,transitions:null},i.updateQueue=null,si(kr,la),la|=e,null;i.memoizedState={baseLanes:0,cachePool:null,transitions:null},t=b!==null?b.baseLanes:n,si(kr,la),la|=t}else b!==null?(t=b.baseLanes|n,i.memoizedState=null):t=n,si(kr,la),la|=t;return $i(e,i,p,n),i.child}function sm(e,i){var n=i.ref;(e===null&&n!==null||e!==null&&e.ref!==n)&&(i.flags|=512,i.flags|=2097152)}function Ac(e,i,n,t,p){var b=Xi(n)?Bn:Oi.current;return b=ur(i,b),yr(i,p),n=yc(e,i,n,t,b,p),t=bc(),e!==null&&!Ji?(i.updateQueue=e.updateQueue,i.flags&=-2053,e.lanes&=~p,Ya(e,i,p)):(di&&t&&Jl(i),i.flags|=1,$i(e,i,n,p),i.child)}function tm(e,i,n,t,p){if(Xi(n)){var b=!0;ms(i)}else b=!1;if(yr(i,p),i.stateNode===null)_s(e,i),Kp(i,n,t),xc(i,n,t,p),t=!0;else if(e===null){var S=i.stateNode,P=i.memoizedProps;S.props=P;var O=S.context,Y=n.contextType;typeof Y=="object"&&Y!==null?Y=ha(Y):(Y=Xi(n)?Bn:Oi.current,Y=ur(i,Y));var se=n.getDerivedStateFromProps,le=typeof se=="function"||typeof S.getSnapshotBeforeUpdate=="function";le||typeof S.UNSAFE_componentWillReceiveProps!="function"&&typeof S.componentWillReceiveProps!="function"||(P!==t||O!==Y)&&Yp(i,S,t,Y),hn=!1;var oe=i.memoizedState;S.state=oe,zs(i,t,S,p),O=i.memoizedState,P!==t||oe!==O||Zi.current||hn?(typeof se=="function"&&(zc(i,n,se,t),O=i.memoizedState),(P=hn||Qp(i,n,P,t,oe,O,Y))?(le||typeof S.UNSAFE_componentWillMount!="function"&&typeof S.componentWillMount!="function"||(typeof S.componentWillMount=="function"&&S.componentWillMount(),typeof S.UNSAFE_componentWillMount=="function"&&S.UNSAFE_componentWillMount()),typeof S.componentDidMount=="function"&&(i.flags|=4194308)):(typeof S.componentDidMount=="function"&&(i.flags|=4194308),i.memoizedProps=t,i.memoizedState=O),S.props=t,S.state=O,S.context=Y,t=P):(typeof S.componentDidMount=="function"&&(i.flags|=4194308),t=!1)}else{S=i.stateNode,xp(e,i),P=i.memoizedProps,Y=i.type===i.elementType?P:Aa(i.type,P),S.props=Y,le=i.pendingProps,oe=S.context,O=n.contextType,typeof O=="object"&&O!==null?O=ha(O):(O=Xi(n)?Bn:Oi.current,O=ur(i,O));var ye=n.getDerivedStateFromProps;(se=typeof ye=="function"||typeof S.getSnapshotBeforeUpdate=="function")||typeof S.UNSAFE_componentWillReceiveProps!="function"&&typeof S.componentWillReceiveProps!="function"||(P!==le||oe!==O)&&Yp(i,S,t,O),hn=!1,oe=i.memoizedState,S Line truncated
`)}function gk(a){if(a.length===0)return`Neighbors
No neighbors reported`;const o=[...a].sort((s,c)=>c.snr-s.snr),r=[`Neighbors (${o.length})`];for(const s of o){const c=s.name||s.pubkey_prefix,l=s.snr>=0?`+${s.snr.toFixed(1)}`:s.snr.toFixed(1);r.push(`${c}, ${l} dB [${tt(s.last_heard_seconds)} ago]`)}return r.join(`
`)}function yk(a){if(a.length===0)return`ACL
`+b.stack}return{value:e,source:i,stack:p,digest:null}}function zc(e,i,n){return{value:e,source:null,stack:n??null,digest:i??null}}function xc(e,i){try{console.error(i.value)}catch(n){setTimeout(function(){throw n})}}var Av=typeof WeakMap=="function"?WeakMap:Map;function Qp(e,i,n){n=Ka(-1,n),n.tag=3,n.payload={element:null};var t=i.value;return n.callback=function(){Ps||(Ps=!0,Ic=t),xc(e,i)},n}function Kp(e,i,n){n=Ka(-1,n),n.tag=3;var t=e.type.getDerivedStateFromError;if(typeof t=="function"){var p=i.value;n.payload=function(){return t(p)},n.callback=function(){xc(e,i)}}var b=e.stateNode;return b!==null&&typeof b.componentDidCatch=="function"&&(n.callback=function(){xc(e,i),typeof t!="function"&&(bn===null?bn=new Set([this]):bn.add(this));var S=i.stack;this.componentDidCatch(i.value,{componentStack:S!==null?S:""})}),n}function Yp(e,i,n){var t=e.pingCache;if(t===null){t=e.pingCache=new Av;var p=new Set;t.set(i,p)}else p=t.get(i),p===void 0&&(p=new Set,t.set(i,p));p.has(n)||(p.add(n),e=Ov.bind(null,e,i,n),i.then(e,e))}function Zp(e){do{var i;if((i=e.tag===13)&&(i=e.memoizedState,i=i!==null?i.dehydrated!==null:!0),i)return e;e=e.return}while(e!==null);return null}function Xp(e,i,n,t,p){return(e.mode&1)===0?(e===i?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,n.tag===1&&(n.alternate===null?n.tag=17:(i=Ka(-1,1),i.tag=2,gn(n,i,1))),n.lanes|=1),e):(e.flags|=65536,e.lanes=p,e)}var Cv=_.ReactCurrentOwner,Ji=!1;function $i(e,i,n,t){i.child=e===null?fp(i,null,n,t):hr(i,e.child,n,t)}function Jp(e,i,n,t,p){n=n.render;var b=i.ref;return yr(i,p),t=hc(e,i,n,t,b,p),n=gc(),e!==null&&!Ji?(i.updateQueue=e.updateQueue,i.flags&=-2053,e.lanes&=~p,Ya(e,i,p)):(di&&n&&Zl(i),i.flags|=1,$i(e,i,t,p),i.child)}function em(e,i,n,t,p){if(e===null){var b=n.type;return typeof b=="function"&&!Wc(b)&&b.defaultProps===void 0&&n.compare===null&&n.defaultProps===void 0?(i.tag=15,i.type=b,im(e,i,b,t,p)):(e=Hs(n.type,null,t,i,i.mode,p),e.ref=i.ref,e.return=i,i.child=e)}if(b=e.child,(e.lanes&p)===0){var S=b.memoizedProps;if(n=n.compare,n=n!==null?n:Yr,n(S,t)&&e.ref===i.ref)return Ya(e,i,p)}return i.flags|=1,e=wn(b,t),e.ref=i.ref,e.return=i,i.child=e}function im(e,i,n,t,p){if(e!==null){var b=e.memoizedProps;if(Yr(b,t)&&e.ref===i.ref)if(Ji=!1,i.pendingProps=t=b,(e.lanes&p)!==0)(e.flags&131072)!==0&&(Ji=!0);else return i.lanes=e.lanes,Ya(e,i,p)}return jc(e,i,n,t,p)}function am(e,i,n){var t=i.pendingProps,p=t.children,b=e!==null?e.memoizedState:null;if(t.mode==="hidden")if((i.mode&1)===0)i.memoizedState={baseLanes:0,cachePool:null,transitions:null},si(kr,la),la|=n;else{if((n&1073741824)===0)return e=b!==null?b.baseLanes|n:n,i.lanes=i.childLanes=1073741824,i.memoizedState={baseLanes:e,cachePool:null,transitions:null},i.updateQueue=null,si(kr,la),la|=e,null;i.memoizedState={baseLanes:0,cachePool:null,transitions:null},t=b!==null?b.baseLanes:n,si(kr,la),la|=t}else b!==null?(t=b.baseLanes|n,i.memoizedState=null):t=n,si(kr,la),la|=t;return $i(e,i,p,n),i.child}function nm(e,i){var n=i.ref;(e===null&&n!==null||e!==null&&e.ref!==n)&&(i.flags|=512,i.flags|=2097152)}function jc(e,i,n,t,p){var b=Xi(n)?Bn:Oi.current;return b=ur(i,b),yr(i,p),n=hc(e,i,n,t,b,p),t=gc(),e!==null&&!Ji?(i.updateQueue=e.updateQueue,i.flags&=-2053,e.lanes&=~p,Ya(e,i,p)):(di&&t&&Zl(i),i.flags|=1,$i(e,i,n,p),i.child)}function rm(e,i,n,t,p){if(Xi(n)){var b=!0;ms(i)}else b=!1;if(yr(i,p),i.stateNode===null)_s(e,i),$p(i,n,t),wc(i,n,t,p),t=!0;else if(e===null){var S=i.stateNode,N=i.memoizedProps;S.props=N;var O=S.context,Y=n.contextType;typeof Y=="object"&&Y!==null?Y=ha(Y):(Y=Xi(n)?Bn:Oi.current,Y=ur(i,Y));var se=n.getDerivedStateFromProps,le=typeof se=="function"||typeof S.getSnapshotBeforeUpdate=="function";le||typeof S.UNSAFE_componentWillReceiveProps!="function"&&typeof S.componentWillReceiveProps!="function"||(N!==t||O!==Y)&&Gp(i,S,t,Y),hn=!1;var oe=i.memoizedState;S.state=oe,zs(i,t,S,p),O=i.memoizedState,N!==t||oe!==O||Zi.current||hn?(typeof se=="function"&&(kc(i,n,se,t),O=i.memoizedState),(N=hn||Wp(i,n,N,t,oe,O,Y))?(le||typeof S.UNSAFE_componentWillMount!="function"&&typeof S.componentWillMount!="function"||(typeof S.componentWillMount=="function"&&S.componentWillMount(),typeof S.UNSAFE_componentWillMount=="function"&&S.UNSAFE_componentWillMount()),typeof S.componentDidMount=="function"&&(i.flags|=4194308)):(typeof S.componentDidMount=="function"&&(i.flags|=4194308),i.memoizedProps=t,i.memoizedState=O),S.props=t,S.state=O,S.context=Y,t=N):(typeof S.componentDidMount=="function"&&(i.flags|=4194308),t=!1)}else{S=i.stateNode,kp(e,i),N=i.memoizedProps,Y=i.type===i.elementType?N:qa(i.type,N),S.props=Y,le=i.pendingProps,oe=S.context,O=n.contextType,typeof O=="object"&&O!==null?O=ha(O):(O=Xi(n)?Bn:Oi.current,O=ur(i,O));var ye=n.getDerivedStateFromProps;(se=typeof ye=="function"||typeof S.getSnapshotBeforeUpdate=="function")||typeof S.UNSAFE_componentWillReceiveProps!="function"&&typeof S.componentWillReceiveProps!="function"||(N!==le||oe!==O)&&Gp(i,S,t,O),hn=!1,oe=i.memoizedState,S Line truncated
`)}function pk(a){if(a.length===0)return`Neighbors
No neighbors reported`;const o=[...a].sort((s,c)=>c.snr-s.snr),r=[`Neighbors (${o.length})`];for(const s of o){const c=s.name||s.pubkey_prefix,l=s.snr>=0?`+${s.snr.toFixed(1)}`:s.snr.toFixed(1);r.push(`${c}, ${l} dB [${st(s.last_heard_seconds)} ago]`)}return r.join(`
`)}function mk(a){if(a.length===0)return`ACL
No ACL entries`;const o=[`ACL (${a.length})`];for(const r of a){const s=r.name||r.pubkey_prefix;o.push(`${s}: ${r.permission_name}`)}return o.join(`
`)}function Hn(a,o,r,s=0){const c=Math.floor(Date.now()/1e3);return{id:-Date.now()-s,type:"PRIV",conversation_key:a,text:o,sender_timestamp:c,received_at:c,path_len:null,txt_type:0,signature:null,outgoing:r,acked:1}}function bk(a,o,r){const[s,c]=E.useState(!1);E.useEffect(()=>{c(!1)},[a==null?void 0:a.id]);const l=E.useMemo(()=>{if(!a||a.type!=="contact")return!1;const h=o.find(d=>d.public_key===a.id);return(h==null?void 0:h.type)===Kg},[a,o]),m=E.useCallback(async h=>{if(!(!a||a.type!=="contact")&&l)try{const d=await Je.requestTelemetry(a.id,h),g=Hn(a.id,hk(d),!1,0),y=Hn(a.id,gk(d.neighbors),!1,1),f=Hn(a.id,yk(d.acl),!1,2);r(w=>[...w,g,y,f]),c(!0)}catch(d){const g=Hn(a.id,`Telemetry request failed: ${d instanceof Error?d.message:"Unknown error"}`,!1,0);r(y=>[...y,g])}},[a,l,r]),u=E.useCallback(async h=>{if(!a||a.type!=="contact"||!l||!s)return;const d=Hn(a.id,`> ${h}`,!0,0);r(g=>[...g,d]);try{const g=await Je.sendRepeaterCommand(a.id,h),y=Hn(a.id,g.response,!1,1);g.sender_timestamp&&(y.sender_timestamp=g.sender_timestamp),r(f=>[...f,y])}catch(g){const y=Hn(a.id,`Command failed: ${g instanceof Error?g.message:"Unknown error"}`,!1,1);r(f=>[...f,y])}},[a,l,s,r]);return{repeaterLoggedIn:s,activeContactIsRepeater:l,handleTelemetryRequest:m,handleRepeaterCommand:u}}const fk=12;function Br(a){return a.slice(0,fk)}function Yg(a,o){return!a||!o?!1:Br(a)===Br(o)}function Yn(a,o){return a||Br(o)}const xu="remoteterm-lastMessageTime",ju="remoteterm-lastReadTime";function rl(a){try{const o=localStorage.getItem(a);return o?JSON.parse(o):{}}catch{return{}}}function Zg(a,o){try{localStorage.setItem(a,JSON.stringify(o))}catch{}}function Zm(){return rl(xu)}function vk(){return rl(ju)}function su(a,o){const r=rl(xu);return(!r[a]||o>r[a])&&(r[a]=o,Zg(xu,r)),r}function Zs(a,o){const r=rl(ju);return r[a]=o,Zg(ju,r),r}function fa(a,o){return a==="channel"?`channel-${o}`:`contact-${Br(o)}`}function kk(a,o,r){const[s,c]=E.useState({}),[l,m]=E.useState(Zm),u=E.useRef(new Set),h=E.useRef(new Set);E.useEffect(()=>{const w=a.filter(v=>!u.current.has(v.key)),k=o.filter(v=>v.public_key&&!h.current.has(v.public_key));if(w.length===0&&k.length===0)return;w.forEach(v=>u.current.add(v.key)),k.forEach(v=>h.current.add(v.public_key)),(async()=>{const v=[...w.map(j=>({type:"CHAN",conversation_key:j.key})),...k.map(j=>({type:"PRIV",conversation_key:j.public_key}))];if(v.length!==0)try{const j=await Je.getMessagesBulk(v,100),A=vk(),x={},_={};for(const C of w){const D=j[`CHAN:${C.key}`]||[];if(D.length>0){const F=fa("channel",C.key),R=A[F]||0,M=D.filter(T=>!T.outgoing&&T.received_at>R).length;M>0&&(x[F]=M);const N=Math.max(...D.map(T=>T.received_at));_[F]=N,su(F,N)}}for(const C of k){const D=j[`PRIV:${C.public_key}`]||[];if(D.length>0){const F=fa("contact",C.public_key),R=A[F]||0,M=D.filter(T=>!T.outgoing&&T.received_at>R).length;M>0&&(x[F]=M);const N=Math.max(...D.map(T=>T.received_at));_[F]=N,su(F,N)}}Object.keys(x).length>0&&c(C=>({...C,...x})),m(Zm())}catch(j){console.error("Failed to fetch messages bulk:",j)}})()},[a,o]),E.useEffect(()=>{if(r&&r.type!=="raw"){const w=fa(r.type,r.id),k=Math.floor(Date.now()/1e3);Zs(w,k),c(z=>{if(z[w]){const v={...z};return delete v[w],v}return z})}},[r]);const d=E.useCallback(w=>{c(k=>({...k,[w]:(k[w]||0)+1}))},[]),g=E.useCallback(()=>{const w=Math.floor(Date.now()/1e3);for(const k of a){const z=fa("channel",k.key);Zs(z,w)}for(const k of o)if(k.public_key){const z=fa("contact",k.public_key);Zs(z,w)}c({})},[a,o]),y=E.useCallback(w=>{if(w.type==="raw")return;const k=fa(w.type,w.id),z=Math.floor(Date.now()/1e3);Zs(k,z),c(v=>{if(v[k]){const j={...v};return delete j[k],j}return v})},[]),f=E.useCallback(w=>{let k=null;if(w.type==="CHAN"&&w.conversation_key?k=fa("channel",w.conversation_key):w.type==="PRIV"&&w.conversation_key&&(k=fa("contact",w.conversation_key)),k){const z=w.received_at||Math.floor(Date.now()/1e3),v=su(k,z);m(v)}},[]);return{unreadCounts:s,lastMessageTimes:l,incrementUnread:d,markAllRead:g,markConversationRead:y,trackNewMessage:f}}const Xs=200;function tu(a){return`${a.type}-${a.conversation_key}-${a.text}-${a.sender_timestamp}`}function wk(a){const[o,r]=E.useState([]),[s,c]=E.useState(!1),[l,m]=E.useState(!1),[u,h]=E.useState(!1),d=E.useRef(new Set),g=E.useCallback(async(k=!1)=>{if(!a||a.type==="raw"){r([]),h(!1);return}k&&c(!0);try{const z=await Je.getMessages({type:a.type==="channel"?"CHAN":"PRIV",conversation_key:a.id,limit:Xs});r(z),d.current.clear();for(const v of z)d.current.add(tu(v));h(z.length>=Xs)}catch(z){console.error("Failed to fetch messages:",z)}finally{k&&c(!1)}},[a]),y=E.useCallback(async()=>{if(!(!a||a.type==="raw"||l||!u)){m(!0);try{const k=await Je.getMessages({type:a.type==="channel"?"CHAN":"PRIV",conversation_key:a.id,limit:Xs,offset:o.length});if(k.length>0){r(z=>[...z,...k]);for(const z of k)d.current.add(tu(z))}h(k.length>=Xs)}catch(k){console.error("Failed to fetch older messages:",k)}finally{m(!1)}}},[a,l,u,o.length]);E.useEffect(()=>{g(!0)},[g]);const f=E.useCallback( Line truncated
`)}function Hn(a,o,r,s=0){const c=Math.floor(Date.now()/1e3);return{id:-Date.now()-s,type:"PRIV",conversation_key:a,text:o,sender_timestamp:c,received_at:c,path_len:null,txt_type:0,signature:null,outgoing:r,acked:1}}function hk(a,o,r){const[s,c]=E.useState(!1);E.useEffect(()=>{c(!1)},[a==null?void 0:a.id]);const l=E.useMemo(()=>{if(!a||a.type!=="contact")return!1;const h=o.find(d=>d.public_key===a.id);return(h==null?void 0:h.type)===$g},[a,o]),m=E.useCallback(async h=>{if(!(!a||a.type!=="contact")&&l)try{const d=await We.requestTelemetry(a.id,h),g=Hn(a.id,dk(d),!1,0),y=Hn(a.id,pk(d.neighbors),!1,1),f=Hn(a.id,mk(d.acl),!1,2);r(w=>[...w,g,y,f]),c(!0)}catch(d){const g=Hn(a.id,`Telemetry request failed: ${d instanceof Error?d.message:"Unknown error"}`,!1,0);r(y=>[...y,g])}},[a,l,r]),u=E.useCallback(async h=>{if(!a||a.type!=="contact"||!l||!s)return;const d=Hn(a.id,`> ${h}`,!0,0);r(g=>[...g,d]);try{const g=await We.sendRepeaterCommand(a.id,h),y=Hn(a.id,g.response,!1,1);g.sender_timestamp&&(y.sender_timestamp=g.sender_timestamp),r(f=>[...f,y])}catch(g){const y=Hn(a.id,`Command failed: ${g instanceof Error?g.message:"Unknown error"}`,!1,1);r(f=>[...f,y])}},[a,l,s,r]);return{repeaterLoggedIn:s,activeContactIsRepeater:l,handleTelemetryRequest:m,handleRepeaterCommand:u}}const gk=12;function Br(a){return a.slice(0,gk)}function Gg(a,o){return!a||!o?!1:Br(a)===Br(o)}function Yn(a,o){return a||Br(o)}const wu="remoteterm-lastMessageTime";function Qg(a){try{const o=localStorage.getItem(a);return o?JSON.parse(o):{}}catch{return{}}}function yk(a,o){try{localStorage.setItem(a,JSON.stringify(o))}catch{}}function Qm(){return Qg(wu)}function ru(a,o){const r=Qg(wu);return(!r[a]||o>r[a])&&(r[a]=o,yk(wu,r)),r}function Oa(a,o){return a==="channel"?`channel-${o}`:`contact-${Br(o)}`}function bk(a,o,r){const[s,c]=E.useState({}),[l,m]=E.useState(Qm),u=E.useRef(new Set),h=E.useRef(new Set);E.useEffect(()=>{const w=a.filter(v=>!u.current.has(v.key)),k=o.filter(v=>v.public_key&&!h.current.has(v.public_key));if(w.length===0&&k.length===0)return;w.forEach(v=>u.current.add(v.key)),k.forEach(v=>h.current.add(v.public_key)),(async()=>{const v=[...w.map(j=>({type:"CHAN",conversation_key:j.key})),...k.map(j=>({type:"PRIV",conversation_key:j.public_key}))];if(v.length!==0)try{const j=await We.getMessagesBulk(v,100),q={},x={};for(const _ of w){const C=j[`CHAN:${_.key}`]||[];if(C.length>0){const D=Oa("channel",_.key),R=_.last_read_at||0,F=C.filter(P=>!P.outgoing&&P.received_at>R).length;F>0&&(q[D]=F);const M=Math.max(...C.map(P=>P.received_at));x[D]=M,ru(D,M)}}for(const _ of k){const C=j[`PRIV:${_.public_key}`]||[];if(C.length>0){const D=Oa("contact",_.public_key),R=_.last_read_at||0,F=C.filter(P=>!P.outgoing&&P.received_at>R).length;F>0&&(q[D]=F);const M=Math.max(...C.map(P=>P.received_at));x[D]=M,ru(D,M)}}Object.keys(q).length>0&&c(_=>({..._,...q})),m(Qm())}catch(j){console.error("Failed to fetch messages bulk:",j)}})()},[a,o]),E.useEffect(()=>{if(r&&r.type!=="raw"){const w=Oa(r.type,r.id);c(k=>{if(k[w]){const z={...k};return delete z[w],z}return k}),r.type==="channel"?We.markChannelRead(r.id).catch(k=>{console.error("Failed to mark channel as read on server:",k)}):r.type==="contact"&&We.markContactRead(r.id).catch(k=>{console.error("Failed to mark contact as read on server:",k)})}},[r]);const d=E.useCallback(w=>{c(k=>({...k,[w]:(k[w]||0)+1}))},[]),g=E.useCallback(()=>{c({}),We.markAllRead().catch(w=>{console.error("Failed to mark all as read on server:",w)})},[]),y=E.useCallback(w=>{if(w.type==="raw")return;const k=Oa(w.type,w.id);c(z=>{if(z[k]){const v={...z};return delete v[k],v}return z}),w.type==="channel"?We.markChannelRead(w.id).catch(z=>{console.error("Failed to mark channel as read on server:",z)}):w.type==="contact"&&We.markContactRead(w.id).catch(z=>{console.error("Failed to mark contact as read on server:",z)})},[]),f=E.useCallback(w=>{let k=null;if(w.type==="CHAN"&&w.conversation_key?k=Oa("channel",w.conversation_key):w.type==="PRIV"&&w.conversation_key&&(k=Oa("contact",w.conversation_key)),k){const z=w.received_at||Math.floor(Date.now()/1e3),v=ru(k,z);m(v)}},[]);return{unreadCounts:s,lastMessageTimes:l,incrementUnread:d,markAllRead:g,markConversationRead:y,trackNewMessage:f}}const Zs=200;function ou(a){return`${a.type}-${a.conversation_key}-${a.text}-${a.sender_timestamp}`}function fk(a){const[o,r]=E.useState([]),[s,c]=E.useState(!1),[l,m]=E.useState(!1),[u,h]=E.useState(!1),d=E.useRef(new Set),g=E.useCallback(async(k=!1)=>{if(!a||a.type==="raw"){r([]),h(!1);return}k&&c(!0);try{const z=await We.getMessages({type:a.type==="channel"?"CHAN":"PRIV",conversation_key:a.id,limit:Zs});r(z),d.current.clear();for(const v of z)d.current.add(ou(v));h(z.length>=Zs)}catch(z){console.error("Failed to fetch messages:",z)}finally{k&&c(!1)}},[a]),y=E.useCallback(async()=>{if(!(!a||a.type==="raw"||l||!u)){m(!0);try{const k=await We.getMessages({type:a.type==="channel"?"CHAN":"PRIV",conversation_key:a.id,limit:Zs,offset:o.length});if(k.length>0){r(z=>[ 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 zk=a=>a.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),xk=a=>a.replace(/^([A-Z])|[\s-_]+(\w)/g,(o,r,s)=>s?s.toUpperCase():r.toLowerCase()),Xm=a=>{const o=xk(a);return o.charAt(0).toUpperCase()+o.slice(1)},Xg=(...a)=>a.filter((o,r,s)=>!!o&&o.trim()!==""&&s.indexOf(o)===r).join(" ").trim(),jk=a=>{for(const o in a)if(o.startsWith("aria-")||o==="role"||o==="title")return!0};/**
*/const vk=a=>a.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),kk=a=>a.replace(/^([A-Z])|[\s-_]+(\w)/g,(o,r,s)=>s?s.toUpperCase():r.toLowerCase()),Km=a=>{const o=kk(a);return o.charAt(0).toUpperCase()+o.slice(1)},Kg=(...a)=>a.filter((o,r,s)=>!!o&&o.trim()!==""&&s.indexOf(o)===r).join(" ").trim(),wk=a=>{for(const o in a)if(o.startsWith("aria-")||o==="role"||o==="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 qk={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"};/**
*/var zk={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 Ak=E.forwardRef(({color:a="currentColor",size:o=24,strokeWidth:r=2,absoluteStrokeWidth:s,className:c="",children:l,iconNode:m,...u},h)=>E.createElement("svg",{ref:h,...qk,width:o,height:o,stroke:a,strokeWidth:s?Number(r)*24/Number(o):r,className:Xg("lucide",c),...!l&&!jk(u)&&{"aria-hidden":"true"},...u},[...m.map(([d,g])=>E.createElement(d,g)),...Array.isArray(l)?l:[l]]));/**
*/const xk=E.forwardRef(({color:a="currentColor",size:o=24,strokeWidth:r=2,absoluteStrokeWidth:s,className:c="",children:l,iconNode:m,...u},h)=>E.createElement("svg",{ref:h,...zk,width:o,height:o,stroke:a,strokeWidth:s?Number(r)*24/Number(o):r,className:Kg("lucide",c),...!l&&!wk(u)&&{"aria-hidden":"true"},...u},[...m.map(([d,g])=>E.createElement(d,g)),...Array.isArray(l)?l:[l]]));/**
* @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 Ou=(a,o)=>{const r=E.forwardRef(({className:s,...c},l)=>E.createElement(Ak,{ref:l,iconNode:o,className:Xg(`lucide-${zk(Xm(a))}`,`lucide-${a}`,s),...c}));return r.displayName=Xm(a),r};/**
*/const Nu=(a,o)=>{const r=E.forwardRef(({className:s,...c},l)=>E.createElement(xk,{ref:l,iconNode:o,className:Kg(`lucide-${vk(Km(a))}`,`lucide-${a}`,s),...c}));return r.displayName=Km(a),r};/**
* @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 Ck=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],Ek=Ou("check",Ck);/**
*/const jk=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],qk=Nu("check",jk);/**
* @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 Sk=[["path",{d:"M4 5h16",key:"1tepv9"}],["path",{d:"M4 12h16",key:"1lakjw"}],["path",{d:"M4 19h16",key:"1djgab"}]],Bk=Ou("menu",Sk);/**
*/const Ak=[["path",{d:"M4 5h16",key:"1tepv9"}],["path",{d:"M4 12h16",key:"1lakjw"}],["path",{d:"M4 19h16",key:"1djgab"}]],Ck=Nu("menu",Ak);/**
* @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 _k=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],Jg=Ou("x",_k);var ey=Qg();const iy=Fr(ey);function Dk(a){if(typeof document>"u")return;let o=document.head||document.getElementsByTagName("head")[0],r=document.createElement("style");r.type="text/css",o.appendChild(r),r.styleSheet?r.styleSheet.cssText=a:r.appendChild(document.createTextNode(a))}const Fk=a=>{switch(a){case"success":return Pk;case"info":return Ik;case"warning":return Nk;case"error":return Mk;default:return null}},Rk=Array(12).fill(0),Tk=({visible:a,className:o})=>de.createElement("div",{className:["sonner-loading-wrapper",o].filter(Boolean).join(" "),"data-visible":a},de.createElement("div",{className:"sonner-spinner"},Rk.map((r,s)=>de.createElement("div",{className:"sonner-loading-bar",key:`spinner-bar-${s}`})))),Pk=de.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},de.createElement("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z",clipRule:"evenodd"})),Nk=de.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",height:"20",width:"20"},de.createElement("path",{fillRule:"evenodd",d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z",clipRule:"evenodd"})),Ik=de.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},de.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z",clipRule:"evenodd"})),Mk=de.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},de.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z",clipRule:"evenodd"})),Ok=de.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"},de.createElement("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),de.createElement("line",{x1:"6",y1:"6",x2:"18",y2:"18"})),Lk=()=>{const[a,o]=de.useState(document.hidden);return de.useEffect(()=>{const r=()=>{o(document.hidden)};return document.addEventListener("visibilitychange",r),()=>window.removeEventListener("visibilitychange",r)},[]),a};let qu=1;class Hk{constructor(){this.subscribe=o=>(this.subscribers.push(o),()=>{const r=this.subscribers.indexOf(o);this.subscribers.splice(r,1)}),this.publish=o=>{this.subscribers.forEach(r=>r(o))},this.addToast=o=>{this.publish(o),this.toasts=[...this.toasts,o]},this.create=o=>{var r;const{message:s,...c}=o,l=typeof(o==null?void 0:o.id)=="number"||((r=o.id)==null?void 0:r.length)>0?o.id:qu++,m=this.toasts.find(h=>h.id===l),u=o.dismissible===void 0?!0:o.dismissible;return this.dismissedToasts.has(l)&&this.dismissedToasts.delete(l),m?this.toasts=this.toasts.map(h=>h.id===l?(this.publish({...h,...o,id:l,title:s}),{...h,...o,id:l,dismissible:u,title:s}):h):this.addToast({title:s,...c,dismissible:u,id:l}),l},this.dismiss=o=>(o?(this.dismissedToasts.add(o),requestAnimationFrame(()=>this.subscribers.forEach(r=>r({id:o,dismiss:!0})))):this.toasts.forEach(r=>{this.subscribers.forEach(s=>s({id:r.id,dismiss:!0}))}),o),this.message=(o,r)=>this.create({...r,message:o}),this.error=(o,r)=>this.create({...r,message:o,type:"error"}),this.success=(o,r)=>this.create({...r,type:"success",message:o}),this.info=(o,r)=>this.create({...r,type:"info",message:o}),this.warning=(o,r)=>this.create({...r,type:"warning",message:o}),this.loading=(o,r)=>this.create({...r,type:"loading",message:o}),this.promise=(o,r)=>{if(!r)return;let s;r.loading!==void 0&&(s=this.create({...r,promise:o,type:"loading",message:r.loading,description:typeof r.description!="function"?r.description:void 0}));const c=Promise.resolve(o instanceof Function?o():o);let l=s!==void 0,m;const u=c.then(async d=>{if(m=["resolve",d],de.isValidElement(d))l=!1,this.create({id:s,type:"default",message:d});else if(Uk(d)&&!d.ok){l=!1;const y=typeof r.error=="function"?await r.error(`HTTP error! status: ${d.status}`):r.error,f=typeof r.description=="function"?await r.description(`HTTP error! status: ${d.status}`):r.description,k=typeof y=="object"&&!de.isValidElement(y)?y:{message:y};this.create({id:s,type:"error",description:f,...k})}else if(d instanceof Error){l=!1;const y=typeof r.error=="function"?await r.error(d):r.error,Line truncated
`).map((q,I,L)=>B.jsxs("span",{children:[mz(q,u),I<L.length-1&&B.jsx("br",{})]},I)),!Z&&B.jsx("span",{className:"text-[10px] text-muted-foreground/50 ml-2",children:uh(C.sender_timestamp||C.received_at)}),C.outgoing&&(C.acked>0?` ✓${C.acked>1?C.acked:""}`:" ?")]})]})]},C.id)})]}),y&&B.jsx("button",{onClick:z,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 dh=156,gz=140,yz=156,bz=120,fz=8,vz=E.forwardRef(function({onSend:o,disabled:r,placeholder:s,isRepeaterMode:c,conversationType:l,senderName:m},u){const[h,d]=E.useState(""),[g,y]=E.useState(!1),f=E.useRef(null);E.useImperativeHandle(u,()=>({appendText:C=>{var D;d(F=>F+C),(D=f.current)==null||D.focus()}}));const w=E.useMemo(()=>{if(l==="contact")return{warningAt:gz,dangerAt:dh,hardLimit:dh};if(l==="channel"){const C=(m==null?void 0:m.length)??10,D=Math.max(1,yz-C-2);return{warningAt:bz,dangerAt:Math.max(1,D-fz),hardLimit:D}}return null},[l,m]),{limitState:k,warningMessage:z}=E.useMemo(()=>{if(!w)return{limitState:"normal",warningMessage:null};const C=h.length;return C>=w.hardLimit?{limitState:"error",warningMessage:"likely truncated by radio"}:C>=w.dangerAt?{limitState:"danger",warningMessage:"may impact multi-repeater hop delivery"}:C>=w.warningAt?{limitState:"warning",warningMessage:"may impact multi-repeater hop delivery"}:{limitState:"normal",warningMessage:null}},[h.length,w]),v=w?w.hardLimit-h.length:0,j=E.useCallback(async C=>{C.preventDefault();const D=h.trim();if(c){if(g||r)return;const F=D==="."?"":D;y(!0);try{await o(F),d("")}catch(R){console.error("Failed to request telemetry:",R);return}finally{y(!1)}setTimeout(()=>{var R;return(R=f.current)==null?void 0:R.focus()},0)}else{if(!D||g||r)return;y(!0);try{await o(D),d("")}catch(F){console.error("Failed to send message:",F);return}finally{y(!1)}setTimeout(()=>{var F;return(F=f.current)==null?void 0:F.focus()},0)}},[h,g,r,o,c]),A=E.useCallback(C=>{C.key==="Enter"&&!C.shiftKey&&(C.preventDefault(),j(C))},[j]),x=c?h.trim().length>0||h===".":h.trim().length>0,_=!c&&w!==null;return B.jsxs("form",{className:"px-4 py-3 border-t border-border flex flex-col gap-1",onSubmit:j,children:[B.jsxs("div",{className:"flex gap-2",children:[B.jsx(xi,{ref:f,type:c?"password":"text",value:h,onChange:C=>d(C.target.value),onKeyDown:A,placeholder:s||(c?"Enter password (or . for none)...":"Type a message..."),disabled:r||g,className:"flex-1 min-w-0"}),B.jsx(Ha,{type:"submit",disabled:r||g||!x,className:"flex-shrink-0",children:g?c?"Fetching...":"Sending...":c?"Fetch":"Send"})]}),_&&B.jsxs("div",{className:"flex items-center justify-end gap-2 text-xs",children:[B.jsxs("span",{className:We("tabular-nums",k==="error"||k==="danger"?"text-red-500 font-medium":k==="warning"?"text-yellow-500":"text-muted-foreground"),children:[h.length,"/",w.hardLimit,v<0&&` (${v})`]}),z&&B.jsxs("span",{className:We(k==="error"?"text-red-500":"text-yellow-500"),children:["— ",z]})]})]})});function Si(a,o,{checkForDefaultPrevented:r=!0}={}){return function(c){if(a==null||a(c),r===!1||!c.defaultPrevented)return o==null?void 0:o(c)}}function kz(a,o){const r=E.createContext(o),s=l=>{const{children:m,...u}=l,h=E.useMemo(()=>u,Object.values(u));return B.jsx(r.Provider,{value:h,children:m})};s.displayName=a+"Provider";function c(l){const m=E.useContext(r);if(m)return m;if(o!==void 0)return o;throw new Error(`\`${l}\` must be used within \`${a}\``)}return[s,c]}function Ho(a,o=[]){let r=[];function s(l,m){const u=E.createContext(m),h=r.length;r=[...r,m];const d=y=>{var j;const{scope:f,children:w,...k}=y,z=((j=f==null?void 0:f[a])==null?void 0:j[h])||u,v=E.useMemo(()=>k,Object.values(k));return B.jsx(z.Provider,{value:v,children:w})};d.displayName=l+"Provider";function g(y,f){var z;const w=((z=f==null?void 0:f[a])==null?void 0:z[h])||u,k=E.useContext(w);if(k)return k;if(m!==void 0)return m;throw new Error(`\`${y}\` must be used within \`${l}\``)}return[d,g]}const c=()=>{const l=r.map(m=>E.createContext(m));return function(u){const h=(u==null?void 0:u[a])||l;return E.useMemo(()=>({[`__scope${a}`]:{...u,[a]:h}}),[u,h])}};return c.scopeName=a,[s,wz(c,...o)]}function wz(...a){const o=a[0];if(a.length===1)return o;const r=()=>{const s=a.map(c=>({useScope:c(),scopeName:c.scopeName}));return function(l){const m=s.reduce((u,{useScope:h,scopeName:d})=>{const y=h(l)[`__scope${d}`];return{...u,...y}},{});return E.useMemo(()=>({[`__scope${o.scopeName}`]:m}),[m])}};return r.scopeName=o.scopeName,r}var _r=globalThis!=null&&globalThis.document?E.useLayoutEffect:()=>{},zz=Mu[" useId ".trim().toString()]||(()=>{}),xz=0;function No(a){conLine truncated
.`.concat(ax,` {
*/const Ek=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],Yg=Nu("x",Ek);var Zg=Wg();const Xg=Fr(Zg);function Sk(a){if(typeof document>"u")return;let o=document.head||document.getElementsByTagName("head")[0],r=document.createElement("style");r.type="text/css",o.appendChild(r),r.styleSheet?r.styleSheet.cssText=a:r.appendChild(document.createTextNode(a))}const Bk=a=>{switch(a){case"success":return Fk;case"info":return Tk;case"warning":return Rk;case"error":return Pk;default:return null}},_k=Array(12).fill(0),Dk=({visible:a,className:o})=>de.createElement("div",{className:["sonner-loading-wrapper",o].filter(Boolean).join(" "),"data-visible":a},de.createElement("div",{className:"sonner-spinner"},_k.map((r,s)=>de.createElement("div",{className:"sonner-loading-bar",key:`spinner-bar-${s}`})))),Fk=de.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},de.createElement("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z",clipRule:"evenodd"})),Rk=de.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",height:"20",width:"20"},de.createElement("path",{fillRule:"evenodd",d:"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z",clipRule:"evenodd"})),Tk=de.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},de.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z",clipRule:"evenodd"})),Pk=de.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 20 20",fill:"currentColor",height:"20",width:"20"},de.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z",clipRule:"evenodd"})),Nk=de.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"},de.createElement("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),de.createElement("line",{x1:"6",y1:"6",x2:"18",y2:"18"})),Ik=()=>{const[a,o]=de.useState(document.hidden);return de.useEffect(()=>{const r=()=>{o(document.hidden)};return document.addEventListener("visibilitychange",r),()=>window.removeEventListener("visibilitychange",r)},[]),a};let zu=1;class Mk{constructor(){this.subscribe=o=>(this.subscribers.push(o),()=>{const r=this.subscribers.indexOf(o);this.subscribers.splice(r,1)}),this.publish=o=>{this.subscribers.forEach(r=>r(o))},this.addToast=o=>{this.publish(o),this.toasts=[...this.toasts,o]},this.create=o=>{var r;const{message:s,...c}=o,l=typeof(o==null?void 0:o.id)=="number"||((r=o.id)==null?void 0:r.length)>0?o.id:zu++,m=this.toasts.find(h=>h.id===l),u=o.dismissible===void 0?!0:o.dismissible;return this.dismissedToasts.has(l)&&this.dismissedToasts.delete(l),m?this.toasts=this.toasts.map(h=>h.id===l?(this.publish({...h,...o,id:l,title:s}),{...h,...o,id:l,dismissible:u,title:s}):h):this.addToast({title:s,...c,dismissible:u,id:l}),l},this.dismiss=o=>(o?(this.dismissedToasts.add(o),requestAnimationFrame(()=>this.subscribers.forEach(r=>r({id:o,dismiss:!0})))):this.toasts.forEach(r=>{this.subscribers.forEach(s=>s({id:r.id,dismiss:!0}))}),o),this.message=(o,r)=>this.create({...r,message:o}),this.error=(o,r)=>this.create({...r,message:o,type:"error"}),this.success=(o,r)=>this.create({...r,type:"success",message:o}),this.info=(o,r)=>this.create({...r,type:"info",message:o}),this.warning=(o,r)=>this.create({...r,type:"warning",message:o}),this.loading=(o,r)=>this.create({...r,type:"loading",message:o}),this.promise=(o,r)=>{if(!r)return;let s;r.loading!==void 0&&(s=this.create({...r,promise:o,type:"loading",message:r.loading,description:typeof r.description!="function"?r.description:void 0}));const c=Promise.resolve(o instanceof Function?o():o);let l=s!==void 0,m;const u=c.then(async d=>{if(m=["resolve",d],de.isValidElement(d))l=!1,this.create({id:s,type:"default",message:d});else if(Lk(d)&&!d.ok){l=!1;const y=typeof r.error=="function"?await r.error(`HTTP error! status: ${d.status}`):r.error,f=typeof r.description=="function"?await r.description(`HTTP error! status: ${d.status}`):r.description,k=typeof y=="object"&&!de.isValidElement(y)?y:{message:y};this.create({id:s,type:"error",description:f,...k})}else if(d instanceof Error){l=!1;const y=typeof r.error=="function"?await r.error(d):r.error,Line truncated
`).map((A,I,L)=>B.jsxs("span",{children:[uz(A,u),I<L.length-1&&B.jsx("br",{})]},I)),!Z&&B.jsx("span",{className:"text-[10px] text-muted-foreground/50 ml-2",children:th(C.sender_timestamp||C.received_at)}),C.outgoing&&(C.acked>0?` ✓${C.acked>1?C.acked:""}`:" ?")]})]})]},C.id)})]}),y&&B.jsx("button",{onClick:z,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 lh=156,pz=140,mz=156,hz=120,gz=8,yz=E.forwardRef(function({onSend:o,disabled:r,placeholder:s,isRepeaterMode:c,conversationType:l,senderName:m},u){const[h,d]=E.useState(""),[g,y]=E.useState(!1),f=E.useRef(null);E.useImperativeHandle(u,()=>({appendText:C=>{var D;d(R=>R+C),(D=f.current)==null||D.focus()}}));const w=E.useMemo(()=>{if(l==="contact")return{warningAt:pz,dangerAt:lh,hardLimit:lh};if(l==="channel"){const C=(m==null?void 0:m.length)??10,D=Math.max(1,mz-C-2);return{warningAt:hz,dangerAt:Math.max(1,D-gz),hardLimit:D}}return null},[l,m]),{limitState:k,warningMessage:z}=E.useMemo(()=>{if(!w)return{limitState:"normal",warningMessage:null};const C=h.length;return C>=w.hardLimit?{limitState:"error",warningMessage:"likely truncated by radio"}:C>=w.dangerAt?{limitState:"danger",warningMessage:"may impact multi-repeater hop delivery"}:C>=w.warningAt?{limitState:"warning",warningMessage:"may impact multi-repeater hop delivery"}:{limitState:"normal",warningMessage:null}},[h.length,w]),v=w?w.hardLimit-h.length:0,j=E.useCallback(async C=>{C.preventDefault();const D=h.trim();if(c){if(g||r)return;const R=D==="."?"":D;y(!0);try{await o(R),d("")}catch(F){console.error("Failed to request telemetry:",F);return}finally{y(!1)}setTimeout(()=>{var F;return(F=f.current)==null?void 0:F.focus()},0)}else{if(!D||g||r)return;y(!0);try{await o(D),d("")}catch(R){console.error("Failed to send message:",R);return}finally{y(!1)}setTimeout(()=>{var R;return(R=f.current)==null?void 0:R.focus()},0)}},[h,g,r,o,c]),q=E.useCallback(C=>{C.key==="Enter"&&!C.shiftKey&&(C.preventDefault(),j(C))},[j]),x=c?h.trim().length>0||h===".":h.trim().length>0,_=!c&&w!==null;return B.jsxs("form",{className:"px-4 py-3 border-t border-border flex flex-col gap-1",onSubmit:j,children:[B.jsxs("div",{className:"flex gap-2",children:[B.jsx(xi,{ref:f,type:c?"password":"text",value:h,onChange:C=>d(C.target.value),onKeyDown:q,placeholder:s||(c?"Enter password (or . for none)...":"Type a message..."),disabled:r||g,className:"flex-1 min-w-0"}),B.jsx(Ha,{type:"submit",disabled:r||g||!x,className:"flex-shrink-0",children:g?c?"Fetching...":"Sending...":c?"Fetch":"Send"})]}),_&&B.jsxs("div",{className:"flex items-center justify-end gap-2 text-xs",children:[B.jsxs("span",{className:$e("tabular-nums",k==="error"||k==="danger"?"text-red-500 font-medium":k==="warning"?"text-yellow-500":"text-muted-foreground"),children:[h.length,"/",w.hardLimit,v<0&&` (${v})`]}),z&&B.jsxs("span",{className:$e(k==="error"?"text-red-500":"text-yellow-500"),children:["— ",z]})]})]})});function Si(a,o,{checkForDefaultPrevented:r=!0}={}){return function(c){if(a==null||a(c),r===!1||!c.defaultPrevented)return o==null?void 0:o(c)}}function bz(a,o){const r=E.createContext(o),s=l=>{const{children:m,...u}=l,h=E.useMemo(()=>u,Object.values(u));return B.jsx(r.Provider,{value:h,children:m})};s.displayName=a+"Provider";function c(l){const m=E.useContext(r);if(m)return m;if(o!==void 0)return o;throw new Error(`\`${l}\` must be used within \`${a}\``)}return[s,c]}function Ho(a,o=[]){let r=[];function s(l,m){const u=E.createContext(m),h=r.length;r=[...r,m];const d=y=>{var j;const{scope:f,children:w,...k}=y,z=((j=f==null?void 0:f[a])==null?void 0:j[h])||u,v=E.useMemo(()=>k,Object.values(k));return B.jsx(z.Provider,{value:v,children:w})};d.displayName=l+"Provider";function g(y,f){var z;const w=((z=f==null?void 0:f[a])==null?void 0:z[h])||u,k=E.useContext(w);if(k)return k;if(m!==void 0)return m;throw new Error(`\`${y}\` must be used within \`${l}\``)}return[d,g]}const c=()=>{const l=r.map(m=>E.createContext(m));return function(u){const h=(u==null?void 0:u[a])||l;return E.useMemo(()=>({[`__scope${a}`]:{...u,[a]:h}}),[u,h])}};return c.scopeName=a,[s,fz(c,...o)]}function fz(...a){const o=a[0];if(a.length===1)return o;const r=()=>{const s=a.map(c=>({useScope:c(),scopeName:c.scopeName}));return function(l){const m=s.reduce((u,{useScope:h,scopeName:d})=>{const y=h(l)[`__scope${d}`];return{...u,...y}},{});return E.useMemo(()=>({[`__scope${o.scopeName}`]:m}),[m])}};return r.scopeName=o.scopeName,r}var _r=globalThis!=null&&globalThis.document?E.useLayoutEffect:()=>{},vz=Pu[" useId ".trim().toString()]||(()=>{}),kz=0;function No(a){conLine truncated
.`.concat(Jz,` {
overflow: hidden `).concat(s,`;
padding-right: `).concat(u,"px ").concat(s,`;
}
@@ -96,33 +96,33 @@ No ACL entries`;const o=[`ACL (${a.length})`];for(const r of a){const s=r.name||
`),r==="padding"&&"padding-right: ".concat(u,"px ").concat(s,";")].filter(Boolean).join(""),`
}
.`).concat(lt,` {
.`).concat(tt,` {
right: `).concat(u,"px ").concat(s,`;
}
.`).concat(ct,` {
.`).concat(lt,` {
margin-right: `).concat(u,"px ").concat(s,`;
}
.`).concat(lt," .").concat(lt,` {
.`).concat(tt," .").concat(tt,` {
right: 0 `).concat(s,`;
}
.`).concat(ct," .").concat(ct,` {
.`).concat(lt," .").concat(lt,` {
margin-right: 0 `).concat(s,`;
}
body[`).concat(Er,`] {
`).concat(nx,": ").concat(u,`px;
`).concat(ex,": ").concat(u,`px;
}
`)},kh=function(){var a=parseInt(document.body.getAttribute(Er)||"0",10);return isFinite(a)?a:0},zx=function(){E.useEffect(function(){return document.body.setAttribute(Er,(kh()+1).toString()),function(){var a=kh()-1;a<=0?document.body.removeAttribute(Er):document.body.setAttribute(Er,a.toString())}},[])},xx=function(a){var o=a.noRelative,r=a.noImportant,s=a.gapMode,c=s===void 0?"margin":s;zx();var l=E.useMemo(function(){return vx(c)},[c]);return E.createElement(kx,{styles:wx(l,!o,c,r?"":"!important")})},Su=!1;if(typeof window<"u")try{var nt=Object.defineProperty({},"passive",{get:function(){return Su=!0,!0}});window.addEventListener("test",nt,nt),window.removeEventListener("test",nt,nt)}catch{Su=!1}var jr=Su?{passive:!1}:!1,jx=function(a){return a.tagName==="TEXTAREA"},Ey=function(a,o){if(!(a instanceof Element))return!1;var r=window.getComputedStyle(a);return r[o]!=="hidden"&&!(r.overflowY===r.overflowX&&!jx(a)&&r[o]==="visible")},qx=function(a){return Ey(a,"overflowY")},Ax=function(a){return Ey(a,"overflowX")},wh=function(a,o){var r=o.ownerDocument,s=o;do{typeof ShadowRoot<"u"&&s instanceof ShadowRoot&&(s=s.host);var c=Sy(a,s);if(c){var l=By(a,s),m=l[1],u=l[2];if(m>u)return!0}s=s.parentNode}while(s&&s!==r.body);return!1},Cx=function(a){var o=a.scrollTop,r=a.scrollHeight,s=a.clientHeight;return[o,r,s]},Ex=function(a){var o=a.scrollLeft,r=a.scrollWidth,s=a.clientWidth;return[o,r,s]},Sy=function(a,o){return a==="v"?qx(o):Ax(o)},By=function(a,o){return a==="v"?Cx(o):Ex(o)},Sx=function(a,o){return a==="h"&&o==="rtl"?-1:1},Bx=function(a,o,r,s,c){var l=Sx(a,window.getComputedStyle(o).direction),m=l*s,u=r.target,h=o.contains(u),d=!1,g=m>0,y=0,f=0;do{if(!u)break;var w=By(a,u),k=w[0],z=w[1],v=w[2],j=z-v-l*k;(k||j)&&Sy(a,u)&&(y+=j,f+=k);var A=u.parentNode;u=A&&A.nodeType===Node.DOCUMENT_FRAGMENT_NODE?A.host:A}while(!h&&u!==document.body||h&&(o.contains(u)||o===u));return(g&&Math.abs(y)<1||!g&&Math.abs(f)<1)&&(d=!0),d},rt=function(a){return"changedTouches"in a?[a.changedTouches[0].clientX,a.changedTouches[0].clientY]:[0,0]},zh=function(a){return[a.deltaX,a.deltaY]},xh=function(a){return a&&"current"in a?a.current:a},_x=function(a,o){return a[0]===o[0]&&a[1]===o[1]},Dx=function(a){return`
`)},bh=function(){var a=parseInt(document.body.getAttribute(Er)||"0",10);return isFinite(a)?a:0},vx=function(){E.useEffect(function(){return document.body.setAttribute(Er,(bh()+1).toString()),function(){var a=bh()-1;a<=0?document.body.removeAttribute(Er):document.body.setAttribute(Er,a.toString())}},[])},kx=function(a){var o=a.noRelative,r=a.noImportant,s=a.gapMode,c=s===void 0?"margin":s;vx();var l=E.useMemo(function(){return yx(c)},[c]);return E.createElement(bx,{styles:fx(l,!o,c,r?"":"!important")})},Au=!1;if(typeof window<"u")try{var at=Object.defineProperty({},"passive",{get:function(){return Au=!0,!0}});window.addEventListener("test",at,at),window.removeEventListener("test",at,at)}catch{Au=!1}var jr=Au?{passive:!1}:!1,wx=function(a){return a.tagName==="TEXTAREA"},qy=function(a,o){if(!(a instanceof Element))return!1;var r=window.getComputedStyle(a);return r[o]!=="hidden"&&!(r.overflowY===r.overflowX&&!wx(a)&&r[o]==="visible")},zx=function(a){return qy(a,"overflowY")},xx=function(a){return qy(a,"overflowX")},fh=function(a,o){var r=o.ownerDocument,s=o;do{typeof ShadowRoot<"u"&&s instanceof ShadowRoot&&(s=s.host);var c=Ay(a,s);if(c){var l=Cy(a,s),m=l[1],u=l[2];if(m>u)return!0}s=s.parentNode}while(s&&s!==r.body);return!1},jx=function(a){var o=a.scrollTop,r=a.scrollHeight,s=a.clientHeight;return[o,r,s]},qx=function(a){var o=a.scrollLeft,r=a.scrollWidth,s=a.clientWidth;return[o,r,s]},Ay=function(a,o){return a==="v"?zx(o):xx(o)},Cy=function(a,o){return a==="v"?jx(o):qx(o)},Ax=function(a,o){return a==="h"&&o==="rtl"?-1:1},Cx=function(a,o,r,s,c){var l=Ax(a,window.getComputedStyle(o).direction),m=l*s,u=r.target,h=o.contains(u),d=!1,g=m>0,y=0,f=0;do{if(!u)break;var w=Cy(a,u),k=w[0],z=w[1],v=w[2],j=z-v-l*k;(k||j)&&Ay(a,u)&&(y+=j,f+=k);var q=u.parentNode;u=q&&q.nodeType===Node.DOCUMENT_FRAGMENT_NODE?q.host:q}while(!h&&u!==document.body||h&&(o.contains(u)||o===u));return(g&&Math.abs(y)<1||!g&&Math.abs(f)<1)&&(d=!0),d},nt=function(a){return"changedTouches"in a?[a.changedTouches[0].clientX,a.changedTouches[0].clientY]:[0,0]},vh=function(a){return[a.deltaX,a.deltaY]},kh=function(a){return a&&"current"in a?a.current:a},Ex=function(a,o){return a[0]===o[0]&&a[1]===o[1]},Sx=function(a){return`
.block-interactivity-`.concat(a,` {pointer-events: none;}
.allow-interactivity-`).concat(a,` {pointer-events: all;}
`)},Fx=0,qr=[];function Rx(a){var o=E.useRef([]),r=E.useRef([0,0]),s=E.useRef(),c=E.useState(Fx++)[0],l=E.useState(Cy)[0],m=E.useRef(a);E.useEffect(function(){m.current=a},[a]),E.useEffect(function(){if(a.inert){document.body.classList.add("block-interactivity-".concat(c));var z=ix([a.lockRef.current],(a.shards||[]).map(xh),!0).filter(Boolean);return z.forEach(function(v){return v.classList.add("allow-interactivity-".concat(c))}),function(){document.body.classList.remove("block-interactivity-".concat(c)),z.forEach(function(v){return v.classList.remove("allow-interactivity-".concat(c))})}}},[a.inert,a.lockRef.current,a.shards]);var u=E.useCallback(function(z,v){if("touches"in z&&z.touches.length===2||z.type==="wheel"&&z.ctrlKey)return!m.current.allowPinchZoom;var j=rt(z),A=r.current,x="deltaX"in z?z.deltaX:A[0]-j[0],_="deltaY"in z?z.deltaY:A[1]-j[1],C,D=z.target,F=Math.abs(x)>Math.abs(_)?"h":"v";if("touches"in z&&F==="h"&&D.type==="range")return!1;var R=window.getSelection(),M=R&&R.anchorNode,N=M?M===D||M.contains(D):!1;if(N)return!1;var T=wh(F,D);if(!T)return!0;if(T?C=F:(C=F==="v"?"h":"v",T=wh(F,D)),!T)return!1;if(!s.current&&"changedTouches"in z&&(x||_)&&(s.current=C),!C)return!0;var U=s.current||C;return Bx(U,v,z,U==="h"?x:_)},[]),h=E.useCallback(function(z){var v=z;if(!(!qr.length||qr[qr.length-1]!==l)){var j="deltaY"in v?zh(v):rt(v),A=o.current.filter(function(C){return C.name===v.type&&(C.target===v.target||v.target===C.shadowParent)&&_x(C.delta,j)})[0];if(A&&A.should){v.cancelable&&v.preventDefault();return}if(!A){var x=(m.current.shards||[]).map(xh).filter(Boolean).filter(function(C){return C.contains(v.target)}),_=x.length>0?u(v,x[0]):!m.current.noIsolation;_&&v.cancelable&&v.preventDefault()}}},[]),d=E.useCallback(function(z,v,j,A){var x={name:z,delta:v,target:j,should:A,shadowParent:Tx(j)};o.current.push(x),setTimeout(function(){o.current=o.current.filter(function(_){return _!==x})},1)},[]),g=E.useCallback(function(z){r.current=rt(z),s.current=void 0},[]),y=E.useCallback(function(z){d(z.type,zh(z),z.target,u(z,a.lockRef.current))},[]),f=E.useCallback(function(z){d(z.type,rt(z),z.target,u(z,a.lockRef.current))},[]);E.useEffect(function(){return qr.push(l),a.setCallbacks({onScrollCapture:y,onWheelCapture:y,onTouchMoveCapture:f}),document.addEventListener("wheel",h,jr),document.addEventListener("touchmove",h,jr),document.addEventListener("touchstart",g,jr),function(){qr=qr.filter(function(z){return z!==l}),document.removeEventListener("wheel",h,jr),document.removeEventListener("touchmove",h,jr),document.removeEventListener("touchstart",g,jr)}},[]);var w=a.removeScrollBar,k=a.inert;return E.createElement(E.Fragment,null,k?E.createElement(l,{styles:Dx(c)}):null,w?E.createElement(xx,{noRelative:a.noRelative,gapMode:a.gapMode}):null)}function Tx(a){for(var o=null;a!==null;)a instanceof ShadowRoot&&(o=a.host,a=a.host),a=a.parentNode;return o}const Px=ux(Ay,Rx);var _y=E.forwardRef(function(a,o){return E.createElement(tl,La({},a,{ref:o,sideCar:Px}))});_y.classNames=tl.classNames;var Nx=function(a){if(typeof document>"u")return null;var o=Array.isArray(a)?a[0]:a;return o.ownerDocument.body},Ar=new WeakMap,ot=new WeakMap,st={},yu=0,Dy=function(a){return a&&(a.host||Dy(a.parentNode))},Ix=function(a,o){return o.map(function(r){if(a.contains(r))return r;var s=Dy(r);return s&&a.contains(s)?s:(console.error("aria-hidden",r,"in not contained inside",a,". Doing nothing"),null)}).filter(function(r){return!!r})},Mx=function(a,o,r,s){var c=Ix(o,Array.isArray(a)?a:[a]);st[r]||(st[r]=new WeakMap);var l=st[r],m=[],u=new Set,h=new Set(c),d=function(y){!y||u.has(y)||(u.add(y),d(y.parentNode))};c.forEach(d);var g=function(y){!y||h.has(y)||Array.prototype.forEach.call(y.children,function(f){if(u.has(f))g(f);else try{var w=f.getAttribute(s),k=w!==null&&w!=="false",z=(Ar.get(f)||0)+1,v=(l.get(f)||0)+1;Ar.set(f,z),l.set(f,v),m.push(f),z===1&&k&&ot.set(f,!0),v===1&&f.setAttribute(r,"true"),k||f.setAttribute(s,"true")}catch(j){console.error("aria-hidden: cannot operate on ",f,j)}})};return g(o),u.clear(),yu++,function(){m.forEach(function(y){var f=Ar.get(y)-1,w=l.get(y)-1;Ar.set(y,f),l.set(y,w),f||(ot.has(y)||y.removeAttribute(s),ot.delete(y)),w||y.removeAttribute(r)}),yu--,yu||(Ar=new WeakMap,Ar=new WeakMap,ot=new WeakMap,st={})}},Ox=function(a,o,r){r===void 0&&(r="data-aria-hidden");var s=Array.from(Array.isArray(a)?a:[a]),c=Nx(a);return c?(s.push.apply(s,Array.from(c.querySelectorAll("[aria-live], script"))),Mx(s,c,r,"aria-hidden")):function(){return null}};function Lx(a){const o=Hx(a),r=E.forwardRef((s,c)=>{const{children:l,...m}=s,u=E.Children.toArray(l),h=u.find(Ux);if(h){const d=h.props.children,g=u.map(y=>y===h?E.Children.count(d)>1?E.Children.only(null):E.isValidElement(d)?d.props.children:null:y);return B.jsx(o,{...m,ref:c,children:E.isValidElement(d)?E.cloneElement(d,void 0,g):null})}return B.jsx(o,{...m,ref:c,children:l})});return r.displayName=`${a}.Slot`,r}function Hx(a){const o=E.forwardRef((r,s)=>{const{children:c Line truncated
`)},Bx=0,qr=[];function _x(a){var o=E.useRef([]),r=E.useRef([0,0]),s=E.useRef(),c=E.useState(Bx++)[0],l=E.useState(jy)[0],m=E.useRef(a);E.useEffect(function(){m.current=a},[a]),E.useEffect(function(){if(a.inert){document.body.classList.add("block-interactivity-".concat(c));var z=Xz([a.lockRef.current],(a.shards||[]).map(kh),!0).filter(Boolean);return z.forEach(function(v){return v.classList.add("allow-interactivity-".concat(c))}),function(){document.body.classList.remove("block-interactivity-".concat(c)),z.forEach(function(v){return v.classList.remove("allow-interactivity-".concat(c))})}}},[a.inert,a.lockRef.current,a.shards]);var u=E.useCallback(function(z,v){if("touches"in z&&z.touches.length===2||z.type==="wheel"&&z.ctrlKey)return!m.current.allowPinchZoom;var j=nt(z),q=r.current,x="deltaX"in z?z.deltaX:q[0]-j[0],_="deltaY"in z?z.deltaY:q[1]-j[1],C,D=z.target,R=Math.abs(x)>Math.abs(_)?"h":"v";if("touches"in z&&R==="h"&&D.type==="range")return!1;var F=window.getSelection(),M=F&&F.anchorNode,P=M?M===D||M.contains(D):!1;if(P)return!1;var T=fh(R,D);if(!T)return!0;if(T?C=R:(C=R==="v"?"h":"v",T=fh(R,D)),!T)return!1;if(!s.current&&"changedTouches"in z&&(x||_)&&(s.current=C),!C)return!0;var U=s.current||C;return Cx(U,v,z,U==="h"?x:_)},[]),h=E.useCallback(function(z){var v=z;if(!(!qr.length||qr[qr.length-1]!==l)){var j="deltaY"in v?vh(v):nt(v),q=o.current.filter(function(C){return C.name===v.type&&(C.target===v.target||v.target===C.shadowParent)&&Ex(C.delta,j)})[0];if(q&&q.should){v.cancelable&&v.preventDefault();return}if(!q){var x=(m.current.shards||[]).map(kh).filter(Boolean).filter(function(C){return C.contains(v.target)}),_=x.length>0?u(v,x[0]):!m.current.noIsolation;_&&v.cancelable&&v.preventDefault()}}},[]),d=E.useCallback(function(z,v,j,q){var x={name:z,delta:v,target:j,should:q,shadowParent:Dx(j)};o.current.push(x),setTimeout(function(){o.current=o.current.filter(function(_){return _!==x})},1)},[]),g=E.useCallback(function(z){r.current=nt(z),s.current=void 0},[]),y=E.useCallback(function(z){d(z.type,vh(z),z.target,u(z,a.lockRef.current))},[]),f=E.useCallback(function(z){d(z.type,nt(z),z.target,u(z,a.lockRef.current))},[]);E.useEffect(function(){return qr.push(l),a.setCallbacks({onScrollCapture:y,onWheelCapture:y,onTouchMoveCapture:f}),document.addEventListener("wheel",h,jr),document.addEventListener("touchmove",h,jr),document.addEventListener("touchstart",g,jr),function(){qr=qr.filter(function(z){return z!==l}),document.removeEventListener("wheel",h,jr),document.removeEventListener("touchmove",h,jr),document.removeEventListener("touchstart",g,jr)}},[]);var w=a.removeScrollBar,k=a.inert;return E.createElement(E.Fragment,null,k?E.createElement(l,{styles:Sx(c)}):null,w?E.createElement(kx,{noRelative:a.noRelative,gapMode:a.gapMode}):null)}function Dx(a){for(var o=null;a!==null;)a instanceof ShadowRoot&&(o=a.host,a=a.host),a=a.parentNode;return o}const Fx=tx(xy,_x);var Ey=E.forwardRef(function(a,o){return E.createElement(ol,La({},a,{ref:o,sideCar:Fx}))});Ey.classNames=ol.classNames;var Rx=function(a){if(typeof document>"u")return null;var o=Array.isArray(a)?a[0]:a;return o.ownerDocument.body},Ar=new WeakMap,rt=new WeakMap,ot={},hu=0,Sy=function(a){return a&&(a.host||Sy(a.parentNode))},Tx=function(a,o){return o.map(function(r){if(a.contains(r))return r;var s=Sy(r);return s&&a.contains(s)?s:(console.error("aria-hidden",r,"in not contained inside",a,". Doing nothing"),null)}).filter(function(r){return!!r})},Px=function(a,o,r,s){var c=Tx(o,Array.isArray(a)?a:[a]);ot[r]||(ot[r]=new WeakMap);var l=ot[r],m=[],u=new Set,h=new Set(c),d=function(y){!y||u.has(y)||(u.add(y),d(y.parentNode))};c.forEach(d);var g=function(y){!y||h.has(y)||Array.prototype.forEach.call(y.children,function(f){if(u.has(f))g(f);else try{var w=f.getAttribute(s),k=w!==null&&w!=="false",z=(Ar.get(f)||0)+1,v=(l.get(f)||0)+1;Ar.set(f,z),l.set(f,v),m.push(f),z===1&&k&&rt.set(f,!0),v===1&&f.setAttribute(r,"true"),k||f.setAttribute(s,"true")}catch(j){console.error("aria-hidden: cannot operate on ",f,j)}})};return g(o),u.clear(),hu++,function(){m.forEach(function(y){var f=Ar.get(y)-1,w=l.get(y)-1;Ar.set(y,f),l.set(y,w),f||(rt.has(y)||y.removeAttribute(s),rt.delete(y)),w||y.removeAttribute(r)}),hu--,hu||(Ar=new WeakMap,Ar=new WeakMap,rt=new WeakMap,ot={})}},Nx=function(a,o,r){r===void 0&&(r="data-aria-hidden");var s=Array.from(Array.isArray(a)?a:[a]),c=Rx(a);return c?(s.push.apply(s,Array.from(c.querySelectorAll("[aria-live], script"))),Px(s,c,r,"aria-hidden")):function(){return null}};function Ix(a){const o=Mx(a),r=E.forwardRef((s,c)=>{const{children:l,...m}=s,u=E.Children.toArray(l),h=u.find(Lx);if(h){const d=h.props.children,g=u.map(y=>y===h?E.Children.count(d)>1?E.Children.only(null):E.isValidElement(d)?d.props.children:null:y);return B.jsx(o,{...m,ref:c,children:E.isValidElement(d)?E.cloneElement(d,void 0,g):null})}return B.jsx(o,{...m,ref:c,children:l})});return r.displayName=`${a}.Slot`,r}function Mx(a){const o=E.forwardRef((r,s)=>{const{children:c Line truncated
If you want to hide the \`${o.titleName}\`, you can wrap it with our VisuallyHidden component.
For more information, see https://radix-ui.com/primitives/docs/components/${o.docsSlug}`;return E.useEffect(()=>{a&&(document.getElementById(a)||console.error(r))},[r,a]),null},i0="DialogDescriptionWarning",a0=({contentRef:a,descriptionId:o})=>{const s=`Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${Gy(i0).contentName}}.`;return E.useEffect(()=>{var l;const c=(l=a.current)==null?void 0:l.getAttribute("aria-describedby");o&&c&&(document.getElementById(o)||console.warn(s))},[s,a,o]),null},Qy=Ry,Ky=Ny,cl=Iy,ul=My,dl=Ly,pl=Vy,Yy=Wy;const Zy=Qy,n0=Ky,Xy=E.forwardRef(({className:a,...o},r)=>B.jsx(cl,{ref:r,className:We("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",a),...o}));Xy.displayName=cl.displayName;const $u=E.forwardRef(({className:a,children:o,...r},s)=>B.jsxs(n0,{children:[B.jsx(Xy,{}),B.jsxs(ul,{ref:s,className:We("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",a),...r,children:[o,B.jsxs(Yy,{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(Jg,{className:"h-4 w-4"}),B.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));$u.displayName=ul.displayName;const Gu=({className:a,...o})=>B.jsx("div",{className:We("flex flex-col space-y-1.5 text-center sm:text-left",a),...o});Gu.displayName="DialogHeader";const Qu=({className:a,...o})=>B.jsx("div",{className:We("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",a),...o});Qu.displayName="DialogFooter";const Ku=E.forwardRef(({className:a,...o},r)=>B.jsx(dl,{ref:r,className:We("text-lg font-semibold leading-none tracking-tight",a),...o}));Ku.displayName=dl.displayName;const r0=E.forwardRef(({className:a,...o},r)=>B.jsx(pl,{ref:r,className:We("text-sm text-muted-foreground",a),...o}));r0.displayName=pl.displayName;function jh(a){const o=o0(a),r=E.forwardRef((s,c)=>{const{children:l,...m}=s,u=E.Children.toArray(l),h=u.find(t0);if(h){const d=h.props.children,g=u.map(y=>y===h?E.Children.count(d)>1?E.Children.only(null):E.isValidElement(d)?d.props.children:null:y);return B.jsx(o,{...m,ref:c,children:E.isValidElement(d)?E.cloneElement(d,void 0,g):null})}return B.jsx(o,{...m,ref:c,children:l})});return r.displayName=`${a}.Slot`,r}function o0(a){const o=E.forwardRef((r,s)=>{const{children:c,...l}=r;if(E.isValidElement(c)){const m=c0(c),u=l0(l,c.props);return c.type!==E.Fragment&&(u.ref=s?Lo(s,m):m),E.cloneElement(c,u)}return E.Children.count(c)>1?E.Children.only(null):null});return o.displayName=`${a}.SlotClone`,o}var s0=Symbol("radix.slottable");function t0(a){return E.isValidElement(a)&&typeof a.type=="function"&&"__radixId"in a.type&&a.type.__radixId===s0}function l0(a,o){const r={...o};for(const s in o){const c=a[s],l=o[s];/^on[A-Z]/.test(s)?c&&l?r[s]=(...u)=>{const h=l(...u);return c(...u),h}:c&&(r[s]=c):s==="style"?r[s]={...c,...l}:s==="className"&&(r[s]=[c,l].filter(Boolean).join(" "))}return{...a,...r}}function c0(a){var s,c;let o=(s=Object.getOwnPropertyDescriptor(a.props,"ref"))==null?void 0:s.get,r=o&&"isReactWarning"in o&&o.isReactWarning;return r?a.ref:(o=(c=Object.getOwnPropertyDescriptor(a,"ref"))==null?void 0:c.get,r=o&&"isReactWarning"in o&&o.isReactWarning,r?a.props.ref:a.props.ref||a.ref)}function u0(a){const o=a+"CollectionProvider",[r,s]=Ho(o),[c,l]=r(o,{collectionRef:{current:null},itemMap:new Map}),m=z=>{const{scope:v,children:j}=z,A=de.useRef(null),x=de.useRef(new Map).current;return B.jsx(c,{scope:v,itemMap:x,collectionRef:A,children:j})};m.displayName=o;const u=a+"CollectionSlot",h=jh(u),d=de.forwardRef((z,v)=>{const{scope:j,children:A}=z,x=l(u,j),_=va(v,x.collectionRef);return B.jsx(h,{ref:_,children:A})});d.displayName=u;const g=a+"CollectionItemSlot",y="data-radix-collection-item",f=jh(g),w=de.forwardRef((z,v)=>{const{scope:j,children:A,...x}=z,_=de.useRef(null),C=va(v,_),D=l(g,j);return de.useEffect(()=>(D.itemMap.set(_,{ref:_,...x}),()=>void D.itemMap.delete(_))),B.jsx(f,{[y]:"",ref:C,children:A})});w.displayName=g;function k(z){const v=l(a+"CollectionConsumer",z);return de.useCallback(()=>{const A=v.collectionRef.current;if(!A)return[];const x=Array.from(A.querySelectorAll(`[${y}]`));return Array.from(v.itemMap.values()).sort((D,F)=>x.indexOf(D.ref.current)-x.indexOf(F.ref.current))},[v.coll Line truncated
For more information, see https://radix-ui.com/primitives/docs/components/${o.docsSlug}`;return E.useEffect(()=>{a&&(document.getElementById(a)||console.error(r))},[r,a]),null},Xx="DialogDescriptionWarning",Jx=({contentRef:a,descriptionId:o})=>{const s=`Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${Uy(Xx).contentName}}.`;return E.useEffect(()=>{var l;const c=(l=a.current)==null?void 0:l.getAttribute("aria-describedby");o&&c&&(document.getElementById(o)||console.warn(s))},[s,a,o]),null},Wy=_y,$y=Ry,tl=Ty,ll=Py,cl=Iy,ul=Oy,Gy=Hy;const Qy=Wy,e0=$y,Ky=E.forwardRef(({className:a,...o},r)=>B.jsx(tl,{ref:r,className:$e("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",a),...o}));Ky.displayName=tl.displayName;const Vu=E.forwardRef(({className:a,children:o,...r},s)=>B.jsxs(e0,{children:[B.jsx(Ky,{}),B.jsxs(ll,{ref:s,className:$e("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",a),...r,children:[o,B.jsxs(Gy,{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(Yg,{className:"h-4 w-4"}),B.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));Vu.displayName=ll.displayName;const Uu=({className:a,...o})=>B.jsx("div",{className:$e("flex flex-col space-y-1.5 text-center sm:text-left",a),...o});Uu.displayName="DialogHeader";const Wu=({className:a,...o})=>B.jsx("div",{className:$e("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",a),...o});Wu.displayName="DialogFooter";const $u=E.forwardRef(({className:a,...o},r)=>B.jsx(cl,{ref:r,className:$e("text-lg font-semibold leading-none tracking-tight",a),...o}));$u.displayName=cl.displayName;const i0=E.forwardRef(({className:a,...o},r)=>B.jsx(ul,{ref:r,className:$e("text-sm text-muted-foreground",a),...o}));i0.displayName=ul.displayName;function wh(a){const o=a0(a),r=E.forwardRef((s,c)=>{const{children:l,...m}=s,u=E.Children.toArray(l),h=u.find(r0);if(h){const d=h.props.children,g=u.map(y=>y===h?E.Children.count(d)>1?E.Children.only(null):E.isValidElement(d)?d.props.children:null:y);return B.jsx(o,{...m,ref:c,children:E.isValidElement(d)?E.cloneElement(d,void 0,g):null})}return B.jsx(o,{...m,ref:c,children:l})});return r.displayName=`${a}.Slot`,r}function a0(a){const o=E.forwardRef((r,s)=>{const{children:c,...l}=r;if(E.isValidElement(c)){const m=s0(c),u=o0(l,c.props);return c.type!==E.Fragment&&(u.ref=s?Lo(s,m):m),E.cloneElement(c,u)}return E.Children.count(c)>1?E.Children.only(null):null});return o.displayName=`${a}.SlotClone`,o}var n0=Symbol("radix.slottable");function r0(a){return E.isValidElement(a)&&typeof a.type=="function"&&"__radixId"in a.type&&a.type.__radixId===n0}function o0(a,o){const r={...o};for(const s in o){const c=a[s],l=o[s];/^on[A-Z]/.test(s)?c&&l?r[s]=(...u)=>{const h=l(...u);return c(...u),h}:c&&(r[s]=c):s==="style"?r[s]={...c,...l}:s==="className"&&(r[s]=[c,l].filter(Boolean).join(" "))}return{...a,...r}}function s0(a){var s,c;let o=(s=Object.getOwnPropertyDescriptor(a.props,"ref"))==null?void 0:s.get,r=o&&"isReactWarning"in o&&o.isReactWarning;return r?a.ref:(o=(c=Object.getOwnPropertyDescriptor(a,"ref"))==null?void 0:c.get,r=o&&"isReactWarning"in o&&o.isReactWarning,r?a.props.ref:a.props.ref||a.ref)}function t0(a){const o=a+"CollectionProvider",[r,s]=Ho(o),[c,l]=r(o,{collectionRef:{current:null},itemMap:new Map}),m=z=>{const{scope:v,children:j}=z,q=de.useRef(null),x=de.useRef(new Map).current;return B.jsx(c,{scope:v,itemMap:x,collectionRef:q,children:j})};m.displayName=o;const u=a+"CollectionSlot",h=wh(u),d=de.forwardRef((z,v)=>{const{scope:j,children:q}=z,x=l(u,j),_=fa(v,x.collectionRef);return B.jsx(h,{ref:_,children:q})});d.displayName=u;const g=a+"CollectionItemSlot",y="data-radix-collection-item",f=wh(g),w=de.forwardRef((z,v)=>{const{scope:j,children:q,...x}=z,_=de.useRef(null),C=fa(v,_),D=l(g,j);return de.useEffect(()=>(D.itemMap.set(_,{ref:_,...x}),()=>void D.itemMap.delete(_))),B.jsx(f,{[y]:"",ref:C,children:q})});w.displayName=g;function k(z){const v=l(a+"CollectionConsumer",z);return de.useCallback(()=>{const q=v.collectionRef.current;if(!q)return[];const x=Array.from(q.querySelectorAll(`[${y}]`));return Array.from(v.itemMap.values()).sort((D,R)=>x.indexOf(D.ref.current)-x.indexOf(R.ref.current))},[v.coll Line 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:
@@ -131,17 +131,17 @@ For more information, see https://radix-ui.com/primitives/docs/components/${o.do
- 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(s){var c=r,l=c.lib,m=l.WordArray,u=l.Hasher,h=c.algo,d=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]),g=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]),f=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]),w=m.create([0,1518500249,1859775393,2400959708,2840853838]),k=m.create([1352829926,1548603684,1836072691,2053994217,0]),z=h.RIPEMD160=u.extend({_doReset:function(){this._hash=m.create([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(D,F){for(var R=0;R<16;R++){var M=F+R,N=D[M];D[M]=(N<<8|N>>>24)&16711935|(N<<24|N>>>8)&4278255360}var T=this._hash.words,U=w.words,H=k.words,K=d.words,ie=g.words,Z=y.words,ae=f.words,W,ne,X,q,I,L,$,te,pe,ge;L=W=T[0],$=ne=T[1],te=X=T[2],pe=q=T[3],ge=I=T[4];for(var re,R=0;R<80;R+=1)re=W+D[F+K[R]]|0,R<16?re+=v(ne,X,q)+U[0]:R<32?re+=j(ne,X,q)+U[1]:R<48?re+=A(ne,X,q)+U[2]:R<64?re+=x(ne,X,q)+U[3]:re+=_(ne,X,q)+U[4],re=re|0,re=C(re,Z[R]),re=re+I|0,W=I,I=q,q=C(X,10),X=ne,ne=re,re=L+D[F+ie[R]]|0,R<16?re+=_($,te,pe)+H[0]:R<32?re+=x($,te,pe)+H[1]:R<48?re+=A($,te,pe)+H[2]:R<64?re+=j($,te,pe)+H[3]:re+=v($,te,pe)+H[4],re=re|0,re=C(re,ae[R]),re=re+ge|0,L=ge,ge=pe,pe=C(te,10),te=$,$=re;re=T[1]+X+pe|0,T[1]=T[2]+q+ge|0,T[2]=T[3]+I+L|0,T[3]=T[4]+W+$|0,T[4]=T[0]+ne+te|0,T[0]=re},_doFinalize:function(){var D=this._data,F=D.words,R=this._nDataBytes*8,M=D.sigBytes*8;F[M>>>5]|=128<<24-M%32,F[(M+64>>>9<<4)+14]=(R<<8|R>>>24)&16711935|(R<<24|R>>>8)&4278255360,D.sigBytes=(F.length+1)*4,this._process();for(var N=this._hash,T=N.words,U=0;U<5;U++){var H=T[U];T[U]=(H<<8|H>>>24)&16711935|(H<<24|H>>>8)&4278255360}return N},clone:function(){var D=u.clone.call(this);return D._hash=this._hash.clone(),D}});function v(D,F,R){return D^F^R}function j(D,F,R){return D&F|~D&R}function A(D,F,R){return(D|~F)^R}function x(D,F,R){return D&R|F&~R}function _(D,F,R){return D^(F|~R)}function C(D,F){return D<<F|D>>>32-F}c.RIPEMD160=u._createHelper(z),c.HmacRIPEMD160=u._createHmacHelper(z)})(),r.RIPEMD160})})(qt)),qt.exports}var At={exports:{}},kj=At.exports,Uh;function yl(){return Uh||(Uh=1,(function(a,o){(function(r,s){a.exports=s(He())})(kj,function(r){(function(){var s=r,c=s.lib,l=c.Base,m=s.enc,u=m.Utf8,h=s.algo;h.HMAC=l.extend({init:function(d,g){d=this._hasher=new d.init,typeof g=="string"&&(g=u.parse(g));var y=d.blockSize,f=y*4;g.sigBytes>f&&(g=d.finalize(g)),g.clamp();for(var w=this._oKey=g.clone(),k=this._iKey=g.clone(),z=w.words,v=k.words,j=0;j<y;j++)z[j]^=1549556828,v[j]^=909522486;w.sigBytes=k.sigBytes=f,this.reset()},reset:function(){var d=this._hasher;d.reset(),d.update(this._iKey)},update:function(d){return this._hasher.update(d),this},finalize:function(d){var g=this._hasher,y=g.finalize(d);g.reset();var f=g.finalize(this._oKey.clone().concat(y));return f}})})()})})(At)),At.exports}var Ct={exports:{}},wj=Ct.exports,Wh;function zj(){return Wh||(Wh=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Uo(),yl())})(wj,function(r){return(function(){var s=r,c=s.lib,l=c.Base,m=c.WordArray,u=s.algo,h=u.SHA256,d=u.HMAC,g=u.PBKDF2=l.extend({cfg:l.extend({keySize:128/32,hasher:h,iterations:25e4}),init:function(y){this.cfg=this.cfg.extend(y)},compute:function(y,f){for(var w=this.cfg,k=d.create(w.hasher,y),z=m.create(),v=m.create([1]),j=z.words,A=v.words,x=w.keySize,_=w.iterations;j.length<x;){var C=k.update(f).finalize(v);k.reset();for(var D=C.words,F=D.length,R=C,M=1;M<_;M++){R=k.finalize(R),k.reset();for(var N=R.words,T=0;T<F;T++)D[T]^=N[T]}z.concat(C),A[0]++}return z.sigBytes=x*4,z}});s.PBKDF2=function(y,f,w){return g.create(w).compute(y,f)}})(),r.PBKDF2})})(Ct)),Ct.exports}var Et={exports:{}},xj=Et.exports,$h;function Cn(){return $h||($h=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Rb(),yl())})(xj,function(r){return(function(){var s=r,c=s.lib,l=c.Base,m=c.WordArray,u=s.algo,h=u.MD5,d=u.EvpKDF=l.extend({cfg:l.extend({keySize:128/32,hasher:h,iterations:1}),init:function(g){this.cfg=this.cfg.extend(g)},compute:function(g,y){for(var f,w=this.cfg,k=w.hasher.create(),z=m.create(),v=z.words,j=w.keySize,A=w.iterations;v.length<j;){f&&k.update(f),f=k.update(g).finalize(y),k.reset();for(var x=1;x<A;x++)f=k.finalize(f),k.reset();z.concat(f)}return z.sigBytes=j*4,z}});s.EvpKDF=function(g,y,f){return d.create(f).compute(g,y)}})(),r.EvpKDF})})(Et)),Et.exports}var St={exports:{}},jj=St.exports,Gh;function Ri(Line truncated
*/return(function(s){var c=r,l=c.lib,m=l.WordArray,u=l.Hasher,h=c.algo,d=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]),g=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]),f=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]),w=m.create([0,1518500249,1859775393,2400959708,2840853838]),k=m.create([1352829926,1548603684,1836072691,2053994217,0]),z=h.RIPEMD160=u.extend({_doReset:function(){this._hash=m.create([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(D,R){for(var F=0;F<16;F++){var M=R+F,P=D[M];D[M]=(P<<8|P>>>24)&16711935|(P<<24|P>>>8)&4278255360}var T=this._hash.words,U=w.words,H=k.words,K=d.words,ie=g.words,Z=y.words,ae=f.words,W,ne,X,A,I,L,$,te,pe,ge;L=W=T[0],$=ne=T[1],te=X=T[2],pe=A=T[3],ge=I=T[4];for(var re,F=0;F<80;F+=1)re=W+D[R+K[F]]|0,F<16?re+=v(ne,X,A)+U[0]:F<32?re+=j(ne,X,A)+U[1]:F<48?re+=q(ne,X,A)+U[2]:F<64?re+=x(ne,X,A)+U[3]:re+=_(ne,X,A)+U[4],re=re|0,re=C(re,Z[F]),re=re+I|0,W=I,I=A,A=C(X,10),X=ne,ne=re,re=L+D[R+ie[F]]|0,F<16?re+=_($,te,pe)+H[0]:F<32?re+=x($,te,pe)+H[1]:F<48?re+=q($,te,pe)+H[2]:F<64?re+=j($,te,pe)+H[3]:re+=v($,te,pe)+H[4],re=re|0,re=C(re,ae[F]),re=re+ge|0,L=ge,ge=pe,pe=C(te,10),te=$,$=re;re=T[1]+X+pe|0,T[1]=T[2]+A+ge|0,T[2]=T[3]+I+L|0,T[3]=T[4]+W+$|0,T[4]=T[0]+ne+te|0,T[0]=re},_doFinalize:function(){var D=this._data,R=D.words,F=this._nDataBytes*8,M=D.sigBytes*8;R[M>>>5]|=128<<24-M%32,R[(M+64>>>9<<4)+14]=(F<<8|F>>>24)&16711935|(F<<24|F>>>8)&4278255360,D.sigBytes=(R.length+1)*4,this._process();for(var P=this._hash,T=P.words,U=0;U<5;U++){var H=T[U];T[U]=(H<<8|H>>>24)&16711935|(H<<24|H>>>8)&4278255360}return P},clone:function(){var D=u.clone.call(this);return D._hash=this._hash.clone(),D}});function v(D,R,F){return D^R^F}function j(D,R,F){return D&R|~D&F}function q(D,R,F){return(D|~R)^F}function x(D,R,F){return D&F|R&~F}function _(D,R,F){return D^(R|~F)}function C(D,R){return D<<R|D>>>32-R}c.RIPEMD160=u._createHelper(z),c.HmacRIPEMD160=u._createHmacHelper(z)})(),r.RIPEMD160})})(jt)),jt.exports}var qt={exports:{}},bj=qt.exports,Lh;function hl(){return Lh||(Lh=1,(function(a,o){(function(r,s){a.exports=s(He())})(bj,function(r){(function(){var s=r,c=s.lib,l=c.Base,m=s.enc,u=m.Utf8,h=s.algo;h.HMAC=l.extend({init:function(d,g){d=this._hasher=new d.init,typeof g=="string"&&(g=u.parse(g));var y=d.blockSize,f=y*4;g.sigBytes>f&&(g=d.finalize(g)),g.clamp();for(var w=this._oKey=g.clone(),k=this._iKey=g.clone(),z=w.words,v=k.words,j=0;j<y;j++)z[j]^=1549556828,v[j]^=909522486;w.sigBytes=k.sigBytes=f,this.reset()},reset:function(){var d=this._hasher;d.reset(),d.update(this._iKey)},update:function(d){return this._hasher.update(d),this},finalize:function(d){var g=this._hasher,y=g.finalize(d);g.reset();var f=g.finalize(this._oKey.clone().concat(y));return f}})})()})})(qt)),qt.exports}var At={exports:{}},fj=At.exports,Hh;function vj(){return Hh||(Hh=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Uo(),hl())})(fj,function(r){return(function(){var s=r,c=s.lib,l=c.Base,m=c.WordArray,u=s.algo,h=u.SHA256,d=u.HMAC,g=u.PBKDF2=l.extend({cfg:l.extend({keySize:128/32,hasher:h,iterations:25e4}),init:function(y){this.cfg=this.cfg.extend(y)},compute:function(y,f){for(var w=this.cfg,k=d.create(w.hasher,y),z=m.create(),v=m.create([1]),j=z.words,q=v.words,x=w.keySize,_=w.iterations;j.length<x;){var C=k.update(f).finalize(v);k.reset();for(var D=C.words,R=D.length,F=C,M=1;M<_;M++){F=k.finalize(F),k.reset();for(var P=F.words,T=0;T<R;T++)D[T]^=P[T]}z.concat(C),q[0]++}return z.sigBytes=x*4,z}});s.PBKDF2=function(y,f,w){return g.create(w).compute(y,f)}})(),r.PBKDF2})})(At)),At.exports}var Ct={exports:{}},kj=Ct.exports,Vh;function Cn(){return Vh||(Vh=1,(function(a,o){(function(r,s,c){a.exports=s(He(),_b(),hl())})(kj,function(r){return(function(){var s=r,c=s.lib,l=c.Base,m=c.WordArray,u=s.algo,h=u.MD5,d=u.EvpKDF=l.extend({cfg:l.extend({keySize:128/32,hasher:h,iterations:1}),init:function(g){this.cfg=this.cfg.extend(g)},compute:function(g,y){for(var f,w=this.cfg,k=w.hasher.create(),z=m.create(),v=z.words,j=w.keySize,q=w.iterations;v.length<j;){f&&k.update(f),f=k.update(g).finalize(y),k.reset();for(var x=1;x<q;x++)f=k.finalize(f),k.reset();z.concat(f)}return z.sigBytes=j*4,z}});s.EvpKDF=function(g,y,f){return d.create(f).compute(g,y)}})(),r.EvpKDF})})(Ct)),Ct.exports}var Et={exports:{}},wj=Et.exports,Uh;function Ri(Line truncated
* Counter block mode compatible with Dr Brian Gladman fileenc.c
* derived from CryptoJS.mode.CTR
* Jan Hruby jhruby.web@gmail.com
*/return r.mode.CTRGladman=(function(){var s=r.lib.BlockCipherMode.extend();function c(u){if((u>>24&255)===255){var h=u>>16&255,d=u>>8&255,g=u&255;h===255?(h=0,d===255?(d=0,g===255?g=0:++g):++d):++h,u=0,u+=h<<16,u+=d<<8,u+=g}else u+=1<<24;return u}function l(u){return(u[0]=c(u[0]))===0&&(u[1]=c(u[1])),u}var m=s.Encryptor=s.extend({processBlock:function(u,h){var d=this._cipher,g=d.blockSize,y=this._iv,f=this._counter;y&&(f=this._counter=y.slice(0),this._iv=void 0),l(f);var w=f.slice(0);d.encryptBlock(w,0);for(var k=0;k<g;k++)u[h+k]^=w[k]}});return s.Decryptor=m,s})(),r.mode.CTRGladman})})(Dt)),Dt.exports}var Ft={exports:{}},_j=Ft.exports,Zh;function Dj(){return Zh||(Zh=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(_j,function(r){return r.mode.OFB=(function(){var s=r.lib.BlockCipherMode.extend(),c=s.Encryptor=s.extend({processBlock:function(l,m){var u=this._cipher,h=u.blockSize,d=this._iv,g=this._keystream;d&&(g=this._keystream=d.slice(0),this._iv=void 0),u.encryptBlock(g,0);for(var y=0;y<h;y++)l[m+y]^=g[y]}});return s.Decryptor=c,s})(),r.mode.OFB})})(Ft)),Ft.exports}var Rt={exports:{}},Fj=Rt.exports,Xh;function Rj(){return Xh||(Xh=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Fj,function(r){return r.mode.ECB=(function(){var s=r.lib.BlockCipherMode.extend();return s.Encryptor=s.extend({processBlock:function(c,l){this._cipher.encryptBlock(c,l)}}),s.Decryptor=s.extend({processBlock:function(c,l){this._cipher.decryptBlock(c,l)}}),s})(),r.mode.ECB})})(Rt)),Rt.exports}var Tt={exports:{}},Tj=Tt.exports,Jh;function Pj(){return Jh||(Jh=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Tj,function(r){return r.pad.AnsiX923={pad:function(s,c){var l=s.sigBytes,m=c*4,u=m-l%m,h=l+u-1;s.clamp(),s.words[h>>>2]|=u<<24-h%4*8,s.sigBytes+=u},unpad:function(s){var c=s.words[s.sigBytes-1>>>2]&255;s.sigBytes-=c}},r.pad.Ansix923})})(Tt)),Tt.exports}var Pt={exports:{}},Nj=Pt.exports,eg;function Ij(){return eg||(eg=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Nj,function(r){return r.pad.Iso10126={pad:function(s,c){var l=c*4,m=l-s.sigBytes%l;s.concat(r.lib.WordArray.random(m-1)).concat(r.lib.WordArray.create([m<<24],1))},unpad:function(s){var c=s.words[s.sigBytes-1>>>2]&255;s.sigBytes-=c}},r.pad.Iso10126})})(Pt)),Pt.exports}var Nt={exports:{}},Mj=Nt.exports,ig;function Oj(){return ig||(ig=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Mj,function(r){return r.pad.Iso97971={pad:function(s,c){s.concat(r.lib.WordArray.create([2147483648],1)),r.pad.ZeroPadding.pad(s,c)},unpad:function(s){r.pad.ZeroPadding.unpad(s),s.sigBytes--}},r.pad.Iso97971})})(Nt)),Nt.exports}var It={exports:{}},Lj=It.exports,ag;function Hj(){return ag||(ag=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Lj,function(r){return r.pad.ZeroPadding={pad:function(s,c){var l=c*4;s.clamp(),s.sigBytes+=l-(s.sigBytes%l||l)},unpad:function(s){for(var c=s.words,l=s.sigBytes-1,l=s.sigBytes-1;l>=0;l--)if(c[l>>>2]>>>24-l%4*8&255){s.sigBytes=l+1;break}}},r.pad.ZeroPadding})})(It)),It.exports}var Mt={exports:{}},Vj=Mt.exports,ng;function Uj(){return ng||(ng=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Vj,function(r){return r.pad.NoPadding={pad:function(){},unpad:function(){}},r.pad.NoPadding})})(Mt)),Mt.exports}var Ot={exports:{}},Wj=Ot.exports,rg;function $j(){return rg||(rg=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Wj,function(r){return(function(s){var c=r,l=c.lib,m=l.CipherParams,u=c.enc,h=u.Hex,d=c.format;d.Hex={stringify:function(g){return g.ciphertext.toString(h)},parse:function(g){var y=h.parse(g);return m.create({ciphertext:y})}}})(),r.format.Hex})})(Ot)),Ot.exports}var Lt={exports:{}},Gj=Lt.exports,og;function Qj(){return og||(og=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Jn(),er(),Cn(),Ri())})(Gj,function(r){return(function(){var s=r,c=s.lib,l=c.BlockCipher,m=s.algo,u=[],h=[],d=[],g=[],y=[],f=[],w=[],k=[],z=[],v=[];(function(){for(var x=[],_=0;_<256;_++)_<128?x[_]=_<<1:x[_]=_<<1^283;for(var C=0,D=0,_=0;_<256;_++){var F=D^D<<1^D<<2^D<<3^D<<4;F=F>>>8^F&255^99,u[C]=F,h[F]=C;var R=x[C],M=x[R],N=x[M],T=x[F]*257^F*16843008;d[C]=T<<24|T>>>8,g[C]=T<<16|T>>>16,y[C]=T<<8|T>>>24,f[C]=T;var T=N*16843009^M*65537^R*257^C*16843008;w[F]=T<<24|T>>>8,k[F]=T<<16|T>>>16,z[F]=T<<8|T>>>24,v[F]=T,C?(C=R^x[x[x[N^R]]],D^=x[x[D]]):C=D=1}})();var j=[0,1,2,4,8,16,32,64,128,27,54],A=m.AES=l.extend({_doReset:function(){var x;if(!(this._nRounds&&this._keyPriorReset===this._key)){for(var _=this._keyPriorReset=this._key,C=_.words,D=_.sigBytes/4,F=this._nRounds=D+6,R=(F+1)*4,M=this._keySchedule=[],N=0;N<R;N++)N<D?M[N]=C[N]:(x=M[N-1],N%D?D>6&&N%D==4&&(x=u[x>>>24]<<24|u[x>>>16&255]<<16|u[x>>>8&255]<<8|u[x&255]):(x=x<<8|x>>>24,x=u[x>>>24]<<24|u[x>>>16&255]<<16|u[x>>>8&255]<<8|u[x&255],x^=j[N/D|0]<<24),M[N]=M[N-D]^x);for(var T=this._invKeySchedule=[],U=0;U<R;U++){var N=R-U;if(U%4)var x=M[N];else var x=M[N-4];U<4||N<=4?T[U]=x:T[U]=w[u[x>>>24]]^k[u[x>>>16&255]]^z[u[x>>>8&255]]^v[u[x&255]]}}},encryptBlock:Line truncated
*/return r.mode.CTRGladman=(function(){var s=r.lib.BlockCipherMode.extend();function c(u){if((u>>24&255)===255){var h=u>>16&255,d=u>>8&255,g=u&255;h===255?(h=0,d===255?(d=0,g===255?g=0:++g):++d):++h,u=0,u+=h<<16,u+=d<<8,u+=g}else u+=1<<24;return u}function l(u){return(u[0]=c(u[0]))===0&&(u[1]=c(u[1])),u}var m=s.Encryptor=s.extend({processBlock:function(u,h){var d=this._cipher,g=d.blockSize,y=this._iv,f=this._counter;y&&(f=this._counter=y.slice(0),this._iv=void 0),l(f);var w=f.slice(0);d.encryptBlock(w,0);for(var k=0;k<g;k++)u[h+k]^=w[k]}});return s.Decryptor=m,s})(),r.mode.CTRGladman})})(_t)),_t.exports}var Dt={exports:{}},Ej=Dt.exports,Qh;function Sj(){return Qh||(Qh=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Ej,function(r){return r.mode.OFB=(function(){var s=r.lib.BlockCipherMode.extend(),c=s.Encryptor=s.extend({processBlock:function(l,m){var u=this._cipher,h=u.blockSize,d=this._iv,g=this._keystream;d&&(g=this._keystream=d.slice(0),this._iv=void 0),u.encryptBlock(g,0);for(var y=0;y<h;y++)l[m+y]^=g[y]}});return s.Decryptor=c,s})(),r.mode.OFB})})(Dt)),Dt.exports}var Ft={exports:{}},Bj=Ft.exports,Kh;function _j(){return Kh||(Kh=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Bj,function(r){return r.mode.ECB=(function(){var s=r.lib.BlockCipherMode.extend();return s.Encryptor=s.extend({processBlock:function(c,l){this._cipher.encryptBlock(c,l)}}),s.Decryptor=s.extend({processBlock:function(c,l){this._cipher.decryptBlock(c,l)}}),s})(),r.mode.ECB})})(Ft)),Ft.exports}var Rt={exports:{}},Dj=Rt.exports,Yh;function Fj(){return Yh||(Yh=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Dj,function(r){return r.pad.AnsiX923={pad:function(s,c){var l=s.sigBytes,m=c*4,u=m-l%m,h=l+u-1;s.clamp(),s.words[h>>>2]|=u<<24-h%4*8,s.sigBytes+=u},unpad:function(s){var c=s.words[s.sigBytes-1>>>2]&255;s.sigBytes-=c}},r.pad.Ansix923})})(Rt)),Rt.exports}var Tt={exports:{}},Rj=Tt.exports,Zh;function Tj(){return Zh||(Zh=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Rj,function(r){return r.pad.Iso10126={pad:function(s,c){var l=c*4,m=l-s.sigBytes%l;s.concat(r.lib.WordArray.random(m-1)).concat(r.lib.WordArray.create([m<<24],1))},unpad:function(s){var c=s.words[s.sigBytes-1>>>2]&255;s.sigBytes-=c}},r.pad.Iso10126})})(Tt)),Tt.exports}var Pt={exports:{}},Pj=Pt.exports,Xh;function Nj(){return Xh||(Xh=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Pj,function(r){return r.pad.Iso97971={pad:function(s,c){s.concat(r.lib.WordArray.create([2147483648],1)),r.pad.ZeroPadding.pad(s,c)},unpad:function(s){r.pad.ZeroPadding.unpad(s),s.sigBytes--}},r.pad.Iso97971})})(Pt)),Pt.exports}var Nt={exports:{}},Ij=Nt.exports,Jh;function Mj(){return Jh||(Jh=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Ij,function(r){return r.pad.ZeroPadding={pad:function(s,c){var l=c*4;s.clamp(),s.sigBytes+=l-(s.sigBytes%l||l)},unpad:function(s){for(var c=s.words,l=s.sigBytes-1,l=s.sigBytes-1;l>=0;l--)if(c[l>>>2]>>>24-l%4*8&255){s.sigBytes=l+1;break}}},r.pad.ZeroPadding})})(Nt)),Nt.exports}var It={exports:{}},Oj=It.exports,eg;function Lj(){return eg||(eg=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Oj,function(r){return r.pad.NoPadding={pad:function(){},unpad:function(){}},r.pad.NoPadding})})(It)),It.exports}var Mt={exports:{}},Hj=Mt.exports,ig;function Vj(){return ig||(ig=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Ri())})(Hj,function(r){return(function(s){var c=r,l=c.lib,m=l.CipherParams,u=c.enc,h=u.Hex,d=c.format;d.Hex={stringify:function(g){return g.ciphertext.toString(h)},parse:function(g){var y=h.parse(g);return m.create({ciphertext:y})}}})(),r.format.Hex})})(Mt)),Mt.exports}var Ot={exports:{}},Uj=Ot.exports,ag;function Wj(){return ag||(ag=1,(function(a,o){(function(r,s,c){a.exports=s(He(),Jn(),er(),Cn(),Ri())})(Uj,function(r){return(function(){var s=r,c=s.lib,l=c.BlockCipher,m=s.algo,u=[],h=[],d=[],g=[],y=[],f=[],w=[],k=[],z=[],v=[];(function(){for(var x=[],_=0;_<256;_++)_<128?x[_]=_<<1:x[_]=_<<1^283;for(var C=0,D=0,_=0;_<256;_++){var R=D^D<<1^D<<2^D<<3^D<<4;R=R>>>8^R&255^99,u[C]=R,h[R]=C;var F=x[C],M=x[F],P=x[M],T=x[R]*257^R*16843008;d[C]=T<<24|T>>>8,g[C]=T<<16|T>>>16,y[C]=T<<8|T>>>24,f[C]=T;var T=P*16843009^M*65537^F*257^C*16843008;w[R]=T<<24|T>>>8,k[R]=T<<16|T>>>16,z[R]=T<<8|T>>>24,v[R]=T,C?(C=F^x[x[x[P^F]]],D^=x[x[D]]):C=D=1}})();var j=[0,1,2,4,8,16,32,64,128,27,54],q=m.AES=l.extend({_doReset:function(){var x;if(!(this._nRounds&&this._keyPriorReset===this._key)){for(var _=this._keyPriorReset=this._key,C=_.words,D=_.sigBytes/4,R=this._nRounds=D+6,F=(R+1)*4,M=this._keySchedule=[],P=0;P<F;P++)P<D?M[P]=C[P]:(x=M[P-1],P%D?D>6&&P%D==4&&(x=u[x>>>24]<<24|u[x>>>16&255]<<16|u[x>>>8&255]<<8|u[x&255]):(x=x<<8|x>>>24,x=u[x>>>24]<<24|u[x>>>16&255]<<16|u[x>>>8&255]<<8|u[x&255],x^=j[P/D|0]<<24),M[P]=M[P-D]^x);for(var T=this._invKeySchedule=[],U=0;U<F;U++){var P=F-U;if(U%4)var x=M[P];else var x=M[P-4];U<4||P<=4?T[U]=x:T[U]=w[u[x>>>24]]^k[u[x>>>16&255]]^z[u[x>>>8&255]]^v[u[x&255]]}}},encryptBlock: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:u+h,endByte:u+c.length-1,value:f});const w={type:a.PayloadType.Request,version:a.PayloadVersion.Version1,isValid:!0,timestamp:0,requestType:a.RequestType.GetStats,requestData:"",destinationHash:d,sourceHash:g,cipherMac:y,ciphertext:f};return l!=null&&l.includeSegments&&(w.segments=m),w}catch(m){return{type:a.PayloadType.Request,version:a.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode request payload"],timestamp:0,requestType:a.RequestType.GetStats,requestData:"",destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:""}}}}return Ao.RequestPayloadDecoder=r,Ao}var Co={},Eg;function Bq(){if(Eg)return Co;Eg=1,Object.defineProperty(Co,"__esModule",{value:!0}),Co.ResponsePayloadDecoder=void 0;const a=ua(),o=Ii();class r{static decode(c,l){try{if(c.length<4){const k={type:a.PayloadType.Response,version:a.PayloadVersion.Version1,isValid:!1,errors:["Response payload too short (minimum 4 bytes: dest + source + MAC)"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return l!=null&&l.includeSegments&&(k.segments=[{name:"Invalid Response Data",description:"Response payload too short (minimum 4 bytes required)",startByte:l.segmentOffset||0,endByte:(l.segmentOffset||0)+c.length-1,value:(0,o.bytesToHex)(c)}]),k}const m=[],u=(l==null?void 0:l.segmentOffset)||0;let h=0;const d=(0,o.byteToHex)(c[h]);l!=null&&l.includeSegments&&m.push({name:"Destination Hash",description:"First byte of destination node public key",startByte:u+h,endByte:u+h,value:d}),h+=1;const g=(0,o.byteToHex)(c[h]);l!=null&&l.includeSegments&&m.push({name:"Source Hash",description:"First byte of source node public key",startByte:u+h,endByte:u+h,value:g}),h+=1;const y=(0,o.bytesToHex)(c.subarray(h,h+2));l!=null&&l.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data in next field",startByte:u+h,endByte:u+h+1,value:y}),h+=2;const f=(0,o.bytesToHex)(c.subarray(h));l!=null&&l.includeSegments&&c.length>h&&m.push({name:"Ciphertext",description:"Encrypted response data (tag + content)",startByte:u+h,endByte:u+c.length-1,value:f});const w={type:a.PayloadType.Response,version:a.PayloadVersion.Version1,isValid:!0,destinationHash:d,sourceHash:g,cipherMac:y,ciphertext:f,ciphertextLength:c.length-4};return l!=null&&l.includeSegments&&(w.segments=m),w}catch(m){return{type:a.PayloadType.Response,version:a.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode response payload"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0}}}}return Co.ResponsePayloadDecoder=r,Co}var Eo={},Sg;function _q(){if(Sg)return Eo;Sg=1,Object.defineProperty(Eo,"__esModule",{value:!0}),Eo.AnonRequestPayloadDecoder=void 0;const a=ua(),o=Ii();class r{static decode(c,l){try{if(c.length<35){const k={type:a.PayloadType.AnonRequest,version:a.PayloadVersion.Version1,isValid:!1,errors:["AnonRequest payload too short (minimum 35 bytes: dest + public key + MAC)"],destinationHash:"",senderPublicKey:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return l!=null&&l.includeSegments&&(k.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:l.segmentOffset||0,endByte:(l.segmentOffset||0)+c.length-1,value:(0,o.bytesToHex)(c)}]),k}const m=[],u=(l==null?void 0:l.segmentOffset)||0;let h=0;const d=(0,o.byteToHex)(c[0]);l!=null&&l.includeSegments&&m.push({name:"Destination Hash",description:`First byte of destination node public key: 0x${d}`,startByte:u+h,endByte:u+h,value:d}),h+=1;const g=(0,o.bytesToHex)(c.subarray(1,33));l!=null&&l.includeSegments&&m.push({name:"Sender Public Key",description:"Ed25519 public key of the sender (32 bytes)",startByte:u+h,endByte:u+h+31,value:g}),h+=32;const y=(0,o.bytesToHex)(c.subarray(33,35));l!=null&&l.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data verification (2 bytes)",startByte:u+h,endByte:u+h+1,value:y}),h+=2;const f=(0,o.bytesToHex)(c.subarray(35));l!=null&&l.includeSegments&&c.length>35&&m.push({name:"Ciphertext",description:`Encrypted message data (${c.length-35} bytes). Contains encrypted plaintext with this structure:
• Request Data (remaining bytes) - additional request-specific data`,startByte:u+h,endByte:u+c.length-1,value:f});const w={type:a.PayloadType.Request,version:a.PayloadVersion.Version1,isValid:!0,timestamp:0,requestType:a.RequestType.GetStats,requestData:"",destinationHash:d,sourceHash:g,cipherMac:y,ciphertext:f};return l!=null&&l.includeSegments&&(w.segments=m),w}catch(m){return{type:a.PayloadType.Request,version:a.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode request payload"],timestamp:0,requestType:a.RequestType.GetStats,requestData:"",destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:""}}}}return Ao.RequestPayloadDecoder=r,Ao}var Co={},qg;function Cq(){if(qg)return Co;qg=1,Object.defineProperty(Co,"__esModule",{value:!0}),Co.ResponsePayloadDecoder=void 0;const a=ua(),o=Ii();class r{static decode(c,l){try{if(c.length<4){const k={type:a.PayloadType.Response,version:a.PayloadVersion.Version1,isValid:!1,errors:["Response payload too short (minimum 4 bytes: dest + source + MAC)"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return l!=null&&l.includeSegments&&(k.segments=[{name:"Invalid Response Data",description:"Response payload too short (minimum 4 bytes required)",startByte:l.segmentOffset||0,endByte:(l.segmentOffset||0)+c.length-1,value:(0,o.bytesToHex)(c)}]),k}const m=[],u=(l==null?void 0:l.segmentOffset)||0;let h=0;const d=(0,o.byteToHex)(c[h]);l!=null&&l.includeSegments&&m.push({name:"Destination Hash",description:"First byte of destination node public key",startByte:u+h,endByte:u+h,value:d}),h+=1;const g=(0,o.byteToHex)(c[h]);l!=null&&l.includeSegments&&m.push({name:"Source Hash",description:"First byte of source node public key",startByte:u+h,endByte:u+h,value:g}),h+=1;const y=(0,o.bytesToHex)(c.subarray(h,h+2));l!=null&&l.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data in next field",startByte:u+h,endByte:u+h+1,value:y}),h+=2;const f=(0,o.bytesToHex)(c.subarray(h));l!=null&&l.includeSegments&&c.length>h&&m.push({name:"Ciphertext",description:"Encrypted response data (tag + content)",startByte:u+h,endByte:u+c.length-1,value:f});const w={type:a.PayloadType.Response,version:a.PayloadVersion.Version1,isValid:!0,destinationHash:d,sourceHash:g,cipherMac:y,ciphertext:f,ciphertextLength:c.length-4};return l!=null&&l.includeSegments&&(w.segments=m),w}catch(m){return{type:a.PayloadType.Response,version:a.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode response payload"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0}}}}return Co.ResponsePayloadDecoder=r,Co}var Eo={},Ag;function Eq(){if(Ag)return Eo;Ag=1,Object.defineProperty(Eo,"__esModule",{value:!0}),Eo.AnonRequestPayloadDecoder=void 0;const a=ua(),o=Ii();class r{static decode(c,l){try{if(c.length<35){const k={type:a.PayloadType.AnonRequest,version:a.PayloadVersion.Version1,isValid:!1,errors:["AnonRequest payload too short (minimum 35 bytes: dest + public key + MAC)"],destinationHash:"",senderPublicKey:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return l!=null&&l.includeSegments&&(k.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:l.segmentOffset||0,endByte:(l.segmentOffset||0)+c.length-1,value:(0,o.bytesToHex)(c)}]),k}const m=[],u=(l==null?void 0:l.segmentOffset)||0;let h=0;const d=(0,o.byteToHex)(c[0]);l!=null&&l.includeSegments&&m.push({name:"Destination Hash",description:`First byte of destination node public key: 0x${d}`,startByte:u+h,endByte:u+h,value:d}),h+=1;const g=(0,o.bytesToHex)(c.subarray(1,33));l!=null&&l.includeSegments&&m.push({name:"Sender Public Key",description:"Ed25519 public key of the sender (32 bytes)",startByte:u+h,endByte:u+h+31,value:g}),h+=32;const y=(0,o.bytesToHex)(c.subarray(33,35));l!=null&&l.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data verification (2 bytes)",startByte:u+h,endByte:u+h+1,value:y}),h+=2;const f=(0,o.bytesToHex)(c.subarray(35));l!=null&&l.includeSegments&&c.length>35&&m.push({name:"Ciphertext",description:`Encrypted message data (${c.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:u+h,endByte:u+c.length-1,value:f});const w={type:a.PayloadType.AnonRequest,version:a.PayloadVersion.Version1,isValid:!0,destinationHash:d,senderPublicKey:g,cipherMac:y,ciphertext:f,ciphertextLength:c.length-35};return l!=null&&l.includeSegments&&(w.segments=m),w}catch(m){return{type:a.PayloadType.AnonRequest,version:a.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode AnonRequest payload"],destinationHash:"",senderPublicKey:"",cipherMac:"",ciphertext:"",ciphertextLength:0}}}}return Eo.AnonRequestPayloadDecoder=r,Eo}var So={},Bg;function Dq(){if(Bg)return So;Bg=1,Object.defineProperty(So,"__esModule",{value:!0}),So.AckPayloadDecoder=void 0;const a=ua(),o=Ii();class r{static decode(c,l){try{if(c.length<4){const g={type:a.PayloadType.Ack,version:a.PayloadVersion.Version1,isValid:!1,errors:["Ack payload too short (minimum 4 bytes for checksum)"],checksum:""};return l!=null&&l.includeSegments&&(g.segments=[{name:"Invalid Ack Data",description:"Ack payload too short (minimum 4 bytes required for checksum)",startByte:l.segmentOffset||0,endByte:(l.segmentOffset||0)+c.length-1,value:(0,o.bytesToHex)(c)}]),g}const m=[],u=(l==null?void 0:l.segmentOffset)||0,h=(0,o.bytesToHex)(c.subarray(0,4));l!=null&&l.includeSegments&&m.push({name:"Checksum",description:`CRC checksum of message timestamp, text, and sender pubkey: 0x${h}`,startByte:u,endByte:u+3,value:h}),l!=null&&l.includeSegments&&c.length>4&&m.push({name:"Additional Data",description:"Extra data in Ack payload",startByte:u+4,endByte:u+c.length-1,value:(0,o.bytesToHex)(c.subarray(4))});const d={type:a.PayloadType.Ack,version:a.PayloadVersion.Version1,isValid:!0,checksum:h};return l!=null&&l.includeSegments&&(d.segments=m),d}catch(m){return{type:a.PayloadType.Ack,version:a.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode Ack payload"],checksum:""}}}}return So.AckPayloadDecoder=r,So}var Bo={},_g;function Fq(){if(_g)return Bo;_g=1,Object.defineProperty(Bo,"__esModule",{value:!0}),Bo.PathPayloadDecoder=void 0;const a=ua(),o=Ii();class r{static decode(c){try{if(c.length<2)return{type:a.PayloadType.Path,version:a.PayloadVersion.Version1,isValid:!1,errors:["Path payload too short (minimum 2 bytes: path length + extra type)"],pathLength:0,pathHashes:[],extraType:0,extraData:""};const l=c[0];if(c.length<1+l+1)return{type:a.PayloadType.Path,version:a.PayloadVersion.Version1,isValid:!1,errors:[`Path payload too short (need ${1+l+1} bytes for path length + path + extra type)`],pathLength:l,pathHashes:[],extraType:0,extraData:""};const m=[];for(let d=0;d<l;d++)m.push((0,o.byteToHex)(c[1+d]));const u=c[1+l];let h="";return c.length>1+l+1&&(h=(0,o.bytesToHex)(c.subarray(1+l+1))),{type:a.PayloadType.Path,version:a.PayloadVersion.Version1,isValid:!0,pathLength:l,pathHashes:m,extraType:u,extraData:h}}catch(l){return{type:a.PayloadType.Path,version:a.PayloadVersion.Version1,isValid:!1,errors:[l instanceof Error?l.message:"Failed to decode Path payload"],pathLength:0,pathHashes:[],extraType:0,extraData:""}}}}return Bo.PathPayloadDecoder=r,Bo}var _o={},Dg;function Rq(){if(Dg)return _o;Dg=1,Object.defineProperty(_o,"__esModule",{value:!0}),_o.TextMessagePayloadDecoder=void 0;const a=ua(),o=Ii();class r{static decode(c,l){try{if(c.length<4){const k={type:a.PayloadType.TextMessage,version:a.PayloadVersion.Version1,isValid:!1,errors:["TextMessage payload too short (minimum 4 bytes: dest + source + MAC)"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return l!=null&&l.includeSegments&&(k.segments=[{name:"Invalid TextMessage Data",description:"TextMessage payload too short (minimum 4 bytes required)",startByte:l.segmentOffset||0,endByte:(l.segmentOffset||0)+c.length-1,value:(0,o.bytesToHex)(c)}]),k}const m=[],u=(l==null?void 0:l.segmentOffset)||0;let h=0;const d=(0,o.byteToHex)(c[h]);l!=null&&l.includeSegments&&m.push({name:"Destination Hash",description:"First byte of destination node public key",startByte:u+h,endByte:u+h,value:d}),h+=1;const g=(0,o.byteToHex)(c[h]);l!=null&&l.includeSegments&&m.push({name:"Source Hash",description:"First byte of source node public key",startByte:u+h,endByte:u+h,value:g}),h+=1;const y=(0,o.bytesToHex)(c.subarray(h,h+2));l!=null&&l.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data in next field",startByte:u+h,endByte:u+h+1,value:y}),h+=2;const f=(0,o.bytesToHex)(c.subarray(h));l!=null&&l.includeSegments&&c.length>h&&m.push({name:"Ciphertext",description:"Encrypted message data (timestamp + message text)",startByte:u+h,endByte:u+c.length-1,value:f});const w={type:a.PayloadType.TextMessage,version:a.PayloadVersion.Version1,isValid:!0,destinationHash:d,sourceHash:g,cipherMac:y,ciphertext:f,ciphertextLength:c.length-4};return l!=null&&l.includeSegments&&(w.segments=m),w}catch(m){return{type:a.PayloadType.TextMessage,version:a.PayloadVersion.Version1,i Line truncated
• Password (remaining bytes) - password for repeater/room`,startByte:u+h,endByte:u+c.length-1,value:f});const w={type:a.PayloadType.AnonRequest,version:a.PayloadVersion.Version1,isValid:!0,destinationHash:d,senderPublicKey:g,cipherMac:y,ciphertext:f,ciphertextLength:c.length-35};return l!=null&&l.includeSegments&&(w.segments=m),w}catch(m){return{type:a.PayloadType.AnonRequest,version:a.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode AnonRequest payload"],destinationHash:"",senderPublicKey:"",cipherMac:"",ciphertext:"",ciphertextLength:0}}}}return Eo.AnonRequestPayloadDecoder=r,Eo}var So={},Cg;function Sq(){if(Cg)return So;Cg=1,Object.defineProperty(So,"__esModule",{value:!0}),So.AckPayloadDecoder=void 0;const a=ua(),o=Ii();class r{static decode(c,l){try{if(c.length<4){const g={type:a.PayloadType.Ack,version:a.PayloadVersion.Version1,isValid:!1,errors:["Ack payload too short (minimum 4 bytes for checksum)"],checksum:""};return l!=null&&l.includeSegments&&(g.segments=[{name:"Invalid Ack Data",description:"Ack payload too short (minimum 4 bytes required for checksum)",startByte:l.segmentOffset||0,endByte:(l.segmentOffset||0)+c.length-1,value:(0,o.bytesToHex)(c)}]),g}const m=[],u=(l==null?void 0:l.segmentOffset)||0,h=(0,o.bytesToHex)(c.subarray(0,4));l!=null&&l.includeSegments&&m.push({name:"Checksum",description:`CRC checksum of message timestamp, text, and sender pubkey: 0x${h}`,startByte:u,endByte:u+3,value:h}),l!=null&&l.includeSegments&&c.length>4&&m.push({name:"Additional Data",description:"Extra data in Ack payload",startByte:u+4,endByte:u+c.length-1,value:(0,o.bytesToHex)(c.subarray(4))});const d={type:a.PayloadType.Ack,version:a.PayloadVersion.Version1,isValid:!0,checksum:h};return l!=null&&l.includeSegments&&(d.segments=m),d}catch(m){return{type:a.PayloadType.Ack,version:a.PayloadVersion.Version1,isValid:!1,errors:[m instanceof Error?m.message:"Failed to decode Ack payload"],checksum:""}}}}return So.AckPayloadDecoder=r,So}var Bo={},Eg;function Bq(){if(Eg)return Bo;Eg=1,Object.defineProperty(Bo,"__esModule",{value:!0}),Bo.PathPayloadDecoder=void 0;const a=ua(),o=Ii();class r{static decode(c){try{if(c.length<2)return{type:a.PayloadType.Path,version:a.PayloadVersion.Version1,isValid:!1,errors:["Path payload too short (minimum 2 bytes: path length + extra type)"],pathLength:0,pathHashes:[],extraType:0,extraData:""};const l=c[0];if(c.length<1+l+1)return{type:a.PayloadType.Path,version:a.PayloadVersion.Version1,isValid:!1,errors:[`Path payload too short (need ${1+l+1} bytes for path length + path + extra type)`],pathLength:l,pathHashes:[],extraType:0,extraData:""};const m=[];for(let d=0;d<l;d++)m.push((0,o.byteToHex)(c[1+d]));const u=c[1+l];let h="";return c.length>1+l+1&&(h=(0,o.bytesToHex)(c.subarray(1+l+1))),{type:a.PayloadType.Path,version:a.PayloadVersion.Version1,isValid:!0,pathLength:l,pathHashes:m,extraType:u,extraData:h}}catch(l){return{type:a.PayloadType.Path,version:a.PayloadVersion.Version1,isValid:!1,errors:[l instanceof Error?l.message:"Failed to decode Path payload"],pathLength:0,pathHashes:[],extraType:0,extraData:""}}}}return Bo.PathPayloadDecoder=r,Bo}var _o={},Sg;function _q(){if(Sg)return _o;Sg=1,Object.defineProperty(_o,"__esModule",{value:!0}),_o.TextMessagePayloadDecoder=void 0;const a=ua(),o=Ii();class r{static decode(c,l){try{if(c.length<4){const k={type:a.PayloadType.TextMessage,version:a.PayloadVersion.Version1,isValid:!1,errors:["TextMessage payload too short (minimum 4 bytes: dest + source + MAC)"],destinationHash:"",sourceHash:"",cipherMac:"",ciphertext:"",ciphertextLength:0};return l!=null&&l.includeSegments&&(k.segments=[{name:"Invalid TextMessage Data",description:"TextMessage payload too short (minimum 4 bytes required)",startByte:l.segmentOffset||0,endByte:(l.segmentOffset||0)+c.length-1,value:(0,o.bytesToHex)(c)}]),k}const m=[],u=(l==null?void 0:l.segmentOffset)||0;let h=0;const d=(0,o.byteToHex)(c[h]);l!=null&&l.includeSegments&&m.push({name:"Destination Hash",description:"First byte of destination node public key",startByte:u+h,endByte:u+h,value:d}),h+=1;const g=(0,o.byteToHex)(c[h]);l!=null&&l.includeSegments&&m.push({name:"Source Hash",description:"First byte of source node public key",startByte:u+h,endByte:u+h,value:g}),h+=1;const y=(0,o.bytesToHex)(c.subarray(h,h+2));l!=null&&l.includeSegments&&m.push({name:"Cipher MAC",description:"MAC for encrypted data in next field",startByte:u+h,endByte:u+h+1,value:y}),h+=2;const f=(0,o.bytesToHex)(c.subarray(h));l!=null&&l.includeSegments&&c.length>h&&m.push({name:"Ciphertext",description:"Encrypted message data (timestamp + message text)",startByte:u+h,endByte:u+c.length-1,value:f});const w={type:a.PayloadType.TextMessage,version:a.PayloadVersion.Version1,isValid:!0,destinationHash:d,sourceHash:g,cipherMac:y,ciphertext:f,ciphertextLength:c.length-4};return l!=null&&l.includeSegments&&(w.segments=m),w}catch(m){return{type:a.PayloadType.TextMessage,version:a.PayloadVersion.Version1,i Line truncated
// SHA256 round constants
const K: array<u32, 64> = array<u32, 64>(
0x428a2f98u, 0x71374491u, 0xb5c0fbcfu, 0xe9b5dba5u, 0x3956c25bu, 0x59f111f1u, 0x923f82a4u, 0xab1c5ed5u,
@@ -527,11 +527,11 @@ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
process_candidate(name_idx);
}
}
`}async init(){if(!navigator.gpu)return console.warn("WebGPU not supported"),!1;try{const o=await navigator.gpu.requestAdapter();if(!o)return console.warn("No GPU adapter found"),!1;this.device=await o.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 c=0;c<2;c++)this.matchCountReadBuffers[c]=this.device.createBuffer({size:4,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),this.matchIndicesReadBuffers[c]=this.device.createBuffer({size:1024*4,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST});const r=this.device.createShaderModule({code:this.shaderCode}),s=this.device.createPipelineLayout({bindGroupLayouts:[this.bindGroupLayout]});return this.pipeline=this.device.createComputePipeline({layout:s,compute:{module:r,entryPoint:"main"}}),!0}catch(o){return console.error("WebGPU initialization failed:",o),!1}}isAvailable(){return this.device!==null&&this.pipeline!==null}indexToRoomName(o,r){return Kn(r,o)}countNamesForLength(o){return To(o)}async runBatch(o,r,s,c,l,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 u=this.currentReadBufferIndex;this.currentReadBufferIndex=1-this.currentReadBufferIndex;const h=this.matchCountReadBuffers[u],d=this.matchIndicesReadBuffers[u],g=l&&m?1:0;let y,f=0,w=0;if(g){const C=new Uint8Array(l.length/2);for(let N=0;N<C.length;N++)C[N]=parseInt(l.substr(N*2,2),16);f=C.length*8;const D=Math.ceil(C.length/4)*4,F=new Uint8Array(D);F.set(C),y=new Uint32Array(D/4);for(let N=0;N<y.length;N++)y[N]=F[N*4]<<24|F[N*4+1]<<16|F[N*4+2]<<8|F[N*4+3];const R=parseInt(m.substr(0,2),16),M=parseInt(m.substr(2,2),16);w=R<<24|M<<16}else y=new Uint32Array([0]);const k=Math.max(y.length*4,4);(!this.ciphertextBuffer||this.ciphertextBufferSize<k)&&(this.ciphertextBuffer&&this.ciphertextBuffer.destroy(),this.ciphertextBuffer=this.device.createBuffer({size:k,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),this.ciphertextBufferSize=k,this.bindGroupDirty=!0);const z=new Uint32Array([o,s,r,c,w,y.length,f,g]);this.device.queue.writeBuffer(this.paramsBuffer,0,z),this.device.queue.writeBuffer(this.ciphertextBuffer,0,y),this.device.queue.writeBuffer(this.matchCountBuffer,0,fl.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 v=this.device.createCommandEncoder(),j=v.beginComputePass();j.setPipeline(this.pipeline),j.setBindGroup(0,this.bindGroup),j.dispatchWorkgroups(Math.ceil(c/(256*16))),j.end(),v.copyBufferToBuffer(this.matchCountBuffer,0,h,0,4),v.copyBufferToBuffer(this.matchIndicesBuffer,0,d,0,1024*4),this.device.queue.submit([v.finish()]),await h.mapAsync(GPUMapMode.READ);const x=new Uint32Array(h.getMappedRange())[0];h.unmap();const _=[];if(x>0){await d.mapAsync(GPUMapMode.READ);const C=new Uint32Array(d.getMappedRange());for(let D=0;D<Math.min(x,1024);D++)_.push(C[D]);d.unmap()}return _}destroy(){var o,r,s,c,l,m,u,h;(o=this.paramsBuffer)==null||o.destroy(),(r=this.matchCountBuffer)==null||r.destroy(),(s=this.matchIndicesBuffer)==null||s.destroy(),(c=this.ciphertextBuffer)==null||c.destroy(),(l=this.matchCountReadBuffers[0])==null||l.destroy(),(m=this.matchCountReadBuffers[1])==null||m.destroy(),(u=this.matchIndicesReadBuffers[0])==null||u.destroy(),(h=this.matchIndicesReadBuffers[1])==null||h.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}}fl.ZERO_DATA=new Uint32Array([0]);function Qq(){return typeof navigator<"u"&&"gpu"in navigator}class Hg{runBatch(o,r,s,c,l,m){const u=[],h=o.toString(16).padStart(2,"0") Line truncated
`).map(l=>l.trim().toLowerCase()).filter(l=>l.length>0);this.wordlist=c.filter(Vg)}setWordlist(o){this.wordlist=o.map(r=>r.trim().toLowerCase()).filter(Vg)}abort(){this.abortFlag=!0}isGpuAvailable(){return Qq()}async decodePacket(o){var s;const r=o.trim().replace(/\s+/g,"").replace(/^0x/i,"");if(!r||!/^[0-9a-fA-F]+$/.test(r))return null;try{const l=(s=(await Mg.MeshCorePacketDecoder.decodeWithVerification(r,{})).payload)==null?void 0:s.decoded;return!(l!=null&&l.channelHash)||!(l!=null&&l.ciphertext)||!(l!=null&&l.cipherMac)?null:{channelHash:l.channelHash,ciphertext:l.ciphertext,cipherMac:l.cipherMac,isGroupText:!0}}catch{return null}}async crack(o,r,s){this.abortFlag=!1,this.useTimestampFilter=(r==null?void 0:r.useTimestampFilter)??!0,this.useUtf8Filter=(r==null?void 0:r.useUtf8Filter)??!0,this.validSeconds=(r==null?void 0:r.validSeconds)??Tu,this.useCpu=(r==null?void 0:r.forceCpu)??!1;const c=(r==null?void 0:r.maxLength)??8,l=(r==null?void 0:r.startingLength)??1,m=(r==null?void 0:r.useDictionary)??!0,u=(r==null?void 0:r.startFromType)??"bruteforce",h=o.toLowerCase(),d=await this.decodePacket(h);if(!d)return{found:!1,error:"Invalid packet or not a GroupText packet"};const{channelHash:g,ciphertext:y,cipherMac:f}=d,w=parseInt(g,16);this.useCpu?this.cpuInstance||(this.cpuInstance=new Hg):this.gpuInstance||(this.gpuInstance=new fl,await this.gpuInstance.init()||(this.useCpu=!0,this.cpuInstance=new Hg));const k=performance.now();let z=0,v=performance.now(),j=l,A=0,x=0,_=!1;if(r!=null&&r.startFrom){const H=r.startFrom.toLowerCase();if(u==="dictionary"){const K=this.wordlist.indexOf(H);K>=0&&(x=K+1)}else{_=!0;const K=Wq(H);K&&(j=Math.max(l,K.length),A=K.index+1,A>=To(j)&&(j++,A=0))}}let C=0;m&&!_&&this.wordlist.length>0&&(C+=this.wordlist.length-x);for(let H=j;H<=c;H++)C+=To(H);C-=A;const D=(H,K,ie)=>{if(!s)return;const ae=(performance.now()-k)/1e3,W=ae>0?Math.round(z/ae):0,ne=C-z,X=W>0?ne/W:0;s({checked:z,total:C,percent:C>0?Math.min(100,z/C*100):0,rateKeysPerSec:W,etaSeconds:X,elapsedSeconds:ae,currentLength:K,currentPosition:ie,phase:H})},F=H=>{if(!nf(y,f,H))return{valid:!1};const K=Mg.ChannelCrypto.decryptGroupTextMessage(y,f,H);return!K.success||!K.data?{valid:!1}:this.useTimestampFilter&&!$q(K.data.timestamp,this.validSeconds)?{valid:!1}:this.useUtf8Filter&&!Gq(K.data.message)?{valid:!1}:{valid:!0,message:K.data.message}};if(!_&&x===0&&j===l&&A===0){D("public-key",0,Ru);const H=Nu(Yt);if(g===H){const K=F(Yt);if(K.valid)return{found:!0,roomName:Ru,key:Yt,decryptedMessage:K.message}}}if(m&&!_&&this.wordlist.length>0)for(let H=x;H<this.wordlist.length;H++){if(this.abortFlag)return{found:!1,aborted:!0,resumeFrom:this.wordlist[H],resumeType:"dictionary"};const K=this.wordlist[H],ie=Pu("#"+K),Z=Nu(ie);if(parseInt(Z,16)===w){const W=F(ie);if(W.valid)return{found:!0,roomName:K,key:ie,decryptedMessage:W.message,resumeFrom:K,resumeType:"dictionary"}}z++;const ae=performance.now();ae-v>=200&&(D("wordlist",K.length,K),v=ae,await new Promise(W=>setTimeout(W,0)))}const R=this.useCpu?1024:32768,M=(r==null?void 0:r.gpuDispatchMs)??1e3;let N=R,T=!1;for(let H=j;H<=c;H++){if(this.abortFlag)return{found:!1,aborted:!0,resumeFrom:Kn(H,0)||void 0,resumeType:"bruteforce"};const K=To(H);let ie=H===j?A:0;for(;ie<K;){if(this.abortFlag)return{found:!1,aborted:!0,resumeFrom:Kn(H,ie)||void 0,resumeType:"bruteforce"};const Z=Math.min(N,K-ie),ae=performance.now();let W;this.useCpu?W=this.cpuInstance.runBatch(w,H,ie,Z,y,f):W=await this.gpuInstance.runBatch(w,H,ie,Z,y,f);const ne=performance.now()-ae;if(z+=Z,!this.useCpu&&!T&&Z>=R&&ne>0){const q=M/ne,I=Math.round(Z*q),L=Math.pow(2,Math.round(Math.log2(Math.max(R,I))));N=Math.max(R,L),T=!0}for(const q of W){const I=Kn(H,q);if(!I)continue;const L=Pu("#"+I),$=F(L);if($.valid)return{found:!0,roomName:I,key:L,decryptedMessage:$.message,resumeFrom:I,resumeType:"bruteforce"}}ie+=Z;const X=performance.now();if(X-v>=200){const q=Kn(H,Math.min(ie,K-1))||"";D("bruteforce",H,q),v=X,await new Promise(I=>setTimeout(I,0))}}}return{found:!1,resumeFrom:Kn(c,To(c)-1)||void 0,resumeType:"bruteforce"}}destroy(){this.gpuInstance&&(this.gpuInstance.destroy(),this.gpuInstance=null),this.cpuInstance&&(this.cpuInstance.destroy(),this.cpuInstance=null)}}const Jq=["2","1080","10-point","10th","11-point","12-point","16-point","18-point","1st","20-point","2d","2nd","30-30","3d","3-d","3m","3rd","48-point","4-d","4gl","4h","4th","5-point","5-t","5th","6-point","6th","7-point","7th","8-point","8th","9-point","9th","a","a1","a-1","a4","a5","aa","aaa","aaaa","aaaaaa","aaal","aaas","aaberg","aachen","aae","aaee","aaf","aag","aah","aahed","aahing","aahs","aaii","aal","aalborg","aalesund","aalii","aaliis","aals","aalst","aalto","aam","aamsi","aandahl","a-and-r","aani","aao","aap","aapss","aaqbiye","aar","aara","aarau","aarc","aardvark","aardvarks","aardwolf","aardwolves","aaren","aargau","aargh","aarhus","aarika","aaron","aaronic","aaronical","aaronite","aaronitic","aaronsburg","aaronson","aarp","aarrgh","aarrghh","aaru","a Line truncated
`}async init(){if(!navigator.gpu)return console.warn("WebGPU not supported"),!1;try{const o=await navigator.gpu.requestAdapter();if(!o)return console.warn("No GPU adapter found"),!1;this.device=await o.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 c=0;c<2;c++)this.matchCountReadBuffers[c]=this.device.createBuffer({size:4,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),this.matchIndicesReadBuffers[c]=this.device.createBuffer({size:1024*4,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST});const r=this.device.createShaderModule({code:this.shaderCode}),s=this.device.createPipelineLayout({bindGroupLayouts:[this.bindGroupLayout]});return this.pipeline=this.device.createComputePipeline({layout:s,compute:{module:r,entryPoint:"main"}}),!0}catch(o){return console.error("WebGPU initialization failed:",o),!1}}isAvailable(){return this.device!==null&&this.pipeline!==null}indexToRoomName(o,r){return Kn(r,o)}countNamesForLength(o){return To(o)}async runBatch(o,r,s,c,l,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 u=this.currentReadBufferIndex;this.currentReadBufferIndex=1-this.currentReadBufferIndex;const h=this.matchCountReadBuffers[u],d=this.matchIndicesReadBuffers[u],g=l&&m?1:0;let y,f=0,w=0;if(g){const C=new Uint8Array(l.length/2);for(let P=0;P<C.length;P++)C[P]=parseInt(l.substr(P*2,2),16);f=C.length*8;const D=Math.ceil(C.length/4)*4,R=new Uint8Array(D);R.set(C),y=new Uint32Array(D/4);for(let P=0;P<y.length;P++)y[P]=R[P*4]<<24|R[P*4+1]<<16|R[P*4+2]<<8|R[P*4+3];const F=parseInt(m.substr(0,2),16),M=parseInt(m.substr(2,2),16);w=F<<24|M<<16}else y=new Uint32Array([0]);const k=Math.max(y.length*4,4);(!this.ciphertextBuffer||this.ciphertextBufferSize<k)&&(this.ciphertextBuffer&&this.ciphertextBuffer.destroy(),this.ciphertextBuffer=this.device.createBuffer({size:k,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),this.ciphertextBufferSize=k,this.bindGroupDirty=!0);const z=new Uint32Array([o,s,r,c,w,y.length,f,g]);this.device.queue.writeBuffer(this.paramsBuffer,0,z),this.device.queue.writeBuffer(this.ciphertextBuffer,0,y),this.device.queue.writeBuffer(this.matchCountBuffer,0,yl.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 v=this.device.createCommandEncoder(),j=v.beginComputePass();j.setPipeline(this.pipeline),j.setBindGroup(0,this.bindGroup),j.dispatchWorkgroups(Math.ceil(c/(256*16))),j.end(),v.copyBufferToBuffer(this.matchCountBuffer,0,h,0,4),v.copyBufferToBuffer(this.matchIndicesBuffer,0,d,0,1024*4),this.device.queue.submit([v.finish()]),await h.mapAsync(GPUMapMode.READ);const x=new Uint32Array(h.getMappedRange())[0];h.unmap();const _=[];if(x>0){await d.mapAsync(GPUMapMode.READ);const C=new Uint32Array(d.getMappedRange());for(let D=0;D<Math.min(x,1024);D++)_.push(C[D]);d.unmap()}return _}destroy(){var o,r,s,c,l,m,u,h;(o=this.paramsBuffer)==null||o.destroy(),(r=this.matchCountBuffer)==null||r.destroy(),(s=this.matchIndicesBuffer)==null||s.destroy(),(c=this.ciphertextBuffer)==null||c.destroy(),(l=this.matchCountReadBuffers[0])==null||l.destroy(),(m=this.matchCountReadBuffers[1])==null||m.destroy(),(u=this.matchIndicesReadBuffers[0])==null||u.destroy(),(h=this.matchIndicesReadBuffers[1])==null||h.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}}yl.ZERO_DATA=new Uint32Array([0]);function Wq(){return typeof navigator<"u"&&"gpu"in navigator}class Mg{runBatch(o,r,s,c,l,m){const u=[],h=o.toString(16).padStart(2,"0") Line truncated
`).map(l=>l.trim().toLowerCase()).filter(l=>l.length>0);this.wordlist=c.filter(Og)}setWordlist(o){this.wordlist=o.map(r=>r.trim().toLowerCase()).filter(Og)}abort(){this.abortFlag=!0}isGpuAvailable(){return Wq()}async decodePacket(o){var s;const r=o.trim().replace(/\s+/g,"").replace(/^0x/i,"");if(!r||!/^[0-9a-fA-F]+$/.test(r))return null;try{const l=(s=(await Pg.MeshCorePacketDecoder.decodeWithVerification(r,{})).payload)==null?void 0:s.decoded;return!(l!=null&&l.channelHash)||!(l!=null&&l.ciphertext)||!(l!=null&&l.cipherMac)?null:{channelHash:l.channelHash,ciphertext:l.ciphertext,cipherMac:l.cipherMac,isGroupText:!0}}catch{return null}}async crack(o,r,s){this.abortFlag=!1,this.useTimestampFilter=(r==null?void 0:r.useTimestampFilter)??!0,this.useUtf8Filter=(r==null?void 0:r.useUtf8Filter)??!0,this.validSeconds=(r==null?void 0:r.validSeconds)??Du,this.useCpu=(r==null?void 0:r.forceCpu)??!1;const c=(r==null?void 0:r.maxLength)??8,l=(r==null?void 0:r.startingLength)??1,m=(r==null?void 0:r.useDictionary)??!0,u=(r==null?void 0:r.startFromType)??"bruteforce",h=o.toLowerCase(),d=await this.decodePacket(h);if(!d)return{found:!1,error:"Invalid packet or not a GroupText packet"};const{channelHash:g,ciphertext:y,cipherMac:f}=d,w=parseInt(g,16);this.useCpu?this.cpuInstance||(this.cpuInstance=new Mg):this.gpuInstance||(this.gpuInstance=new yl,await this.gpuInstance.init()||(this.useCpu=!0,this.cpuInstance=new Mg));const k=performance.now();let z=0,v=performance.now(),j=l,q=0,x=0,_=!1;if(r!=null&&r.startFrom){const H=r.startFrom.toLowerCase();if(u==="dictionary"){const K=this.wordlist.indexOf(H);K>=0&&(x=K+1)}else{_=!0;const K=Hq(H);K&&(j=Math.max(l,K.length),q=K.index+1,q>=To(j)&&(j++,q=0))}}let C=0;m&&!_&&this.wordlist.length>0&&(C+=this.wordlist.length-x);for(let H=j;H<=c;H++)C+=To(H);C-=q;const D=(H,K,ie)=>{if(!s)return;const ae=(performance.now()-k)/1e3,W=ae>0?Math.round(z/ae):0,ne=C-z,X=W>0?ne/W:0;s({checked:z,total:C,percent:C>0?Math.min(100,z/C*100):0,rateKeysPerSec:W,etaSeconds:X,elapsedSeconds:ae,currentLength:K,currentPosition:ie,phase:H})},R=H=>{if(!Jb(y,f,H))return{valid:!1};const K=Pg.ChannelCrypto.decryptGroupTextMessage(y,f,H);return!K.success||!K.data?{valid:!1}:this.useTimestampFilter&&!Vq(K.data.timestamp,this.validSeconds)?{valid:!1}:this.useUtf8Filter&&!Uq(K.data.message)?{valid:!1}:{valid:!0,message:K.data.message}};if(!_&&x===0&&j===l&&q===0){D("public-key",0,_u);const H=Ru(Kt);if(g===H){const K=R(Kt);if(K.valid)return{found:!0,roomName:_u,key:Kt,decryptedMessage:K.message}}}if(m&&!_&&this.wordlist.length>0)for(let H=x;H<this.wordlist.length;H++){if(this.abortFlag)return{found:!1,aborted:!0,resumeFrom:this.wordlist[H],resumeType:"dictionary"};const K=this.wordlist[H],ie=Fu("#"+K),Z=Ru(ie);if(parseInt(Z,16)===w){const W=R(ie);if(W.valid)return{found:!0,roomName:K,key:ie,decryptedMessage:W.message,resumeFrom:K,resumeType:"dictionary"}}z++;const ae=performance.now();ae-v>=200&&(D("wordlist",K.length,K),v=ae,await new Promise(W=>setTimeout(W,0)))}const F=this.useCpu?1024:32768,M=(r==null?void 0:r.gpuDispatchMs)??1e3;let P=F,T=!1;for(let H=j;H<=c;H++){if(this.abortFlag)return{found:!1,aborted:!0,resumeFrom:Kn(H,0)||void 0,resumeType:"bruteforce"};const K=To(H);let ie=H===j?q:0;for(;ie<K;){if(this.abortFlag)return{found:!1,aborted:!0,resumeFrom:Kn(H,ie)||void 0,resumeType:"bruteforce"};const Z=Math.min(P,K-ie),ae=performance.now();let W;this.useCpu?W=this.cpuInstance.runBatch(w,H,ie,Z,y,f):W=await this.gpuInstance.runBatch(w,H,ie,Z,y,f);const ne=performance.now()-ae;if(z+=Z,!this.useCpu&&!T&&Z>=F&&ne>0){const A=M/ne,I=Math.round(Z*A),L=Math.pow(2,Math.round(Math.log2(Math.max(F,I))));P=Math.max(F,L),T=!0}for(const A of W){const I=Kn(H,A);if(!I)continue;const L=Fu("#"+I),$=R(L);if($.valid)return{found:!0,roomName:I,key:L,decryptedMessage:$.message,resumeFrom:I,resumeType:"bruteforce"}}ie+=Z;const X=performance.now();if(X-v>=200){const A=Kn(H,Math.min(ie,K-1))||"";D("bruteforce",H,A),v=X,await new Promise(I=>setTimeout(I,0))}}}return{found:!1,resumeFrom:Kn(c,To(c)-1)||void 0,resumeType:"bruteforce"}}destroy(){this.gpuInstance&&(this.gpuInstance.destroy(),this.gpuInstance=null),this.cpuInstance&&(this.cpuInstance.destroy(),this.cpuInstance=null)}}const Yq=["2","1080","10-point","10th","11-point","12-point","16-point","18-point","1st","20-point","2d","2nd","30-30","3d","3-d","3m","3rd","48-point","4-d","4gl","4h","4th","5-point","5-t","5th","6-point","6th","7-point","7th","8-point","8th","9-point","9th","a","a1","a-1","a4","a5","aa","aaa","aaaa","aaaaaa","aaal","aaas","aaberg","aachen","aae","aaee","aaf","aag","aah","aahed","aahing","aahs","aaii","aal","aalborg","aalesund","aalii","aaliis","aals","aalst","aalto","aam","aamsi","aandahl","a-and-r","aani","aao","aap","aapss","aaqbiye","aar","aara","aarau","aarc","aardvark","aardvarks","aardwolf","aardwolves","aaren","aargau","aargh","aarhus","aarika","aaron","aaronic","aaronical","aaronite","aaronitic","aaronsburg","aaronson","aarp","aarrgh","aarrghh","aaru","a 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(u=>(this.enabled=!0,u)).catch(u=>{throw this.enabled=!1,u})}disable(){s()?(this._wakeLock&&this._wakeLock.release(),this._wakeLock=null):r()?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 zu=c,zu}var aA=iA();const nA=Fr(aA);function rA(a){if(a.length<4)return null;try{const r=parseInt(a.slice(0,2),16)&3;let s=2;if(r===0||r===3){if(a.length<s+8)return null;s+=8}if(a.length<s+2)return null;const c=parseInt(a.slice(s,s+2),16);s+=2;const l=c*2;return a.length<s+l?null:(s+=l,a.slice(s))}catch{return null}}function oA({packets:a,channels:o,onChannelCreate:r,onRunningChange:s}){const[c,l]=E.useState(!1),[m,u]=E.useState(6),[h,d]=E.useState(!1),[g,y]=E.useState(!0),[f,w]=E.useState(!1),[k,z]=E.useState(null),[v,j]=E.useState(new Map),[A,x]=E.useState([]),[_,C]=E.useState(!1),[D,F]=E.useState(null),[R,M]=E.useState(null),[N,T]=E.useState(0),U=E.useRef(null),H=E.useRef(null),K=E.useRef(!1),ie=E.useRef(!1),Z=E.useRef(!1),ae=E.useRef(new Map),W=E.useRef(!1),ne=E.useRef(6),X=E.useRef(!0),q=E.useRef(!1),I=E.useRef(new Set),L=E.useRef(new Set);E.useEffect(()=>{const he=new Xq;U.current=he,F(he.isGpuAvailable());const Be=new nA;return H.current=Be,he.setWordlist(Jq),C(!0),()=>{he.destroy(),U.current=null,Be.disable(),H.current=null}},[]),E.useEffect(()=>{const he=()=>{Je.getUndecryptedPacketCount().then(({count:Ae})=>M(Ae)).catch(()=>M(null))};he();const Be=setInterval(he,3e4);return()=>clearInterval(Be)},[]);const $=new Set(o.map(he=>he.key.toUpperCase())),te=a.filter(he=>he.payload_type==="GROUP_TEXT"&&!he.decrypted);E.useEffect(()=>{let he=0;j(Be=>{const Ae=new Map(Be);let ji=!1;for(const ti of te)if(!Ae.has(ti.id)){const ei=rA(ti.data);if(ei&&L.current.has(ei)){he++;continue}ei&&L.current.add(ei),Ae.set(ti.id,{packet:ti,attempts:0,lastAttemptLength:0,status:"pending"}),ji=!0}return ji?(ae.current=Ae,Ae):Be}),he>0&&T(Be=>Be+he)},[te.length]),E.useEffect(()=>{ae.current=v},[v]),E.useEffect(()=>{W.current=h},[h]),E.useEffect(()=>{ne.current=m},[m]),E.useEffect(()=>{X.current=g},[g]),E.useEffect(()=>{q.current=f},[f]),E.useEffect(()=>{I.current=new Set(te.map(he=>he.id))},[te]),E.useEffect(()=>{s==null||s(c)},[c,s]);const pe=Array.from(v.values()).filter(he=>he.status==="pending").length,ge=Array.from(v.values()).filter(he=>he.status==="cracked").length,re=Array.from(v.values()).filter(he=>he.status==="failed").length,Se=E.useCallback(async()=>{if(Z.current||!U.current||!K.current)return;const he=ae.current;let Be=null,Ae=null;for(const[Ue,Te]of he.entries())if(Te.status==="pending"){Be=Te,Ae=Ue;break}if(!Be&&W.current){const Ue=Array.from(he.entries()).filter(([,Te])=>Te.status==="failed"&&Te.lastAttemptLength<10);Ue.length>0&&(Ue.sort((Te,ii)=>Te[1].lastAttemptLength-ii[1].lastAttemptLength),[Ae,Be]=Ue[0])}if(!Be||Ae===null){K.current&&setTimeout(()=>Se(),1e3);return}if(!I.current.has(Ae)){j(Ue=>{const Te=new Map(Ue);return Te.delete(Ae),Te}),K.current&&setTimeout(()=>Se(),10);return}Z.current=!0;const ji=ne.current,ti=Be.lastAttemptLength>0,ei=ti?Be.lastAttemptLength+1:ji;try{const Ue=await U.current.crack(Be.packet.data,{maxLength:ei,useTimestampFilter:!0,useUtf8Filter:!0,...q.current&&{gpuDispatchMs:1e4},...ti&&{useDictionary:!1,startingLength:ei}},Te=>{z(Te)});if(ie.current){ie.current=!1,Z.current=!1,z(null);return}if(Ue.found&&Ue.roomName&&Ue.key){j(Re=>{const Ne=new Map(Re),ri=Ne.get(Ae);return ri&&Ne.set(Ae,{...ri,status:"cracked",attempts:ri.attempts+1,lastAttemptLength:ei}),Ne});const Te={roomName:Ue.roomName,key:Ue.key,packetId:Ae,message:Ue.decryptedMessage||"",crackedAt:Date.now()};x(Re=>[...Re,Te]);const ii=Ue.key.toUpperCase();if(!$.has(ii))try{const Re="#"+Ue.roomName;await r(Re,Ue.key),X.current&&await Je.decryptHistoricalPackets({key_type:"channel",channel_name:Re})}catch(Re){console.error("Failed to create channel or decrypt historical:",Re)}}else j(Te=>{const ii=new Map(Te),Re=ii.get(Ae);return Re&&ii.set(Ae,{...Re,status:"failed",attempts:Re.attempts+1,lastAttemptLength:ei}),ii})}catch(Ue){console.error("Cracking error:",Ue),j(Te=>{const ii=new Map(Te),Re=ii.get(Ae);return Re&&ii.set(Ae,{...Re,status:"failed",attempts:Re.attempts+1,lastAttemptLength:ei}),ii})}Z.current=!1,z(null),K.current&&setTimeout(()=>Se(),100)},[$,r]),Me=()=>{var he;if(!D){alert("WebGPU is not available in your browser. Please use Chrome 113+ or Edge 113+.");return}l(!0),K.current=!0,ie.current=!1,(he=H.current)==null||he.enable(),Se()},pi=()=>{var he,Be;l(!1),K.current=!1,ie.current=!0,(he=U.current)==null||he.abort(),(Be=H.current)==null||Be.disable()};return B.jsxs("div",{className:"flex flex-col h-full p-3 gap-3 bg-background border-t border-border",children:[B.jsxs("p",{className:"text-xs text-muted-foreground leading-relaxed",children:["This will attempt to dictionary attack, then brute force GroupText packets as they arrive, testing room names up to the specified length.",B.jsx("strong",{children:" Retry failed at n+1"})," will let the cracker return to the failed queue and pick up messages it couldn't crack, attempting them at one longer length.",B.jsx("strong",{children:" Decrypt Line truncated
`),window.clearInterval(this.noSleepTimer),this.noSleepTimer=null):this.noSleepVideo.pause(),this.enabled=!1}}return ku=c,ku}var Jq=Xq();const eA=Fr(Jq);function iA(a){if(a.length<4)return null;try{const r=parseInt(a.slice(0,2),16)&3;let s=2;if(r===0||r===3){if(a.length<s+8)return null;s+=8}if(a.length<s+2)return null;const c=parseInt(a.slice(s,s+2),16);s+=2;const l=c*2;return a.length<s+l?null:(s+=l,a.slice(s))}catch{return null}}function aA({packets:a,channels:o,onChannelCreate:r,onRunningChange:s}){const[c,l]=E.useState(!1),[m,u]=E.useState(6),[h,d]=E.useState(!1),[g,y]=E.useState(!0),[f,w]=E.useState(!1),[k,z]=E.useState(null),[v,j]=E.useState(new Map),[q,x]=E.useState([]),[_,C]=E.useState(!1),[D,R]=E.useState(null),[F,M]=E.useState(null),[P,T]=E.useState(0),U=E.useRef(null),H=E.useRef(null),K=E.useRef(!1),ie=E.useRef(!1),Z=E.useRef(!1),ae=E.useRef(new Map),W=E.useRef(!1),ne=E.useRef(6),X=E.useRef(!0),A=E.useRef(!1),I=E.useRef(new Set),L=E.useRef(new Set);E.useEffect(()=>{const he=new Kq;U.current=he,R(he.isGpuAvailable());const Be=new eA;return H.current=Be,he.setWordlist(Yq),C(!0),()=>{he.destroy(),U.current=null,Be.disable(),H.current=null}},[]),E.useEffect(()=>{const he=()=>{We.getUndecryptedPacketCount().then(({count:Ae})=>M(Ae)).catch(()=>M(null))};he();const Be=setInterval(he,3e4);return()=>clearInterval(Be)},[]);const $=new Set(o.map(he=>he.key.toUpperCase())),te=a.filter(he=>he.payload_type==="GROUP_TEXT"&&!he.decrypted);E.useEffect(()=>{let he=0;j(Be=>{const Ae=new Map(Be);let ji=!1;for(const ti of te)if(!Ae.has(ti.id)){const ii=iA(ti.data);if(ii&&L.current.has(ii)){he++;continue}ii&&L.current.add(ii),Ae.set(ti.id,{packet:ti,attempts:0,lastAttemptLength:0,status:"pending"}),ji=!0}return ji?(ae.current=Ae,Ae):Be}),he>0&&T(Be=>Be+he)},[te.length]),E.useEffect(()=>{ae.current=v},[v]),E.useEffect(()=>{W.current=h},[h]),E.useEffect(()=>{ne.current=m},[m]),E.useEffect(()=>{X.current=g},[g]),E.useEffect(()=>{A.current=f},[f]),E.useEffect(()=>{I.current=new Set(te.map(he=>he.id))},[te]),E.useEffect(()=>{s==null||s(c)},[c,s]);const pe=Array.from(v.values()).filter(he=>he.status==="pending").length,ge=Array.from(v.values()).filter(he=>he.status==="cracked").length,re=Array.from(v.values()).filter(he=>he.status==="failed").length,Se=E.useCallback(async()=>{if(Z.current||!U.current||!K.current)return;const he=ae.current;let Be=null,Ae=null;for(const[Ue,Te]of he.entries())if(Te.status==="pending"){Be=Te,Ae=Ue;break}if(!Be&&W.current){const Ue=Array.from(he.entries()).filter(([,Te])=>Te.status==="failed"&&Te.lastAttemptLength<10);Ue.length>0&&(Ue.sort((Te,ai)=>Te[1].lastAttemptLength-ai[1].lastAttemptLength),[Ae,Be]=Ue[0])}if(!Be||Ae===null){K.current&&setTimeout(()=>Se(),1e3);return}if(!I.current.has(Ae)){j(Ue=>{const Te=new Map(Ue);return Te.delete(Ae),Te}),K.current&&setTimeout(()=>Se(),10);return}Z.current=!0;const ji=ne.current,ti=Be.lastAttemptLength>0,ii=ti?Be.lastAttemptLength+1:ji;try{const Ue=await U.current.crack(Be.packet.data,{maxLength:ii,useTimestampFilter:!0,useUtf8Filter:!0,...A.current&&{gpuDispatchMs:1e4},...ti&&{useDictionary:!1,startingLength:ii}},Te=>{z(Te)});if(ie.current){ie.current=!1,Z.current=!1,z(null);return}if(Ue.found&&Ue.roomName&&Ue.key){j(Re=>{const Ne=new Map(Re),ri=Ne.get(Ae);return ri&&Ne.set(Ae,{...ri,status:"cracked",attempts:ri.attempts+1,lastAttemptLength:ii}),Ne});const Te={roomName:Ue.roomName,key:Ue.key,packetId:Ae,message:Ue.decryptedMessage||"",crackedAt:Date.now()};x(Re=>[...Re,Te]);const ai=Ue.key.toUpperCase();if(!$.has(ai))try{const Re="#"+Ue.roomName;await r(Re,Ue.key),X.current&&await We.decryptHistoricalPackets({key_type:"channel",channel_name:Re})}catch(Re){console.error("Failed to create channel or decrypt historical:",Re)}}else j(Te=>{const ai=new Map(Te),Re=ai.get(Ae);return Re&&ai.set(Ae,{...Re,status:"failed",attempts:Re.attempts+1,lastAttemptLength:ii}),ai})}catch(Ue){console.error("Cracking error:",Ue),j(Te=>{const ai=new Map(Te),Re=ai.get(Ae);return Re&&ai.set(Ae,{...Re,status:"failed",attempts:Re.attempts+1,lastAttemptLength:ii}),ai})}Z.current=!1,z(null),K.current&&setTimeout(()=>Se(),100)},[$,r]),Me=()=>{var he;if(!D){alert("WebGPU is not available in your browser. Please use Chrome 113+ or Edge 113+.");return}l(!0),K.current=!0,ie.current=!1,(he=H.current)==null||he.enable(),Se()},pi=()=>{var he,Be;l(!1),K.current=!1,ie.current=!0,(he=U.current)==null||he.abort(),(Be=H.current)==null||Be.disable()};return B.jsxs("div",{className:"flex flex-col h-full p-3 gap-3 bg-background border-t border-border",children:[B.jsxs("p",{className:"text-xs text-muted-foreground leading-relaxed",children:["This will attempt to dictionary attack, then brute force GroupText packets as they arrive, testing room names up to the specified length.",B.jsx("strong",{children:" Retry failed at n+1"})," will let the cracker return to the failed queue and pick up messages it couldn't crack, attempting them at one longer length.",B.jsx("strong",{children:" Decrypt Line truncated
+1 -1
View File
@@ -13,7 +13,7 @@
<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-6T32T4ZI.js"></script>
<script type="module" crossorigin src="/assets/index-Cp9RQ4Uj.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DaLCXB8p.css">
</head>
<body>
+1
View File
@@ -393,6 +393,7 @@ export function App() {
lon: null,
last_seen: null,
on_radio: false,
last_read_at: null,
};
setContacts((prev) => [...prev, newContact]);
+14
View File
@@ -82,6 +82,10 @@ export const api = {
fetchJson<{ status: string }>(`/contacts/${publicKey}`, {
method: 'DELETE',
}),
markContactRead: (publicKey: string) =>
fetchJson<{ status: string; public_key: string }>(`/contacts/${publicKey}/mark-read`, {
method: 'POST',
}),
requestTelemetry: (publicKey: string, password: string) =>
fetchJson<TelemetryResponse>(`/contacts/${publicKey}/telemetry`, {
method: 'POST',
@@ -105,6 +109,10 @@ export const api = {
fetchJson<{ synced: number }>('/channels/sync', { method: 'POST' }),
deleteChannel: (key: string) =>
fetchJson<{ status: string }>(`/channels/${key}`, { method: 'DELETE' }),
markChannelRead: (key: string) =>
fetchJson<{ status: string; key: string }>(`/channels/${key}/mark-read`, {
method: 'POST',
}),
// Messages
getMessages: (params?: {
@@ -157,6 +165,12 @@ export const api = {
body: JSON.stringify(params),
}),
// Read State
markAllRead: () =>
fetchJson<{ status: string; timestamp: number }>('/read-state/mark-all-read', {
method: 'POST',
}),
// App Settings
getSettings: () => fetchJson<AppSettings>('/settings'),
updateSettings: (settings: AppSettingsUpdate) =>
+41 -26
View File
@@ -2,9 +2,7 @@ import { useState, useCallback, useEffect, useRef } from 'react';
import { api } from '../api';
import {
getLastMessageTimes,
getLastReadTimes,
setLastMessageTime,
setLastReadTime,
getStateKey,
type ConversationTimes,
} from '../utils/conversationState';
@@ -32,6 +30,7 @@ export function useUnreadCounts(
const fetchedContacts = useRef<Set<string>>(new Set());
// Fetch messages and count unreads for new channels/contacts
// Uses server-side last_read_at for consistent read state across devices
useEffect(() => {
const newChannels = channels.filter(c => !fetchedChannels.current.has(c.key));
const newContacts = contacts.filter(c => c.public_key && !fetchedContacts.current.has(c.public_key));
@@ -52,16 +51,16 @@ export function useUnreadCounts(
try {
const bulkMessages = await api.getMessagesBulk(conversations, 100);
const currentReadTimes = getLastReadTimes();
const newUnreadCounts: Record<string, number> = {};
const newLastMessageTimes: Record<string, number> = {};
// Process channel messages
// Process channel messages - use server-side last_read_at
for (const channel of newChannels) {
const msgs = bulkMessages[`CHAN:${channel.key}`] || [];
if (msgs.length > 0) {
const key = getStateKey('channel', channel.key);
const lastRead = currentReadTimes[key] || 0;
// Use server-side last_read_at, fallback to 0 if never read
const lastRead = channel.last_read_at || 0;
const unreadCount = msgs.filter(m => !m.outgoing && m.received_at > lastRead).length;
if (unreadCount > 0) {
@@ -74,12 +73,13 @@ export function useUnreadCounts(
}
}
// Process contact messages
// Process contact messages - use server-side last_read_at
for (const contact of newContacts) {
const msgs = bulkMessages[`PRIV:${contact.public_key}`] || [];
if (msgs.length > 0) {
const key = getStateKey('contact', contact.public_key);
const lastRead = currentReadTimes[key] || 0;
// Use server-side last_read_at, fallback to 0 if never read
const lastRead = contact.last_read_at || 0;
const unreadCount = msgs.filter(m => !m.outgoing && m.received_at > lastRead).length;
if (unreadCount > 0) {
@@ -105,15 +105,15 @@ export function useUnreadCounts(
}, [channels, contacts]);
// Mark conversation as read when user views it
// Calls server API to persist read state across devices
useEffect(() => {
if (activeConversation && activeConversation.type !== 'raw') {
const key = getStateKey(
activeConversation.type as 'channel' | 'contact',
activeConversation.id
);
const now = Math.floor(Date.now() / 1000);
setLastReadTime(key, now);
// Update local state immediately for responsive UI
setUnreadCounts((prev) => {
if (prev[key]) {
const next = { ...prev };
@@ -122,6 +122,17 @@ export function useUnreadCounts(
}
return prev;
});
// Persist to server (fire-and-forget, errors logged but not blocking)
if (activeConversation.type === 'channel') {
api.markChannelRead(activeConversation.id).catch((err) => {
console.error('Failed to mark channel as read on server:', err);
});
} else if (activeConversation.type === 'contact') {
api.markContactRead(activeConversation.id).catch((err) => {
console.error('Failed to mark contact as read on server:', err);
});
}
}
}, [activeConversation]);
@@ -134,32 +145,25 @@ export function useUnreadCounts(
}, []);
// Mark all conversations as read
// Calls single bulk API endpoint to persist read state
const markAllRead = useCallback(() => {
const now = Math.floor(Date.now() / 1000);
for (const channel of channels) {
const key = getStateKey('channel', channel.key);
setLastReadTime(key, now);
}
for (const contact of contacts) {
if (contact.public_key) {
const key = getStateKey('contact', contact.public_key);
setLastReadTime(key, now);
}
}
// Update local state immediately
setUnreadCounts({});
}, [channels, contacts]);
// Persist to server with single bulk request
api.markAllRead().catch((err) => {
console.error('Failed to mark all as read on server:', err);
});
}, []);
// Mark a specific conversation as read
// Calls server API to persist read state across devices
const markConversationRead = useCallback((conv: Conversation) => {
if (conv.type === 'raw') return;
const key = getStateKey(conv.type as 'channel' | 'contact', conv.id);
const now = Math.floor(Date.now() / 1000);
setLastReadTime(key, now);
// Update local state immediately
setUnreadCounts((prev) => {
if (prev[key]) {
const next = { ...prev };
@@ -168,6 +172,17 @@ export function useUnreadCounts(
}
return prev;
});
// Persist to server (fire-and-forget)
if (conv.type === 'channel') {
api.markChannelRead(conv.id).catch((err) => {
console.error('Failed to mark channel as read on server:', err);
});
} else if (conv.type === 'contact') {
api.markContactRead(conv.id).catch((err) => {
console.error('Failed to mark contact as read on server:', err);
});
}
}, []);
// Track a new incoming message for unread counts
+2
View File
@@ -55,6 +55,7 @@ export interface Contact {
lon: number | null;
last_seen: number | null;
on_radio: boolean;
last_read_at: number | null;
}
export interface Channel {
@@ -62,6 +63,7 @@ export interface Channel {
name: string;
is_hashtag: boolean;
on_radio: boolean;
last_read_at: number | null;
}
export interface Message {
+6 -18
View File
@@ -1,17 +1,16 @@
/**
* localStorage utilities for tracking conversation read/message state.
* localStorage utilities for tracking conversation message times.
*
* Stores two maps:
* - lastMessageTime: when each conversation last received a message
* - lastReadTime: when the user last viewed each conversation
* Stores when each conversation last received a message, used for
* sorting conversations by recency in the sidebar.
*
* A conversation has unread messages if lastMessageTime > lastReadTime.
* Read state (last_read_at) is tracked server-side for consistency
* across devices - see useUnreadCounts hook.
*/
import { getPubkeyPrefix } from './pubkey';
const LAST_MESSAGE_KEY = 'remoteterm-lastMessageTime';
const LAST_READ_KEY = 'remoteterm-lastReadTime';
export type ConversationTimes = Record<string, number>;
@@ -36,10 +35,6 @@ export function getLastMessageTimes(): ConversationTimes {
return loadTimes(LAST_MESSAGE_KEY);
}
export function getLastReadTimes(): ConversationTimes {
return loadTimes(LAST_READ_KEY);
}
export function setLastMessageTime(stateKey: string, timestamp: number): ConversationTimes {
const times = loadTimes(LAST_MESSAGE_KEY);
// Only update if this is a newer message
@@ -50,15 +45,8 @@ export function setLastMessageTime(stateKey: string, timestamp: number): Convers
return times;
}
export function setLastReadTime(stateKey: string, timestamp: number): ConversationTimes {
const times = loadTimes(LAST_READ_KEY);
times[stateKey] = timestamp;
saveTimes(LAST_READ_KEY, times);
return times;
}
/**
* Generate a state tracking key for unread counts and message times.
* Generate a state tracking key for message times.
*
* This is NOT the same as Message.conversation_key (the database field).
* This creates prefixed keys for localStorage/state tracking:
+251
View File
@@ -185,6 +185,257 @@ class TestPacketsEndpoint:
assert response.json()["count"] == 42
class TestReadStateEndpoints:
"""Test read state tracking endpoints."""
@pytest.mark.asyncio
async def test_mark_contact_read_updates_timestamp(self):
"""Marking contact as read updates last_read_at in database."""
import aiosqlite
import time
from app.repository import ContactRepository
from app.database import db
# Use in-memory database for testing
conn = await aiosqlite.connect(":memory:")
conn.row_factory = aiosqlite.Row
# Create contacts table with last_read_at column
await conn.execute("""
CREATE TABLE contacts (
public_key TEXT PRIMARY KEY,
name TEXT,
type INTEGER DEFAULT 0,
flags INTEGER DEFAULT 0,
last_path TEXT,
last_path_len INTEGER DEFAULT -1,
last_advert INTEGER,
lat REAL,
lon REAL,
last_seen INTEGER,
on_radio INTEGER DEFAULT 0,
last_contacted INTEGER,
last_read_at INTEGER
)
""")
# Insert a test contact
await conn.execute(
"INSERT INTO contacts (public_key, name) VALUES (?, ?)",
("abc123def456789012345678901234567890123456789012345678901234", "TestContact")
)
await conn.commit()
original_conn = db._connection
db._connection = conn
try:
before_time = int(time.time())
# Update last_read_at
updated = await ContactRepository.update_last_read_at(
"abc123def456789012345678901234567890123456789012345678901234"
)
assert updated is True
# Verify the timestamp was set
contact = await ContactRepository.get_by_key(
"abc123def456789012345678901234567890123456789012345678901234"
)
assert contact is not None
assert contact.last_read_at is not None
assert contact.last_read_at >= before_time
finally:
db._connection = original_conn
await conn.close()
@pytest.mark.asyncio
async def test_mark_channel_read_updates_timestamp(self):
"""Marking channel as read updates last_read_at in database."""
import aiosqlite
import time
from app.repository import ChannelRepository
from app.database import db
# Use in-memory database for testing
conn = await aiosqlite.connect(":memory:")
conn.row_factory = aiosqlite.Row
# Create channels table with last_read_at column
await conn.execute("""
CREATE TABLE channels (
key TEXT PRIMARY KEY,
name TEXT NOT NULL,
is_hashtag INTEGER DEFAULT 0,
on_radio INTEGER DEFAULT 0,
last_read_at INTEGER
)
""")
# Insert a test channel
await conn.execute(
"INSERT INTO channels (key, name) VALUES (?, ?)",
("0123456789ABCDEF0123456789ABCDEF", "#testchannel")
)
await conn.commit()
original_conn = db._connection
db._connection = conn
try:
before_time = int(time.time())
# Update last_read_at
updated = await ChannelRepository.update_last_read_at(
"0123456789ABCDEF0123456789ABCDEF"
)
assert updated is True
# Verify the timestamp was set
channel = await ChannelRepository.get_by_key(
"0123456789ABCDEF0123456789ABCDEF"
)
assert channel is not None
assert channel.last_read_at is not None
assert channel.last_read_at >= before_time
finally:
db._connection = original_conn
await conn.close()
@pytest.mark.asyncio
async def test_mark_nonexistent_contact_returns_false(self):
"""Marking nonexistent contact returns False."""
import aiosqlite
from app.repository import ContactRepository
from app.database import db
# Use in-memory database for testing
conn = await aiosqlite.connect(":memory:")
conn.row_factory = aiosqlite.Row
await conn.execute("""
CREATE TABLE contacts (
public_key TEXT PRIMARY KEY,
name TEXT,
type INTEGER DEFAULT 0,
flags INTEGER DEFAULT 0,
last_path TEXT,
last_path_len INTEGER DEFAULT -1,
last_advert INTEGER,
lat REAL,
lon REAL,
last_seen INTEGER,
on_radio INTEGER DEFAULT 0,
last_contacted INTEGER,
last_read_at INTEGER
)
""")
await conn.commit()
original_conn = db._connection
db._connection = conn
try:
updated = await ContactRepository.update_last_read_at("nonexistent")
assert updated is False
finally:
db._connection = original_conn
await conn.close()
def test_mark_contact_read_endpoint_returns_404_for_missing(self):
"""Mark-read endpoint returns 404 for nonexistent contact."""
from fastapi.testclient import TestClient
with patch("app.repository.ContactRepository.get_by_key_or_prefix", new_callable=AsyncMock) as mock_get:
mock_get.return_value = None
from app.main import app
client = TestClient(app)
response = client.post("/api/contacts/nonexistent/mark-read")
assert response.status_code == 404
assert "not found" in response.json()["detail"].lower()
def test_mark_channel_read_endpoint_returns_404_for_missing(self):
"""Mark-read endpoint returns 404 for nonexistent channel."""
from fastapi.testclient import TestClient
with patch("app.repository.ChannelRepository.get_by_key", new_callable=AsyncMock) as mock_get:
mock_get.return_value = None
from app.main import app
client = TestClient(app)
response = client.post("/api/channels/NONEXISTENT/mark-read")
assert response.status_code == 404
assert "not found" in response.json()["detail"].lower()
@pytest.mark.asyncio
async def test_mark_all_read_updates_all_conversations(self):
"""Bulk mark-all-read updates all contacts and channels."""
import aiosqlite
import time
from app.database import db
conn = await aiosqlite.connect(":memory:")
conn.row_factory = aiosqlite.Row
# Create tables
await conn.execute("""
CREATE TABLE contacts (
public_key TEXT PRIMARY KEY,
name TEXT,
last_read_at INTEGER
)
""")
await conn.execute("""
CREATE TABLE channels (
key TEXT PRIMARY KEY,
name TEXT NOT NULL,
last_read_at INTEGER
)
""")
# Insert test data with NULL last_read_at
await conn.execute("INSERT INTO contacts (public_key, name) VALUES (?, ?)", ("contact1", "Alice"))
await conn.execute("INSERT INTO contacts (public_key, name) VALUES (?, ?)", ("contact2", "Bob"))
await conn.execute("INSERT INTO channels (key, name) VALUES (?, ?)", ("CHAN1", "#test1"))
await conn.execute("INSERT INTO channels (key, name) VALUES (?, ?)", ("CHAN2", "#test2"))
await conn.commit()
original_conn = db._connection
db._connection = conn
try:
before_time = int(time.time())
# Call the endpoint
from app.routers.read_state import mark_all_read
result = await mark_all_read()
assert result["status"] == "ok"
assert result["timestamp"] >= before_time
# Verify all contacts updated
cursor = await conn.execute("SELECT last_read_at FROM contacts")
rows = await cursor.fetchall()
for row in rows:
assert row["last_read_at"] >= before_time
# Verify all channels updated
cursor = await conn.execute("SELECT last_read_at FROM channels")
rows = await cursor.fetchall()
for row in rows:
assert row["last_read_at"] >= before_time
finally:
db._connection = original_conn
await conn.close()
class TestRawPacketRepository:
"""Test raw packet storage with deduplication."""
+221
View File
@@ -0,0 +1,221 @@
"""Tests for database migrations."""
import pytest
import aiosqlite
from app.migrations import get_version, set_version, run_migrations
class TestMigrationSystem:
"""Test the migration version tracking system."""
@pytest.mark.asyncio
async def test_get_version_returns_zero_for_new_db(self):
"""New database has user_version=0."""
conn = await aiosqlite.connect(":memory:")
try:
version = await get_version(conn)
assert version == 0
finally:
await conn.close()
@pytest.mark.asyncio
async def test_set_version_updates_pragma(self):
"""Setting version updates the user_version pragma."""
conn = await aiosqlite.connect(":memory:")
try:
await set_version(conn, 5)
version = await get_version(conn)
assert version == 5
finally:
await conn.close()
class TestMigration001:
"""Test migration 001: add last_read_at columns."""
@pytest.mark.asyncio
async def test_migration_adds_last_read_at_to_contacts(self):
"""Migration adds last_read_at column to contacts table."""
conn = await aiosqlite.connect(":memory:")
conn.row_factory = aiosqlite.Row
try:
# Create schema without last_read_at (simulating pre-migration state)
await conn.execute("""
CREATE TABLE contacts (
public_key TEXT PRIMARY KEY,
name TEXT,
type INTEGER DEFAULT 0,
flags INTEGER DEFAULT 0,
last_path TEXT,
last_path_len INTEGER DEFAULT -1,
last_advert INTEGER,
lat REAL,
lon REAL,
last_seen INTEGER,
on_radio INTEGER DEFAULT 0,
last_contacted INTEGER
)
""")
await conn.execute("""
CREATE TABLE channels (
key TEXT PRIMARY KEY,
name TEXT NOT NULL,
is_hashtag INTEGER DEFAULT 0,
on_radio INTEGER DEFAULT 0
)
""")
await conn.commit()
# Run migrations
applied = await run_migrations(conn)
assert applied == 1
assert await get_version(conn) == 1
# Verify columns exist by inserting and selecting
await conn.execute(
"INSERT INTO contacts (public_key, name, last_read_at) VALUES (?, ?, ?)",
("abc123", "Test", 12345)
)
await conn.execute(
"INSERT INTO channels (key, name, last_read_at) VALUES (?, ?, ?)",
("KEY123", "#test", 67890)
)
await conn.commit()
cursor = await conn.execute(
"SELECT last_read_at FROM contacts WHERE public_key = ?",
("abc123",)
)
row = await cursor.fetchone()
assert row["last_read_at"] == 12345
cursor = await conn.execute(
"SELECT last_read_at FROM channels WHERE key = ?",
("KEY123",)
)
row = await cursor.fetchone()
assert row["last_read_at"] == 67890
finally:
await conn.close()
@pytest.mark.asyncio
async def test_migration_is_idempotent(self):
"""Running migration multiple times is safe."""
conn = await aiosqlite.connect(":memory:")
conn.row_factory = aiosqlite.Row
try:
# Create schema without last_read_at
await conn.execute("""
CREATE TABLE contacts (
public_key TEXT PRIMARY KEY,
name TEXT
)
""")
await conn.execute("""
CREATE TABLE channels (
key TEXT PRIMARY KEY,
name TEXT NOT NULL
)
""")
await conn.commit()
# Run migrations twice
applied1 = await run_migrations(conn)
applied2 = await run_migrations(conn)
assert applied1 == 1
assert applied2 == 0 # No migrations on second run
assert await get_version(conn) == 1
finally:
await conn.close()
@pytest.mark.asyncio
async def test_migration_handles_column_already_exists(self):
"""Migration handles case where column already exists."""
conn = await aiosqlite.connect(":memory:")
conn.row_factory = aiosqlite.Row
try:
# Create schema with last_read_at already present
await conn.execute("""
CREATE TABLE contacts (
public_key TEXT PRIMARY KEY,
name TEXT,
last_read_at INTEGER
)
""")
await conn.execute("""
CREATE TABLE channels (
key TEXT PRIMARY KEY,
name TEXT NOT NULL,
last_read_at INTEGER
)
""")
await conn.commit()
# Run migrations - should not fail
applied = await run_migrations(conn)
# Still counts as applied (version incremented) but no error
assert applied == 1
assert await get_version(conn) == 1
finally:
await conn.close()
@pytest.mark.asyncio
async def test_existing_data_preserved_after_migration(self):
"""Migration preserves existing contact and channel data."""
conn = await aiosqlite.connect(":memory:")
conn.row_factory = aiosqlite.Row
try:
# Create schema and insert data before migration
await conn.execute("""
CREATE TABLE contacts (
public_key TEXT PRIMARY KEY,
name TEXT,
type INTEGER DEFAULT 0
)
""")
await conn.execute("""
CREATE TABLE channels (
key TEXT PRIMARY KEY,
name TEXT NOT NULL,
is_hashtag INTEGER DEFAULT 0
)
""")
await conn.execute(
"INSERT INTO contacts (public_key, name, type) VALUES (?, ?, ?)",
("existingkey", "ExistingContact", 1)
)
await conn.execute(
"INSERT INTO channels (key, name, is_hashtag) VALUES (?, ?, ?)",
("EXISTINGCHAN", "#existing", 1)
)
await conn.commit()
# Run migrations
await run_migrations(conn)
# Verify data is preserved
cursor = await conn.execute(
"SELECT public_key, name, type, last_read_at FROM contacts WHERE public_key = ?",
("existingkey",)
)
row = await cursor.fetchone()
assert row["public_key"] == "existingkey"
assert row["name"] == "ExistingContact"
assert row["type"] == 1
assert row["last_read_at"] is None # New column defaults to NULL
cursor = await conn.execute(
"SELECT key, name, is_hashtag, last_read_at FROM channels WHERE key = ?",
("EXISTINGCHAN",)
)
row = await cursor.fetchone()
assert row["key"] == "EXISTINGCHAN"
assert row["name"] == "#existing"
assert row["is_hashtag"] == 1
assert row["last_read_at"] is None
finally:
await conn.close()