@prismer/runtime 1.9.0-hotfix.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +288 -0
- package/dist/adapter-registry-EMZFKFYK.mjs +8 -0
- package/dist/adapter-registry-EMZFKFYK.mjs.map +1 -0
- package/dist/artifacts-uploader-N2HNBSTW.mjs +159 -0
- package/dist/artifacts-uploader-N2HNBSTW.mjs.map +1 -0
- package/dist/auto-register-M4YSPJS6.mjs +204 -0
- package/dist/auto-register-M4YSPJS6.mjs.map +1 -0
- package/dist/bin/prismer.js +14988 -0
- package/dist/chunk-BJTO5JO5.mjs +11 -0
- package/dist/chunk-BJTO5JO5.mjs.map +1 -0
- package/dist/chunk-JIEDFDVI.mjs +148 -0
- package/dist/chunk-JIEDFDVI.mjs.map +1 -0
- package/dist/chunk-NDNX2G6O.mjs +68 -0
- package/dist/chunk-NDNX2G6O.mjs.map +1 -0
- package/dist/chunk-POWV475F.mjs +45 -0
- package/dist/chunk-POWV475F.mjs.map +1 -0
- package/dist/chunk-VTFKZAUY.mjs +68 -0
- package/dist/chunk-VTFKZAUY.mjs.map +1 -0
- package/dist/dispatch-mux-MW4HHICS.mjs +8 -0
- package/dist/dispatch-mux-MW4HHICS.mjs.map +1 -0
- package/dist/dispatch-rpc-J7H6KC2V.mjs +78 -0
- package/dist/dispatch-rpc-J7H6KC2V.mjs.map +1 -0
- package/dist/fs-rpc-OSHJZYK6.mjs +58 -0
- package/dist/fs-rpc-OSHJZYK6.mjs.map +1 -0
- package/dist/heartbeat-loop-H2LAI3V5.mjs +95 -0
- package/dist/heartbeat-loop-H2LAI3V5.mjs.map +1 -0
- package/dist/icon +21 -0
- package/dist/index.d.mts +2063 -0
- package/dist/index.d.ts +2063 -0
- package/dist/index.js +10013 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +8807 -0
- package/dist/index.mjs.map +1 -0
- package/dist/mode-b-DXJ7FJAL.mjs +152 -0
- package/dist/mode-b-DXJ7FJAL.mjs.map +1 -0
- package/dist/registry-ZYU2HDFL.mjs +12 -0
- package/dist/registry-ZYU2HDFL.mjs.map +1 -0
- package/dist/smallicon +6 -0
- package/package.json +72 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/daemon-process.ts","../src/event-bus.ts","../src/agent-supervisor.ts","../src/daemon-http.ts","../src/http/helpers.ts","../src/http/sse.ts","../src/http/fs-routes.ts","../src/http/agent-routes.ts","../src/pairing-manager.ts","../src/evolution-gateway.ts","../src/task-router.ts","../src/llm-dispatcher.ts","../src/keychain.ts","../src/config.ts","../src/commands/migrate-secrets.ts","../src/daemon/runner.ts","../src/trace-writer.ts","../src/multi-path-transport.ts","../src/connection-prober.ts","../src/relay-client.ts","../src/daemon-outbox.ts","../src/e2ee-crypto.ts","../src/cloud-url.ts","../src/memory-gateway.ts","../src/memory-db.ts","../src/memory-db-crypto.ts","../src/daemon/events-tailer.ts","../src/cli/ui.ts","../src/shared/brand-voice.ts","../src/cli/context.ts","../src/agents/hooks.ts","../src/memory-dream-runtime.ts","../src/e2ee-key-storage.ts","../src/secret-scan.ts","../src/memory-team-sync.ts","../src/shamir.ts","../src/index.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport { constants as fsConstants } from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\n\n// ============================================================\n// Types\n// ============================================================\n\nexport type DaemonState = 'starting' | 'running' | 'shutting_down' | 'stopped';\n\nexport interface DaemonOptions {\n pidFile?: string;\n dataDir?: string;\n logFile?: string;\n installSignalHandlers?: boolean;\n}\n\nexport interface ShutdownHandler {\n name: string;\n handler: () => Promise<void> | void;\n}\n\n// ============================================================\n// Errors\n// ============================================================\n\nexport class DaemonAlreadyRunningError extends Error {\n readonly existingPid: number;\n readonly pidFile: string;\n\n constructor(pid: number, pidFile: string) {\n super(`Another daemon instance is already running (PID ${pid}, PID file: ${pidFile})`);\n this.name = 'DaemonAlreadyRunningError';\n this.existingPid = pid;\n this.pidFile = pidFile;\n }\n}\n\n// ============================================================\n// DaemonProcess\n// ============================================================\n\nexport class DaemonProcess {\n private _state: DaemonState = 'starting';\n private readonly _pidFile: string;\n private readonly _dataDir: string;\n private readonly _logFile: string;\n private readonly _installSignalHandlers: boolean;\n private readonly _shutdownHandlers: ShutdownHandler[] = [];\n private readonly _signalHistory: Array<{ signal: string; ts: number }> = [];\n private _shutdownInProgress = false;\n\n private _sigTermHandler: (() => void) | null = null;\n private _sigIntHandler: (() => void) | null = null;\n private _sigHupHandler: (() => void) | null = null;\n // Second-signal guard: if SIGTERM/SIGINT fires while we're already shutting\n // down, the operator wants to hard-kill. process.exit(1) to avoid hanging.\n private _signalReceived = false;\n\n constructor(opts?: DaemonOptions) {\n const home = os.homedir();\n this._pidFile = opts?.pidFile ?? path.join(home, '.prismer', 'daemon.pid');\n this._dataDir = opts?.dataDir ?? path.join(home, '.prismer');\n this._logFile = opts?.logFile ?? path.join(home, '.prismer', 'daemon.log');\n this._installSignalHandlers = opts?.installSignalHandlers ?? true;\n }\n\n get state(): DaemonState {\n return this._state;\n }\n\n get pid(): number {\n return process.pid;\n }\n\n get pidFile(): string {\n return this._pidFile;\n }\n\n get dataDir(): string {\n return this._dataDir;\n }\n\n get signalHistory(): ReadonlyArray<{ signal: string; ts: number }> {\n return this._signalHistory;\n }\n\n async start(): Promise<void> {\n if (this._state !== 'starting') {\n throw new Error(`Cannot start: current state is '${this._state}', expected 'starting'`);\n }\n\n const subdirs = [\n this._dataDir,\n path.join(this._dataDir, 'logs'),\n path.join(this._dataDir, 'sandbox'),\n path.join(this._dataDir, 'data'),\n path.join(this._dataDir, 'config'),\n ];\n for (const dir of subdirs) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n this._atomicPidWrite();\n\n if (this._installSignalHandlers) {\n // Signal handlers await shutdown() then process.exit(0). We don't rely\n // on the event loop draining on its own — upstream deps (ws, keep-alive\n // sockets, node-fetch) leak timers that keep the process alive past\n // shutdown, which caused every `daemon stop` to fall through to the\n // 10s SIGKILL path.\n const handleTerm = (signal: 'SIGTERM' | 'SIGINT') => async (): Promise<void> => {\n if (this._signalReceived) {\n // Operator hit Ctrl+C twice / kill -TERM a second time. Hard-exit.\n process.exit(1);\n }\n this._signalReceived = true;\n this._recordSignal(signal);\n try {\n await this.shutdown(signal);\n } catch {\n // Shutdown errors are already logged by shutdown() handler loop.\n }\n process.exit(0);\n };\n this._sigTermHandler = (): void => { void handleTerm('SIGTERM')(); };\n this._sigIntHandler = (): void => { void handleTerm('SIGINT')(); };\n this._sigHupHandler = () => {\n this._recordSignal('SIGHUP');\n void this.reload();\n };\n process.on('SIGTERM', this._sigTermHandler);\n process.on('SIGINT', this._sigIntHandler);\n process.on('SIGHUP', this._sigHupHandler);\n }\n\n this._state = 'running';\n }\n\n onShutdown(h: ShutdownHandler): void {\n this._shutdownHandlers.push(h);\n }\n\n async shutdown(signal?: NodeJS.Signals | 'manual'): Promise<void> {\n if (this._state === 'stopped' || this._state === 'shutting_down') {\n return;\n }\n if (this._state !== 'running') {\n throw new Error(`Cannot shutdown: current state is '${this._state}', expected 'running'`);\n }\n\n if (this._shutdownInProgress) {\n return;\n }\n this._shutdownInProgress = true;\n\n this._state = 'shutting_down';\n\n const reversed = [...this._shutdownHandlers].reverse();\n for (const { name, handler } of reversed) {\n try {\n await handler();\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n console.log(`[DaemonProcess] Shutdown handler '${name}' failed: ${msg}`);\n }\n }\n\n try {\n fs.rmSync(this._pidFile, { force: true });\n } catch {\n // Best effort\n }\n\n if (this._installSignalHandlers) {\n if (this._sigTermHandler) process.off('SIGTERM', this._sigTermHandler);\n if (this._sigIntHandler) process.off('SIGINT', this._sigIntHandler);\n if (this._sigHupHandler) process.off('SIGHUP', this._sigHupHandler);\n this._sigTermHandler = null;\n this._sigIntHandler = null;\n this._sigHupHandler = null;\n }\n\n this._state = 'stopped';\n console.log(`[DaemonProcess] Stopped (signal=${signal ?? 'manual'})`);\n }\n\n async reload(): Promise<void> {\n console.log('[DaemonProcess] SIGHUP received — reload requested');\n }\n\n static isRunning(pidFile: string): boolean {\n if (!fs.existsSync(pidFile)) {\n return false;\n }\n try {\n const raw = fs.readFileSync(pidFile, 'utf-8').trim();\n const pid = parseInt(raw, 10);\n if (isNaN(pid) || pid <= 0) {\n return false;\n }\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n }\n\n static cleanupStalePidFile(pidFile: string): boolean {\n if (DaemonProcess.isRunning(pidFile)) {\n return false;\n }\n try {\n fs.rmSync(pidFile, { force: true });\n return true;\n } catch {\n return false;\n }\n }\n\n private _atomicPidWrite(): void {\n let fd: number;\n let cleanedStale = false;\n\n const openExclusive = (): number => {\n return fs.openSync(\n this._pidFile,\n fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL,\n 0o644,\n );\n };\n\n try {\n fd = openExclusive();\n } catch (err) {\n const e = err as NodeJS.ErrnoException;\n if (e.code !== 'EEXIST') throw e;\n\n // PID file exists — check whether the owning process is still alive.\n if (DaemonProcess.isRunning(this._pidFile)) {\n const pid = this._readPidFromFile(this._pidFile) ?? 0;\n throw new DaemonAlreadyRunningError(pid, this._pidFile);\n }\n\n // Stale — remove and retry exactly once.\n fs.rmSync(this._pidFile, { force: true });\n cleanedStale = true;\n\n try {\n fd = openExclusive();\n } catch (retryErr) {\n const e2 = retryErr as NodeJS.ErrnoException;\n if (e2.code === 'EEXIST') {\n // Another process raced in and recreated the pidfile between our rm and retry.\n if (DaemonProcess.isRunning(this._pidFile)) {\n const pid = this._readPidFromFile(this._pidFile) ?? 0;\n throw new DaemonAlreadyRunningError(pid, this._pidFile);\n }\n throw new Error(`Race on PID file ${this._pidFile}; retry start`);\n }\n throw retryErr;\n }\n }\n\n try {\n fs.writeSync(fd, String(process.pid));\n } finally {\n fs.closeSync(fd);\n }\n\n if (cleanedStale) {\n console.log('[DaemonProcess] Cleaned stale PID file');\n }\n }\n\n private _recordSignal(signal: string): void {\n this._signalHistory.push({ signal, ts: Date.now() });\n }\n\n private _readPidFromFile(pidFile: string): number | null {\n try {\n const raw = fs.readFileSync(pidFile, 'utf-8').trim();\n const pid = parseInt(raw, 10);\n return isNaN(pid) || pid <= 0 ? null : pid;\n } catch {\n return null;\n }\n }\n}\n","/**\n * Unified event envelope that wraps PARA events.\n * This aligns with the event-bus API while providing type safety.\n */\n\n// AgentDescriptor type (from wire package)\nexport interface AgentDescriptor {\n id: string;\n adapter: string;\n version: string;\n tiersSupported: number[];\n capabilityTags: string[];\n workspace: string;\n workspaceGroup?: string;\n}\n\n// Local PARA event type definitions (from wire package, re-exported here)\nexport type ParaEvent = {\n 'agent.register': { type: 'agent.register'; agent: AgentDescriptor };\n 'agent.session.started': { type: 'agent.session.started'; session: string };\n 'agent.session.ended': { type: 'agent.session.ended'; session: string };\n 'agent.state': { type: 'agent.state'; status: string };\n 'agent.skill.activated': { type: 'agent.skill.activated'; skill: string };\n 'agent.skill.deactivated': { type: 'agent.skill.deactivated'; skill: string };\n 'agent.approval.request': { type: 'agent.approval.request'; requestId: string };\n 'agent.approval.result': { type: 'agent.approval.result'; approved: boolean };\n 'agent.task.created': { type: 'agent.task.created'; taskId: string };\n 'agent.task.completed': { type: 'agent.task.completed'; taskId: string };\n 'agent.llm.pre': { type: 'agent.llm.pre'; requestId: string };\n 'agent.llm.post': { type: 'agent.llm.post'; requestId: string };\n};\n\nexport interface EventBusEnvelope<T = unknown> {\n topic: string;\n ts: number;\n payload: T;\n source?: string;\n requestId?: string;\n}\n\n/**\n * Unified subscription handler that accepts EventBusEnvelope.\n * This matches the EventBus API expectation.\n */\nexport type SubscriptionHandler<T = unknown> = (ev: EventBusEnvelope<T>) => void | Promise<void>;\n\nexport interface Subscription {\n id: string;\n pattern: string;\n unsubscribe(): void;\n}\n\nexport interface EventBusOptions {\n onSubscriberError?: (err: unknown, sub: Subscription, ev: EventBusEnvelope) => void;\n queueWarnThreshold?: number;\n}\n\n// ============================================================\n// Internal subscriber entry\n// ============================================================\n\ninterface SubscriberEntry {\n handler: SubscriptionHandler;\n pattern: string;\n subscription: Subscription;\n queue: EventBusEnvelope[];\n draining: boolean;\n}\n\n// ============================================================\n// Wildcard matching (mirrors EXP-31 semantics)\n//\n// pattern === '*' matches any topic (receive-all)\n// pattern.endsWith('.*') prefix match: 'agent.tool.*' matches 'agent.tool.pre'\n// but NOT 'agent.session.start'\n// otherwise exact match\n// ============================================================\n\nfunction matchesTopic(topic: string, pattern: string): boolean {\n if (pattern === '*') {\n return true;\n }\n if (pattern.endsWith('.*')) {\n const prefix = pattern.slice(0, -1); // 'agent.tool.'\n return topic.startsWith(prefix);\n }\n return topic === pattern;\n}\n\n// ============================================================\n// EventBus\n// ============================================================\n\nexport class EventBus {\n private readonly _subscribers = new Map<string, SubscriberEntry>();\n private _monotonicTs = 0;\n private _totalPublished = 0;\n private readonly _onError: (err: unknown, sub: Subscription, ev: EventBusEnvelope) => void;\n private readonly _warnThreshold: number;\n\n constructor(opts?: EventBusOptions) {\n this._warnThreshold = opts?.queueWarnThreshold ?? 1000;\n this._onError = opts?.onSubscriberError ?? ((err) => {\n process.stderr.write(\n `[EventBus] Subscriber error: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n });\n }\n\n publish<T>(\n topic: string,\n payload: T,\n meta?: { source?: string; requestId?: string },\n ): void {\n const now = Date.now();\n this._monotonicTs = Math.max(this._monotonicTs + 1, now);\n\n const envelope: EventBusEnvelope<T> = { topic, ts: this._monotonicTs, payload };\n if (meta?.source !== undefined) (envelope as EventBusEnvelope<T>).source = meta.source;\n if (meta?.requestId !== undefined) (envelope as EventBusEnvelope<T>).requestId = meta.requestId;\n\n this._totalPublished++;\n\n for (const entry of this._subscribers.values()) {\n if (matchesTopic(topic, entry.pattern)) {\n entry.queue.push(envelope as EventBusEnvelope<T>);\n\n if (entry.queue.length >= this._warnThreshold) {\n process.stderr.write(\n `[EventBus] Subscriber '${entry.subscription.id}' backlog ${entry.queue.length} events\\n`,\n );\n }\n }\n\n this._drain(entry);\n }\n }\n\n subscribe<T>(\n topic: string,\n handler: SubscriptionHandler<T>,\n ): Subscription {\n const id = `sub_${Math.random().toString(36).slice(2)}_${Date.now()}`;\n\n const subscription: Subscription = {\n id,\n pattern: topic,\n unsubscribe: () => {\n this._subscribers.delete(id);\n },\n };\n\n const entry: SubscriberEntry = {\n handler: handler as SubscriptionHandler<unknown>,\n pattern: topic,\n subscription,\n queue: [],\n draining: false,\n };\n\n this._subscribers.set(id, entry);\n return subscription;\n }\n\n unsubscribeAll(): void {\n this._subscribers.clear();\n }\n\n get subscriberCount(): number {\n return this._subscribers.size;\n }\n\n get totalPublished(): number {\n return this._totalPublished;\n }\n\n private _drain(entry: SubscriberEntry): void {\n if (entry.draining) {\n return;\n }\n\n entry.draining = true;\n\n const loop = async () => {\n while (entry.queue.length > 0) {\n const ev = entry.queue.shift()!;\n try {\n await entry.handler(ev);\n } catch (err: unknown) {\n this._onError(err, entry.subscription, ev);\n }\n }\n entry.draining = false;\n };\n\n loop().catch((err) => {\n process.stderr.write(`[EventBus] Drain error: ${err}\\n`);\n });\n }\n}\n","import * as cp from 'node:child_process';\nimport type { EventBus } from './event-bus.js';\n\n// ============================================================\n// Types\n// ============================================================\n\nexport type AgentState =\n | 'registered' // in registry, not yet spawned\n | 'spawning'\n | 'running'\n | 'degraded' // health probes failing but process up\n | 'crashed'\n | 'backoff' // waiting for restart\n | 'stopping'\n | 'stopped'\n | 'failed'; // exceeded max restarts\n\nexport interface AgentDescriptor {\n id: string;\n name: string;\n command: string;\n args?: string[];\n cwd?: string;\n env?: NodeJS.ProcessEnv;\n // Called periodically while 'running'. Consecutive failures beyond the threshold\n // cause state → 'degraded'. Returns false or throws to signal unhealthy.\n healthCheck?: () => Promise<boolean> | boolean;\n backoff?: {\n initialMs?: number; // default 50\n multiplier?: number; // default 2\n maxMs?: number; // default 30000\n maxRestarts?: number; // default 5 — then 'failed'\n resetAfterMs?: number; // default 60000 — clean uptime resets the counter\n };\n // Attach (don't spawn): supervisor tracks this pid but does NOT own lifecycle.\n // stop() sends SIGTERM only — if the process ignores it, the caller must handle it.\n // Crash recovery does NOT restart attached agents.\n attachPid?: number;\n}\n\nexport interface AgentStatus {\n id: string;\n state: AgentState;\n pid?: number;\n startedAt?: number;\n restarts: number;\n lastExitCode?: number;\n lastSignal?: NodeJS.Signals | null;\n lastHealthError?: string;\n nextRestartAt?: number;\n}\n\nexport interface SupervisorOptions {\n eventBus: EventBus;\n healthProbeIntervalMs?: number; // default 5000\n degradedThreshold?: number; // default 3 consecutive failures → 'degraded'\n stopTimeoutMs?: number; // default 5000 — SIGTERM grace period before SIGKILL\n}\n\n// ============================================================\n// Internal per-agent runtime record\n// ============================================================\n\ninterface AgentEntry {\n descriptor: AgentDescriptor;\n status: AgentStatus;\n // Owned child process (spawn path). Absent for attached agents.\n child?: cp.ChildProcess;\n // Whether supervisor owns this pid (false for attached agents).\n owned: boolean;\n // Backoff timer handle for pending restart.\n backoffTimer?: NodeJS.Timeout;\n // Health probe interval handle.\n probeInterval?: NodeJS.Timeout;\n // Consecutive health-check failures since last reset.\n consecutiveHealthFailures: number;\n // Timestamp when the current run started (to support resetAfterMs).\n runStartedAt?: number;\n}\n\n// Maximum bytes forwarded per stdout/stderr event (1 KB).\nconst MAX_IO_BYTES = 1024;\n\n// ============================================================\n// AgentSupervisor\n// ============================================================\n\nexport class AgentSupervisor {\n private readonly _bus: EventBus;\n private readonly _probeIntervalMs: number;\n private readonly _degradedThreshold: number;\n private readonly _stopTimeoutMs: number;\n private readonly _agents = new Map<string, AgentEntry>();\n\n constructor(opts: SupervisorOptions) {\n this._bus = opts.eventBus;\n this._probeIntervalMs = opts.healthProbeIntervalMs ?? 5000;\n this._degradedThreshold = opts.degradedThreshold ?? 3;\n this._stopTimeoutMs = opts.stopTimeoutMs ?? 5000;\n }\n\n // ----------------------------------------------------------\n // Public API\n // ----------------------------------------------------------\n\n register(descriptor: AgentDescriptor): void {\n if (this._agents.has(descriptor.id)) {\n throw new Error(`Agent '${descriptor.id}' is already registered`);\n }\n const entry: AgentEntry = {\n descriptor,\n status: {\n id: descriptor.id,\n state: 'registered',\n restarts: 0,\n },\n owned: true,\n consecutiveHealthFailures: 0,\n };\n this._agents.set(descriptor.id, entry);\n this._publish('agent.registered', { id: descriptor.id });\n }\n\n async unregister(id: string): Promise<void> {\n const entry = this._require(id);\n const { state } = entry.status;\n if (state !== 'registered' && state !== 'stopped' && state !== 'failed') {\n await this.stop(id, 'unregister');\n }\n this._agents.delete(id);\n }\n\n async spawn(id: string): Promise<void> {\n const entry = this._require(id);\n if (entry.status.state !== 'registered') {\n throw new Error(\n `Agent '${id}' must be in 'registered' state to spawn (current: '${entry.status.state}')`,\n );\n }\n await this._doSpawn(entry);\n }\n\n async stop(id: string, reason?: string): Promise<void> {\n const entry = this._require(id);\n const { state } = entry.status;\n\n // Cancel any pending restart first so we don't re-spawn after stopping.\n this._cancelBackoff(entry);\n this._stopProbe(entry);\n\n if (state === 'stopped' || state === 'registered' || state === 'failed') {\n entry.status.state = 'stopped';\n return;\n }\n\n entry.status.state = 'stopping';\n this._publish('agent.stopping', { id, reason });\n\n if (entry.owned && entry.child) {\n await this._killOwned(entry);\n } else if (!entry.owned && entry.status.pid !== undefined) {\n // Attached agent: polite SIGTERM only — we do not SIGKILL.\n try {\n process.kill(entry.status.pid, 'SIGTERM');\n } catch {\n // Already gone — treat as stopped.\n }\n }\n\n entry.status.state = 'stopped';\n entry.status.pid = undefined;\n entry.child = undefined;\n this._publish('agent.stopped', { id });\n }\n\n async restart(id: string): Promise<void> {\n const entry = this._require(id);\n this._cancelBackoff(entry);\n this._stopProbe(entry);\n\n if (entry.child) {\n await this._killOwned(entry);\n entry.child = undefined;\n }\n\n entry.status.state = 'registered';\n entry.status.restarts = 0;\n await this._doSpawn(entry);\n }\n\n // Track an external PID without spawning or owning its lifecycle.\n // Health probes still run if the descriptor has healthCheck.\n // On exit, transitions to 'stopped' (not 'crashed') — no restart.\n async attach(id: string, pid: number): Promise<void> {\n const entry = this._require(id);\n\n entry.owned = false;\n entry.status.pid = pid;\n entry.status.state = 'running';\n entry.status.startedAt = Date.now();\n entry.runStartedAt = entry.status.startedAt;\n\n this._publish('agent.running', { id, pid });\n this._startProbe(entry);\n\n // Poll for PID disappearance on a best-effort basis (1-second tick).\n // When the attached process exits, emit agent.exited and move to stopped.\n this._pollAttached(entry);\n }\n\n get(id: string): AgentStatus | undefined {\n const entry = this._agents.get(id);\n return entry ? { ...entry.status } : undefined;\n }\n\n list(): AgentStatus[] {\n return Array.from(this._agents.values()).map((e) => ({ ...e.status }));\n }\n\n async shutdown(): Promise<void> {\n const ids = Array.from(this._agents.keys());\n await Promise.all(ids.map((id) => this.stop(id, 'shutdown').catch(() => undefined)));\n this._agents.clear();\n }\n\n // ----------------------------------------------------------\n // Spawn internals\n // ----------------------------------------------------------\n\n private async _doSpawn(entry: AgentEntry): Promise<void> {\n const { descriptor, status } = entry;\n const id = descriptor.id;\n\n status.state = 'spawning';\n entry.consecutiveHealthFailures = 0;\n this._publish('agent.spawning', { id });\n\n let child: cp.ChildProcess;\n try {\n child = cp.spawn(descriptor.command, descriptor.args ?? [], {\n cwd: descriptor.cwd,\n env: descriptor.env,\n stdio: 'pipe',\n });\n } catch (err: unknown) {\n const reason = err instanceof Error ? err.message : String(err);\n status.state = 'crashed';\n this._publish('agent.crashed', { id, reason });\n this._scheduleRestart(entry);\n return;\n }\n\n entry.child = child;\n entry.owned = true;\n status.pid = child.pid;\n status.startedAt = Date.now();\n entry.runStartedAt = status.startedAt;\n\n // Forward stdout/stderr as events, capped at MAX_IO_BYTES per chunk.\n child.stdout?.on('data', (chunk: Buffer) => {\n const text = chunk.toString('utf8').slice(0, MAX_IO_BYTES);\n this._publish('agent.stdout', { id, text });\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n const text = chunk.toString('utf8').slice(0, MAX_IO_BYTES);\n this._publish('agent.stderr', { id, text });\n });\n\n // Spawn-time error (e.g. ENOENT — process never started).\n child.once('error', (err) => {\n if (status.state === 'stopping' || status.state === 'stopped') return;\n status.state = 'crashed';\n this._publish('agent.crashed', { id, reason: err.message });\n this._stopProbe(entry);\n entry.child = undefined;\n this._scheduleRestart(entry);\n });\n\n child.once('exit', (code, signal) => {\n if (status.state === 'stopping' || status.state === 'stopped') return;\n this._stopProbe(entry);\n entry.child = undefined;\n status.lastExitCode = code ?? undefined;\n status.lastSignal = signal;\n status.pid = undefined;\n this._publish('agent.exited', { id, code, signal });\n this._handleCrash(entry);\n });\n\n status.state = 'running';\n this._publish('agent.running', { id, pid: child.pid });\n this._startProbe(entry);\n }\n\n // ----------------------------------------------------------\n // Crash recovery\n // ----------------------------------------------------------\n\n private _handleCrash(entry: AgentEntry): void {\n const { status } = entry;\n const id = entry.descriptor.id;\n\n status.state = 'crashed';\n this._publish('agent.crashed', { id, reason: `exited: code=${status.lastExitCode ?? 'null'} signal=${status.lastSignal ?? 'null'}` });\n\n this._scheduleRestart(entry);\n }\n\n private _scheduleRestart(entry: AgentEntry): void {\n const { descriptor, status } = entry;\n const id = descriptor.id;\n const cfg = descriptor.backoff ?? {};\n const initialMs = cfg.initialMs ?? 50;\n const multiplier = cfg.multiplier ?? 2;\n const maxMs = cfg.maxMs ?? 30000;\n const maxRestarts = cfg.maxRestarts ?? 5;\n const resetAfterMs = cfg.resetAfterMs ?? 60000;\n\n // If the agent ran cleanly for more than resetAfterMs before this crash, reset counter.\n if (entry.runStartedAt !== undefined) {\n const uptime = Date.now() - entry.runStartedAt;\n if (uptime >= resetAfterMs) {\n status.restarts = 0;\n }\n }\n\n if (status.restarts >= maxRestarts) {\n status.state = 'failed';\n this._publish('agent.failed', { id, reason: `exceeded maxRestarts (${maxRestarts})` });\n return;\n }\n\n const delay = Math.min(initialMs * Math.pow(multiplier, status.restarts), maxMs);\n const attempt = status.restarts + 1;\n const nextRestartAt = Date.now() + delay;\n status.nextRestartAt = nextRestartAt;\n status.state = 'backoff';\n this._publish('agent.restarting', { id, attempt, delayMs: delay });\n\n const timer = setTimeout(async () => {\n entry.backoffTimer = undefined;\n status.nextRestartAt = undefined;\n status.restarts++;\n await this._doSpawn(entry);\n }, delay);\n\n // unref so the timer does not prevent the event loop from exiting in tests.\n timer.unref();\n entry.backoffTimer = timer;\n }\n\n // ----------------------------------------------------------\n // Stop helpers\n // ----------------------------------------------------------\n\n // SIGTERM → wait stopTimeoutMs → SIGKILL if still alive → await exit event.\n private _killOwned(entry: AgentEntry): Promise<void> {\n const child = entry.child;\n if (!child || child.exitCode !== null || child.signalCode !== null) {\n return Promise.resolve();\n }\n\n return new Promise<void>((resolve) => {\n const done = (): void => {\n clearTimeout(killTimer);\n resolve();\n };\n\n child.once('exit', done);\n\n try {\n child.kill('SIGTERM');\n } catch {\n // Already dead.\n done();\n return;\n }\n\n const killTimer = setTimeout(() => {\n try {\n child.kill('SIGKILL');\n } catch {\n // Already dead.\n }\n }, this._stopTimeoutMs);\n });\n }\n\n private _cancelBackoff(entry: AgentEntry): void {\n if (entry.backoffTimer !== undefined) {\n clearTimeout(entry.backoffTimer);\n entry.backoffTimer = undefined;\n entry.status.nextRestartAt = undefined;\n }\n }\n\n // ----------------------------------------------------------\n // Health probe\n // ----------------------------------------------------------\n\n private _startProbe(entry: AgentEntry): void {\n if (!entry.descriptor.healthCheck) return;\n this._stopProbe(entry); // clear any stale interval\n\n const interval = setInterval(async () => {\n await this._runProbe(entry);\n }, this._probeIntervalMs);\n\n interval.unref();\n entry.probeInterval = interval;\n }\n\n private _stopProbe(entry: AgentEntry): void {\n if (entry.probeInterval !== undefined) {\n clearInterval(entry.probeInterval);\n entry.probeInterval = undefined;\n }\n }\n\n private async _runProbe(entry: AgentEntry): Promise<void> {\n const { status, descriptor } = entry;\n if (!descriptor.healthCheck) return;\n if (status.state !== 'running' && status.state !== 'degraded') return;\n\n let healthy = false;\n let errorMsg: string | undefined;\n\n try {\n healthy = await descriptor.healthCheck();\n } catch (err: unknown) {\n healthy = false;\n errorMsg = err instanceof Error ? err.message : String(err);\n }\n\n if (healthy) {\n if (status.state === 'degraded') {\n // Recovery: reset counter, return to running.\n entry.consecutiveHealthFailures = 0;\n status.state = 'running';\n delete status.lastHealthError;\n } else {\n entry.consecutiveHealthFailures = 0;\n }\n } else {\n entry.consecutiveHealthFailures++;\n if (errorMsg !== undefined) {\n status.lastHealthError = errorMsg;\n }\n if (entry.consecutiveHealthFailures >= this._degradedThreshold) {\n status.state = 'degraded';\n this._publish('agent.degraded', { id: descriptor.id, lastHealthError: status.lastHealthError });\n }\n }\n }\n\n // ----------------------------------------------------------\n // Attach poll\n // ----------------------------------------------------------\n\n // Periodically check whether an attached (non-owned) PID is still alive.\n // This uses process.kill(pid, 0) as a probe — zero-cost on most platforms.\n private _pollAttached(entry: AgentEntry): void {\n const { status, descriptor } = entry;\n const id = descriptor.id;\n\n const tick = (): void => {\n if (status.state !== 'running' && status.state !== 'degraded') return;\n const pid = status.pid;\n if (pid === undefined) return;\n\n let alive = false;\n try {\n process.kill(pid, 0);\n alive = true;\n } catch {\n alive = false;\n }\n\n if (!alive) {\n this._stopProbe(entry);\n status.state = 'stopped';\n status.pid = undefined;\n this._publish('agent.exited', { id, code: null, signal: null });\n // Attached agents do NOT restart — transition to stopped, not crashed.\n return;\n }\n\n // Schedule the next poll with unref so it does not block the event loop.\n const t = setTimeout(tick, 1000);\n t.unref();\n };\n\n const t = setTimeout(tick, 1000);\n t.unref();\n }\n\n // ----------------------------------------------------------\n // Utilities\n // ----------------------------------------------------------\n\n private _require(id: string): AgentEntry {\n const entry = this._agents.get(id);\n if (!entry) throw new Error(`Agent '${id}' not found`);\n return entry;\n }\n\n private _publish(topic: string, payload: Record<string, unknown>): void {\n this._bus.publish(topic, payload, { source: 'supervisor' });\n }\n}\n","import * as http from 'node:http';\nimport type { EventBus } from './event-bus.js';\nimport type { AgentSupervisor } from './agent-supervisor.js';\nimport type { FsContext } from '@prismer/sandbox-runtime';\nimport { sendJson, readBody, extractBearer } from './http/helpers.js';\nimport { handleSse } from './http/sse.js';\nimport type { SseDeps } from './http/sse.js';\nimport {\n handleFsRead,\n handleFsWrite,\n handleFsDelete,\n handleFsEdit,\n handleFsList,\n handleFsSearch,\n} from './http/fs-routes.js';\nimport type { FsRoutesDeps } from './http/fs-routes.js';\nimport {\n handleAgentList,\n handleAgentGet,\n handleAgentRegister,\n handleAgentMessage,\n handleAgentStop,\n handleAgentApprove,\n} from './http/agent-routes.js';\nimport type { AgentRoutesDeps } from './http/agent-routes.js';\nimport { PairingManager } from './pairing-manager.js';\nimport { EventHandler } from './event-handler.js';\n\n// ============================================================\n// Public types\n// ============================================================\n\n/** Authenticated identity returned by the authenticate callback. */\nexport interface AuthenticatedIdentity {\n agentId: string;\n bearerSub?: string;\n}\n\nexport interface DaemonHttpOptions {\n host?: string;\n port?: number;\n eventBus: EventBus;\n supervisor: AgentSupervisor;\n fsContextProvider?: (req: { agentId: string; workspace?: string }) => FsContext | undefined;\n pairingManager?: PairingManager;\n eventHandler?: EventHandler; // Optional event handler for PARA events\n /** When provided, every non-health request must carry a valid Bearer token (null = 401).\n * When absent, localhost trust mode: body agentId is used as-is. */\n authenticate?: (bearerToken: string | undefined) => AuthenticatedIdentity | null;\n}\n\n/** Generic extension-point route handler registered via registerRoute() (Q3). */\nexport type RouteHandler = (\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ctx: { authed: AuthenticatedIdentity | null; body: Buffer },\n) => Promise<void> | void;\n\nconst DEFAULT_HOST = '127.0.0.1';\nconst DEFAULT_PORT = 3210;\nconst REQUEST_TIMEOUT_MS = 30_000;\nconst STOP_GRACE_MS = 5_000;\n\n// ============================================================\n// DaemonHttpServer — thin dispatcher\n// ============================================================\n\nexport class DaemonHttpServer {\n private readonly _host: string;\n private readonly _port: number;\n private readonly _bus: EventBus;\n private readonly _supervisor: AgentSupervisor;\n private readonly _fsCtxProvider?: DaemonHttpOptions['fsContextProvider'];\n private readonly _authenticate?: DaemonHttpOptions['authenticate'];\n private readonly _pairingManager: PairingManager;\n private readonly _eventHandler?: EventHandler;\n\n private _server: http.Server | undefined;\n private _url: string | undefined;\n private _running = false;\n\n private readonly _sseClients = new Set<http.ServerResponse>();\n private readonly _inFlight = new Set<http.ServerResponse>();\n private readonly _startedAt = Date.now();\n\n // Extension-point route registry (Q3)\n private readonly _customRoutes = new Map<string, RouteHandler>();\n\n constructor(opts: DaemonHttpOptions) {\n this._host = opts.host ?? DEFAULT_HOST;\n this._port = opts.port ?? DEFAULT_PORT;\n this._bus = opts.eventBus;\n this._supervisor = opts.supervisor;\n this._fsCtxProvider = opts.fsContextProvider;\n this._authenticate = opts.authenticate;\n this._pairingManager = opts.pairingManager ?? new PairingManager();\n this._eventHandler = opts.eventHandler;\n }\n\n get url(): string | undefined { return this._url; }\n get isRunning(): boolean { return this._running; }\n\n // Extension-point route registration (Q3)\n // ============================================================\n\n /** Register a custom route handler. Built-in routes take precedence. */\n registerRoute(\n method: 'GET' | 'POST' | 'PATCH' | 'DELETE',\n path: string,\n handler: RouteHandler,\n ): void {\n this._customRoutes.set(`${method}:${path}`, handler);\n }\n\n /** Remove a previously registered custom route. */\n unregisterRoute(method: string, path: string): void {\n this._customRoutes.delete(`${method}:${path}`);\n }\n\n private _findCustomRoute(method: string, pathname: string): RouteHandler | undefined {\n const exact = this._customRoutes.get(`${method}:${pathname}`);\n if (exact !== undefined) return exact;\n\n const withoutPrefix = pathname.startsWith('/api/v1/')\n ? pathname.slice('/api/v1'.length)\n : pathname;\n if (withoutPrefix !== pathname) {\n const prefixedExact = this._customRoutes.get(`${method}:${withoutPrefix}`);\n if (prefixedExact !== undefined) return prefixedExact;\n }\n\n for (const [key, handler] of this._customRoutes) {\n const sep = key.indexOf(':');\n if (sep < 0 || key.slice(0, sep) !== method) continue;\n const routePath = key.slice(sep + 1);\n if (routePath.indexOf(':') < 0) continue;\n if (routeMatches(routePath, pathname) || routeMatches(routePath, withoutPrefix)) {\n return handler;\n }\n }\n\n return undefined;\n }\n\n // Lifecycle\n // ============================================================\n\n start(): Promise<{ host: string; port: number }> {\n return new Promise<{ host: string; port: number }>((resolve, reject) => {\n const server = http.createServer((req, res) => {\n void this._handleRequest(req, res);\n });\n server.on('error', reject);\n // Swallow expected socket errors (ECONNRESET during teardown / client abort)\n server.on('clientError', (_err, socket) => {\n if (!socket.destroyed) socket.destroy();\n });\n server.listen(this._port, this._host, () => {\n const addr = server.address();\n if (!addr || typeof addr !== 'object') {\n reject(new Error('Failed to obtain bound address'));\n return;\n }\n this._server = server;\n this._running = true;\n this._url = `http://${addr.address}:${addr.port}`;\n\n // Start event handler if provided\n if (this._eventHandler) {\n this._eventHandler.start();\n }\n\n resolve({ host: addr.address, port: addr.port });\n });\n });\n }\n\n async stop(timeoutMs: number = STOP_GRACE_MS): Promise<void> {\n if (!this._server || !this._running) return;\n this._running = false;\n const server = this._server;\n\n // Stop event handler if provided\n if (this._eventHandler) {\n this._eventHandler.stop();\n }\n\n await new Promise<void>((resolve) => {\n const deadline = setTimeout(() => {\n for (const res of this._inFlight) res.destroy();\n for (const res of this._sseClients) res.destroy();\n this._inFlight.clear();\n this._sseClients.clear();\n resolve();\n }, timeoutMs);\n deadline.unref();\n\n for (const res of this._sseClients) res.end();\n this._sseClients.clear();\n\n // Force-close all lingering keep-alive / in-flight connections so\n // server.close() resolves immediately instead of waiting for idle\n // timeout — prevents ECONNRESET errors from writes to dying sockets.\n server.closeAllConnections();\n\n server.close(() => {\n clearTimeout(deadline);\n resolve();\n });\n });\n }\n\n // ============================================================\n // Request dispatcher\n // ============================================================\n\n private async _handleRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {\n this._inFlight.add(res);\n\n // Swallow write errors on the response (e.g. ECONNRESET when the client\n // disconnects or the socket is torn down during server.stop()). Without\n // this handler the error becomes \"unhandled\" and poisons the process exit\n // code even though every test passes.\n res.on('error', () => {});\n\n const timeoutHandle = setTimeout(() => {\n if (!res.headersSent) {\n sendJson(res, 503, { error: 'timeout' });\n } else {\n res.destroy();\n }\n }, REQUEST_TIMEOUT_MS);\n\n res.on('finish', () => { clearTimeout(timeoutHandle); this._inFlight.delete(res); });\n res.on('close', () => { clearTimeout(timeoutHandle); this._inFlight.delete(res); });\n\n const url = new URL(req.url ?? '/', 'http://localhost');\n const method = (req.method ?? 'GET').toUpperCase();\n const pathname = url.pathname;\n\n try {\n // Health — always auth-free\n if (method === 'GET' && pathname === '/api/v1/health') {\n return this._handleHealth(res);\n }\n\n // Auth gate\n let authed: AuthenticatedIdentity | null = null;\n if (this._authenticate !== undefined && !isAuthBypassedPath(method, pathname)) {\n const token = extractBearer(req);\n const identity = this._authenticate(token);\n if (identity === null) {\n return sendJson(res, 401, { error: 'unauthorized' });\n }\n authed = identity;\n }\n\n // Shared deps structs\n const agentDeps: AgentRoutesDeps = { supervisor: this._supervisor, bus: this._bus };\n const fsDeps: FsRoutesDeps = { fsContextProvider: this._fsCtxProvider };\n const sseDeps: SseDeps = { bus: this._bus, sseClients: this._sseClients };\n\n // ---- Agents ----\n if (method === 'GET' && pathname === '/api/v1/agents') {\n return handleAgentList(res, agentDeps);\n }\n if (method === 'POST' && pathname === '/api/v1/agents/register') {\n return await handleAgentRegister(req, res, agentDeps);\n }\n const agentDetailMatch = pathname.match(/^\\/api\\/v1\\/agents\\/([^/]+)$/);\n if (method === 'GET' && agentDetailMatch) {\n return handleAgentGet(res, agentDetailMatch[1], agentDeps);\n }\n const agentActionMatch = pathname.match(/^\\/api\\/v1\\/agents\\/([^/]+)\\/([^/]+)$/);\n if (agentActionMatch) {\n const agentId = agentActionMatch[1];\n const action = agentActionMatch[2];\n if (method === 'POST' && action === 'message') {\n return await handleAgentMessage(req, res, agentId, agentDeps);\n }\n if (method === 'POST' && action === 'stop') {\n return await handleAgentStop(req, res, agentId, agentDeps);\n }\n if (method === 'POST' && action === 'approve') {\n return await handleAgentApprove(req, res, agentId, agentDeps);\n }\n }\n\n // ---- SSE ----\n if (method === 'GET' && pathname === '/api/v1/events') {\n return handleSse(req, res, url, sseDeps);\n }\n\n // ---- Pairing ----\n if (method === 'POST' && pathname === '/api/v1/pair/offer') {\n return await this._handlePairOffer(req, res);\n }\n if (method === 'GET' && pathname === '/api/v1/pair/status') {\n return this._handlePairStatus(res, url);\n }\n if (method === 'POST' && pathname === '/api/v1/pair/confirm') {\n return await this._handlePairConfirm(req, res);\n }\n\n // ---- Transport routes ----\n if (method === 'GET' && pathname === '/v1/lan-probe') {\n return this._handleLanProbe(req, res);\n }\n if (method === 'GET' && pathname === '/api/v1/transport/status') {\n return this._handleTransportStatus(res);\n }\n if (method === 'POST' && pathname === '/api/v1/transport/reprobe') {\n return this._handleTransportReprobe(res);\n }\n\n // ---- FS routes ----\n if (method === 'POST' && pathname === '/api/v1/fs/read') {\n return await handleFsRead(req, res, fsDeps, authed);\n }\n if (method === 'POST' && pathname === '/api/v1/fs/write') {\n return await handleFsWrite(req, res, fsDeps, authed);\n }\n if (method === 'POST' && pathname === '/api/v1/fs/delete') {\n return await handleFsDelete(req, res, fsDeps, authed);\n }\n if (method === 'POST' && pathname === '/api/v1/fs/edit') {\n return await handleFsEdit(req, res, fsDeps, authed);\n }\n if (method === 'POST' && pathname === '/api/v1/fs/list') {\n return await handleFsList(req, res, fsDeps, authed);\n }\n if (method === 'POST' && pathname === '/api/v1/fs/search') {\n return await handleFsSearch(req, res, fsDeps, authed);\n }\n\n // ---- GUI routes (v1.9.0 Pattern P9 — L9 GUI Integration) ----\n // Stable read-only HTTP for GUI consumers (luminpulse, web console).\n // Mirrors /agents but scoped to human presentation and versioned\n // independently so GUI tooling can pin to /gui/v1 without churn.\n if (method === 'GET' && pathname === '/api/v1/gui/agents') {\n return handleAgentList(res, agentDeps);\n }\n if (method === 'GET' && pathname === '/api/v1/gui/status') {\n // Lightweight \"everything-in-one\" snapshot for dashboard consumers.\n return sendJson(res, 200, {\n daemon: {\n pid: process.pid,\n uptime: process.uptime(),\n version: '1.9.0',\n },\n agents: this._supervisor ? this._supervisor.list() : [],\n transport: await this._snapshotTransportStatus(),\n });\n }\n\n // ---- Custom extension routes (Q3) ----\n const customHandler = this._findCustomRoute(method, pathname);\n if (customHandler !== undefined) {\n let body: Buffer;\n try {\n body = await readBody(req);\n } catch (err: unknown) {\n if (err instanceof Error && (err as Error & { code?: string }).code === 'E_TOO_LARGE') {\n return sendJson(res, 413, { error: 'body-too-large', max: 10 * 1024 * 1024 });\n }\n return sendJson(res, 400, { error: 'read-error' });\n }\n await customHandler(req, res, { authed, body });\n return;\n }\n\n sendJson(res, 404, { error: 'not-found' });\n } catch (err: unknown) {\n if (res.headersSent) return;\n const msg = err instanceof Error ? err.message : String(err);\n sendJson(res, 500, { error: 'internal', message: msg });\n }\n }\n\n // ============================================================\n // Health handler (inline — too small to extract)\n // ============================================================\n\n private _handleHealth(res: http.ServerResponse): void {\n const agents = this._supervisor.list();\n const rssBytes = process.memoryUsage().rss;\n const addr = this._server?.address();\n const port = addr !== null && typeof addr === 'object' ? addr.port : this._port;\n sendJson(res, 200, {\n status: 'ok',\n daemon: {\n pid: process.pid,\n uptime: Date.now() - this._startedAt,\n state: 'running',\n rssBytes,\n port,\n },\n counts: {\n agents: agents.length,\n subscriptions: this._bus.subscriberCount,\n },\n });\n }\n\n private async _handlePairOffer(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {\n let body: Buffer;\n try {\n body = await readBody(req);\n } catch (err: unknown) {\n if (err instanceof Error && (err as Error & { code?: string }).code === 'E_TOO_LARGE') {\n return sendJson(res, 413, { error: 'body-too-large', max: 10 * 1024 * 1024 });\n }\n return sendJson(res, 400, { error: 'read-error' });\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = body.length > 0 ? JSON.parse(body.toString('utf8')) as Record<string, unknown> : {};\n } catch {\n return sendJson(res, 400, { error: 'bad-json' });\n }\n const ttlSec = typeof parsed['ttlSec'] === 'number' ? parsed['ttlSec'] : undefined;\n const offer = this._pairingManager.createOffer(ttlSec);\n sendJson(res, 201, {\n ok: true,\n data: {\n offer: offer.offer,\n uri: offer.uri,\n expiresAt: offer.expiresAt,\n },\n });\n }\n\n private _handlePairStatus(res: http.ServerResponse, url: URL): void {\n const offer = url.searchParams.get('offer');\n if (!offer) {\n sendJson(res, 400, { error: 'missing-offer' });\n return;\n }\n\n const status = this._pairingManager.getStatus(offer);\n if (!status) {\n sendJson(res, 404, { error: 'offer-not-found', paired: false });\n return;\n }\n sendJson(res, 200, status);\n }\n\n private async _handlePairConfirm(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {\n let body: Buffer;\n try {\n body = await readBody(req);\n } catch (err: unknown) {\n if (err instanceof Error && (err as Error & { code?: string }).code === 'E_TOO_LARGE') {\n return sendJson(res, 413, { error: 'body-too-large', max: 10 * 1024 * 1024 });\n }\n return sendJson(res, 400, { error: 'read-error' });\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = body.length > 0 ? JSON.parse(body.toString('utf8')) as Record<string, unknown> : {};\n } catch {\n return sendJson(res, 400, { error: 'bad-json' });\n }\n\n const offer = typeof parsed['offer'] === 'string' ? parsed['offer'] : undefined;\n if (!offer) {\n return sendJson(res, 400, { error: 'missing-offer' });\n }\n\n try {\n const status = this._pairingManager.confirm(offer, {\n bindingId: typeof parsed['bindingId'] === 'string' ? parsed['bindingId'] : undefined,\n deviceName: typeof parsed['deviceName'] === 'string' ? parsed['deviceName'] : undefined,\n transport: parsed['transport'] === 'relay' ? 'relay' : 'lan',\n clientPubKey: typeof parsed['clientPubKey'] === 'string' ? parsed['clientPubKey'] : undefined,\n });\n sendJson(res, 200, { ok: true, ...status });\n } catch (err) {\n const e = err as Error & { status?: number };\n sendJson(res, e.status ?? 500, { ok: false, error: e.message });\n }\n }\n\n // ============================================================\n // Transport status handler\n // ============================================================\n\n private _handleTransportStatus(res: http.ServerResponse): void {\n // Four-state enum. Old schema lied: a fresh daemon with credentials\n // configured but no reachable cloud reported \"disabled\" even while the\n // relay prober was firing 404s in the background. Now:\n // disabled - TransportManager not instantiated (no cloud configured)\n // probing - enabled, first probe pass not complete\n // connected - a path is selected and health checks are green\n // unreachable - probes have run and all paths failed (or no path met the\n // latency threshold); `lastError` carries the short diag\n const transportManager = (globalThis as any).__transportManager as {\n getStatus: () => {\n currentPath: string | null;\n currentEndpoint: string | null;\n connected: boolean;\n latencyMs: number;\n lastHealthCheck: number;\n probesCompleted?: boolean;\n lastError?: string | null;\n paths: {\n [key: string]: {\n available: boolean;\n latencyMs: number;\n lastProbed: number;\n };\n };\n };\n } | undefined;\n\n if (!transportManager) {\n sendJson(res, 200, {\n status: 'disabled',\n message: 'Multi-path transport is not enabled',\n });\n return;\n }\n\n const status = transportManager.getStatus();\n\n // Derive the enum. `connected` requires both a currentPath and the\n // connection flag — e.g. relay may be \"switched to\" momentarily but\n // the WS is still reconnecting.\n let derived: 'probing' | 'connected' | 'unreachable';\n if (status.connected && status.currentPath !== null) {\n derived = 'connected';\n } else if (!status.probesCompleted) {\n derived = 'probing';\n } else {\n derived = 'unreachable';\n }\n\n const body: {\n status: 'probing' | 'connected' | 'unreachable';\n path?: string | null;\n latencyMs?: number;\n lastError?: string | null;\n transport: {\n currentPath: string | null;\n currentEndpoint: string | null;\n connected: boolean;\n latencyMs: number;\n lastHealthCheck: number;\n paths: unknown;\n };\n } = {\n status: derived,\n transport: {\n currentPath: status.currentPath,\n currentEndpoint: status.currentEndpoint,\n connected: status.connected,\n latencyMs: status.latencyMs,\n lastHealthCheck: status.lastHealthCheck,\n paths: status.paths,\n },\n };\n if (derived === 'connected') {\n body.path = status.currentPath;\n body.latencyMs = status.latencyMs;\n } else if (derived === 'unreachable') {\n body.lastError = status.lastError ?? null;\n }\n sendJson(res, 200, body);\n }\n\n /** Read-only snapshot of transport state, used by /gui/status. Returns\n * null when the multi-path transport isn't enabled. */\n private async _snapshotTransportStatus(): Promise<unknown> {\n const transportManager = (globalThis as any).__transportManager as\n | { getStatus: () => unknown }\n | undefined;\n return transportManager ? transportManager.getStatus() : null;\n }\n\n // ============================================================\n // LAN probe handler (for client connection probing)\n // ============================================================\n\n private _handleLanProbe(req: http.IncomingMessage, res: http.ServerResponse): void {\n // Verify client is from same subnet for security\n const clientIP = req.socket.remoteAddress;\n if (!clientIP) {\n sendJson(res, 403, { error: 'forbidden', message: 'Could not determine client IP' });\n return;\n }\n\n // Extract server address\n const addr = this._server?.address();\n if (!addr || typeof addr !== 'object') {\n sendJson(res, 500, { error: 'internal', message: 'Could not get server address' });\n return;\n }\n\n // Get daemon info from global storage\n const daemonInfo = (globalThis as any).__daemonInfo as {\n daemonId?: string;\n version?: string;\n lanIP?: string;\n port?: number;\n };\n\n const daemonId = daemonInfo?.daemonId || 'unknown';\n const version = daemonInfo?.version || '1.9.0';\n const lanIP = daemonInfo?.lanIP || addr.address;\n const port = daemonInfo?.port || addr.port;\n\n // Log probe request for debugging\n console.log(`[Daemon] LAN probe from ${clientIP} -> responding with ${lanIP}:${port}`);\n\n sendJson(res, 200, {\n daemonId,\n lanIP,\n port,\n version,\n timestamp: Date.now(),\n capabilities: [\n 'e2ee',\n 'binary-multiplex',\n 'connection-probing',\n ],\n });\n }\n\n // ============================================================\n // Transport reprobe handler\n // ============================================================\n\n private async _handleTransportReprobe(res: http.ServerResponse): Promise<void> {\n const transportManager = (globalThis as any).__transportManager as {\n forceReprobe: () => Promise<void>;\n };\n\n if (!transportManager) {\n sendJson(res, 400, {\n error: 'transport_disabled',\n message: 'Multi-path transport is not enabled',\n });\n return;\n }\n\n try {\n await transportManager.forceReprobe();\n sendJson(res, 200, {\n status: 'ok',\n message: 'Reprobe initiated',\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n sendJson(res, 500, {\n error: 'reprobe_failed',\n message: msg,\n });\n }\n }\n}\n\n/**\n * Routes that bypass the bearer-token auth gate even when `authenticate` is\n * configured. Mirrors the rationale at `runner.ts:415` for register-mode-b:\n * Localhost-only — loopback validation is the boundary. The dispatch endpoint\n * (`/adapters/dispatch`) is intentionally NOT in this list — it can carry\n * remote caller payloads in production and must remain authenticated.\n *\n * Exported for test access — see test/daemon-http-auth-bypass.test.ts.\n */\nexport const AUTH_BYPASS_PATHS: ReadonlyArray<{ method: string; pathname: string }> = [\n { method: 'POST', pathname: '/api/v1/adapters/register-mode-b' },\n];\n\nfunction isAuthBypassedPath(method: string, pathname: string): boolean {\n for (const entry of AUTH_BYPASS_PATHS) {\n if (entry.method === method && entry.pathname === pathname) return true;\n }\n return false;\n}\n\nfunction routeMatches(pattern: string, pathname: string): boolean {\n const patternParts = pattern.split('/').filter(Boolean);\n const pathParts = pathname.split('/').filter(Boolean);\n if (patternParts.length !== pathParts.length) return false;\n\n for (let i = 0; i < patternParts.length; i++) {\n const patternPart = patternParts[i];\n if (patternPart.startsWith(':')) continue;\n if (patternPart !== pathParts[i]) return false;\n }\n\n return true;\n}\n","// HTTP layer shared helpers — constants, readBody, sendJson, topic utilities.\n\nimport type * as http from 'node:http';\n\n// ============================================================\n// Constants\n// ============================================================\n\nexport const DEFAULT_PORT = 3210;\nexport const MAX_BODY_BYTES = 10 * 1024 * 1024; // 10 MB\n\n// ============================================================\n// sendJson\n// ============================================================\n\nexport function sendJson(res: http.ServerResponse, status: number, data: unknown): void {\n const body = JSON.stringify(data);\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(body),\n });\n res.end(body);\n}\n\n// ============================================================\n// readBody — destroys the request stream on oversize (I5)\n// ============================================================\n\nexport function readBody(req: http.IncomingMessage, maxBytes: number = MAX_BODY_BYTES): Promise<Buffer> {\n return new Promise<Buffer>((resolve, reject) => {\n const chunks: Buffer[] = [];\n let total = 0;\n let settled = false;\n\n req.on('data', (chunk: Buffer) => {\n if (settled) return;\n total += chunk.length;\n if (total > maxBytes) {\n settled = true;\n // Drain remaining data so the response can be flushed to the client\n // before the connection is torn down. Memory safety: we stop accumulating\n // into `chunks` immediately; the OS buffers are discarded as they drain.\n req.resume();\n // Destroy after the current tick so the 413 response has a chance to flush.\n setImmediate(() => req.destroy(new Error('body-too-large')));\n reject(Object.assign(new Error('body-too-large'), { code: 'E_TOO_LARGE' }));\n return;\n }\n chunks.push(chunk);\n });\n req.on('end', () => {\n if (!settled) {\n settled = true;\n resolve(Buffer.concat(chunks));\n }\n });\n req.on('error', (err) => {\n if (!settled) {\n settled = true;\n reject(err);\n }\n });\n });\n}\n\n// ============================================================\n// parseBody\n// ============================================================\n\nexport function parseBody(buf: Buffer): unknown {\n try {\n return JSON.parse(buf.toString('utf8'));\n } catch {\n return undefined;\n }\n}\n\n// ============================================================\n// extractBearer\n// ============================================================\n\nexport function extractBearer(req: http.IncomingMessage): string | undefined {\n const auth = req.headers['authorization'];\n if (!auth) return undefined;\n if (auth.startsWith('Bearer ')) return auth.slice(7);\n return undefined;\n}\n\n// ============================================================\n// SSE topic matching\n// ============================================================\n\nexport function topicMatches(topic: string, pattern: string): boolean {\n if (pattern === '*') return true;\n if (pattern.endsWith('.*')) {\n const prefix = pattern.slice(0, -1);\n return topic.startsWith(prefix);\n }\n return topic === pattern;\n}\n","// SSE subscription handler — extracted from daemon-http.ts (Q1 split).\n\nimport type * as http from 'node:http';\nimport type { EventBus, EventBusEnvelope } from '../event-bus.js';\nimport { sendJson, topicMatches } from './helpers.js';\n\nexport const SSE_HEARTBEAT_MS = 15_000;\nexport const MAX_SSE_CLIENTS = 50;\n\nexport interface SseDeps {\n bus: EventBus;\n sseClients: Set<http.ServerResponse>;\n}\n\nexport function handleSse(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n url: URL,\n deps: SseDeps,\n): void {\n if (deps.sseClients.size >= MAX_SSE_CLIENTS) {\n sendJson(res, 503, { error: 'too-many-sse-clients' });\n return;\n }\n\n const topicsParam = url.searchParams.get('topics') ?? '*';\n const patterns = topicsParam\n .split(',')\n .map((t) => t.trim())\n .filter((t) => t.length > 0);\n\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n });\n res.flushHeaders();\n\n deps.sseClients.add(res);\n\n // Per-client write helper.\n const send = (envelope: EventBusEnvelope): void => {\n if (res.writableEnded) return;\n res.write(`data: ${JSON.stringify(envelope)}\\n\\n`);\n };\n\n // Subscribe for each requested topic pattern.\n const subs = patterns.map((pattern) =>\n deps.bus.subscribe(pattern, (ev) => {\n if (patterns.some((p) => topicMatches(ev.topic, p))) {\n send(ev);\n }\n }),\n );\n\n // Heartbeat every 15s.\n const heartbeat = setInterval(() => {\n if (!res.writableEnded) {\n res.write(': heartbeat\\n\\n');\n }\n }, SSE_HEARTBEAT_MS);\n heartbeat.unref();\n\n const cleanup = (): void => {\n clearInterval(heartbeat);\n for (const sub of subs) sub.unsubscribe();\n deps.sseClients.delete(res);\n };\n\n req.on('close', cleanup);\n res.on('close', cleanup);\n}\n","// FS route handlers — extracted from daemon-http.ts (Q1 split).\n// Each function is a standalone route handler; the server wires them in.\n// C2: every handler receives `authed` (authenticated identity or null).\n// G2: FsContext is built with callPath: 'http' so audit logs reflect origin.\n\nimport type * as http from 'node:http';\nimport type { FsContext } from '@prismer/sandbox-runtime';\nimport {\n fsRead,\n fsWrite,\n fsDelete,\n fsEdit,\n fsList,\n fsSearch,\n UncPathError,\n OutsideSandboxError,\n PermissionDeniedError,\n} from '@prismer/sandbox-runtime';\nimport { sendJson, parseBody, readBody } from './helpers.js';\nimport type { AuthenticatedIdentity } from '../daemon-http.js';\n\n// ============================================================\n// Dependency interface\n// ============================================================\n\nexport interface FsRoutesDeps {\n /** Resolve FsContext from agent identity; returns undefined if FS not configured. */\n fsContextProvider?: (req: { agentId: string; workspace?: string }) => FsContext | undefined;\n}\n\n// ============================================================\n// resolveAgentId — C2 identity reconciliation\n//\n// Rules:\n// - If authed is non-null (authenticate IS configured):\n// * No body agentId → use authed.agentId.\n// * Body agentId present and matches authed.agentId → OK, use it.\n// * Body agentId present but differs → 403 agent-mismatch.\n// - If authed is null (localhost trust mode / no authenticate):\n// * Fall back to body agentId (existing behavior).\n// * If body agentId is also absent → return null (caller returns 400).\n// Returns { agentId: string } on success, or throws a sentinel to signal\n// a 403/400 response (we return null + side-effect on res instead).\n// ============================================================\n\nexport function resolveAgentId(\n res: http.ServerResponse,\n bodyAgentId: string | undefined,\n authed: AuthenticatedIdentity | null,\n): string | null {\n if (authed !== null) {\n // Authenticated mode\n if (bodyAgentId !== undefined && bodyAgentId !== authed.agentId) {\n sendJson(res, 403, {\n error: 'agent-mismatch',\n message: 'body agentId does not match authenticated identity',\n });\n return null;\n }\n return authed.agentId;\n }\n // Trust mode — body agentId\n if (bodyAgentId === undefined || bodyAgentId === '') {\n sendJson(res, 400, { error: 'missing-agent-id' });\n return null;\n }\n return bodyAgentId;\n}\n\n// ============================================================\n// Build FsContext with callPath: 'http' (G2)\n// ============================================================\n\nfunction getFsCtx(\n deps: FsRoutesDeps,\n agentId: string,\n workspace?: string,\n): FsContext | undefined {\n if (!deps.fsContextProvider) return undefined;\n const ctx = deps.fsContextProvider({ agentId, workspace });\n if (!ctx) return undefined;\n // G2: stamp callPath so audit entries reflect HTTP origin\n return { ...ctx, callPath: 'http' };\n}\n\n// ============================================================\n// mapFsError — translate fs-adapter errors to HTTP status codes\n// ============================================================\n\nexport function mapFsError(res: http.ServerResponse, err: unknown): void {\n if (err instanceof UncPathError) {\n sendJson(res, 400, { error: 'unc-path', message: (err as Error).message });\n return;\n }\n if (err instanceof OutsideSandboxError) {\n sendJson(res, 403, { error: 'outside-sandbox', message: (err as Error).message });\n return;\n }\n if (err instanceof PermissionDeniedError) {\n sendJson(res, 403, { error: 'permission-denied', message: (err as Error).message });\n return;\n }\n if (\n err instanceof Error &&\n 'code' in err &&\n (err as NodeJS.ErrnoException).code === 'ENOENT'\n ) {\n sendJson(res, 404, { error: 'not-found', message: (err as Error).message });\n return;\n }\n const name = err instanceof Error ? err.name : 'Error';\n const message = err instanceof Error ? err.message : String(err);\n sendJson(res, 500, { error: name, message });\n}\n\n// ============================================================\n// Helper: read body and resolve agentId together (used by all FS handlers)\n// Returns [buf, agentId] or null if a response was already sent.\n// ============================================================\n\nasync function readBodyAndResolveAgent(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n authed: AuthenticatedIdentity | null,\n): Promise<[Buffer, string] | null> {\n let buf: Buffer;\n try {\n buf = await readBody(req);\n } catch (err: unknown) {\n if (err instanceof Error && (err as Error & { code?: string }).code === 'E_TOO_LARGE') {\n sendJson(res, 413, { error: 'body-too-large', max: 10 * 1024 * 1024 });\n return null;\n }\n sendJson(res, 400, { error: 'read-error' });\n return null;\n }\n\n const parsed = parseBody(buf);\n if (parsed === undefined) {\n sendJson(res, 400, { error: 'bad-json' });\n return null;\n }\n\n const bodyObj = parsed as Record<string, unknown>;\n const bodyAgentId = typeof bodyObj['agentId'] === 'string' ? bodyObj['agentId'] : undefined;\n const agentId = resolveAgentId(res, bodyAgentId, authed);\n if (agentId === null) return null;\n\n return [buf, agentId];\n}\n\n// ============================================================\n// FS route handlers\n// ============================================================\n\nexport async function handleFsRead(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n deps: FsRoutesDeps,\n authed: AuthenticatedIdentity | null,\n): Promise<void> {\n const pair = await readBodyAndResolveAgent(req, res, authed);\n if (pair === null) return;\n const [buf, agentId] = pair;\n\n const body = parseBody(buf) as { path: string; offset?: number; limit?: number; workspace?: string };\n const ctx = getFsCtx(deps, agentId, body.workspace);\n if (!ctx) { sendJson(res, 503, { error: 'fs-adapter-not-configured' }); return; }\n\n try {\n const result = await fsRead(ctx, { path: body.path, offset: body.offset, limit: body.limit });\n sendJson(res, 200, result);\n } catch (err) {\n mapFsError(res, err);\n }\n}\n\nexport async function handleFsWrite(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n deps: FsRoutesDeps,\n authed: AuthenticatedIdentity | null,\n): Promise<void> {\n const pair = await readBodyAndResolveAgent(req, res, authed);\n if (pair === null) return;\n const [buf, agentId] = pair;\n\n const body = parseBody(buf) as { path: string; content: string; encoding?: 'utf8' | 'base64'; workspace?: string };\n const ctx = getFsCtx(deps, agentId, body.workspace);\n if (!ctx) { sendJson(res, 503, { error: 'fs-adapter-not-configured' }); return; }\n\n try {\n const result = await fsWrite(ctx, { path: body.path, content: body.content, encoding: body.encoding });\n sendJson(res, 200, result);\n } catch (err) {\n mapFsError(res, err);\n }\n}\n\nexport async function handleFsDelete(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n deps: FsRoutesDeps,\n authed: AuthenticatedIdentity | null,\n): Promise<void> {\n const pair = await readBodyAndResolveAgent(req, res, authed);\n if (pair === null) return;\n const [buf, agentId] = pair;\n\n const body = parseBody(buf) as { path: string; workspace?: string };\n const ctx = getFsCtx(deps, agentId, body.workspace);\n if (!ctx) { sendJson(res, 503, { error: 'fs-adapter-not-configured' }); return; }\n\n try {\n const result = await fsDelete(ctx, { path: body.path });\n sendJson(res, 200, result);\n } catch (err) {\n mapFsError(res, err);\n }\n}\n\nexport async function handleFsEdit(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n deps: FsRoutesDeps,\n authed: AuthenticatedIdentity | null,\n): Promise<void> {\n const pair = await readBodyAndResolveAgent(req, res, authed);\n if (pair === null) return;\n const [buf, agentId] = pair;\n\n const body = parseBody(buf) as {\n path: string;\n oldString: string;\n newString: string;\n replaceAll?: boolean;\n workspace?: string;\n };\n const ctx = getFsCtx(deps, agentId, body.workspace);\n if (!ctx) { sendJson(res, 503, { error: 'fs-adapter-not-configured' }); return; }\n\n try {\n const result = await fsEdit(ctx, {\n path: body.path,\n oldString: body.oldString,\n newString: body.newString,\n replaceAll: body.replaceAll,\n });\n sendJson(res, 200, result);\n } catch (err) {\n mapFsError(res, err);\n }\n}\n\nexport async function handleFsList(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n deps: FsRoutesDeps,\n authed: AuthenticatedIdentity | null,\n): Promise<void> {\n const pair = await readBodyAndResolveAgent(req, res, authed);\n if (pair === null) return;\n const [buf, agentId] = pair;\n\n const body = parseBody(buf) as { path: string; maxDepth?: number; workspace?: string };\n const ctx = getFsCtx(deps, agentId, body.workspace);\n if (!ctx) { sendJson(res, 503, { error: 'fs-adapter-not-configured' }); return; }\n\n try {\n const result = await fsList(ctx, { path: body.path, maxDepth: body.maxDepth });\n sendJson(res, 200, result);\n } catch (err) {\n mapFsError(res, err);\n }\n}\n\nexport async function handleFsSearch(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n deps: FsRoutesDeps,\n authed: AuthenticatedIdentity | null,\n): Promise<void> {\n const pair = await readBodyAndResolveAgent(req, res, authed);\n if (pair === null) return;\n const [buf, agentId] = pair;\n\n const body = parseBody(buf) as { query: string; path?: string; glob?: string; workspace?: string };\n const ctx = getFsCtx(deps, agentId, body.workspace);\n if (!ctx) { sendJson(res, 503, { error: 'fs-adapter-not-configured' }); return; }\n\n try {\n const result = await fsSearch(ctx, { query: body.query, path: body.path, glob: body.glob });\n sendJson(res, 200, result);\n } catch (err) {\n mapFsError(res, err);\n }\n}\n","// Agent route handlers — extracted from daemon-http.ts (Q1 split).\n\nimport type * as http from 'node:http';\nimport type { AgentSupervisor, AgentStatus } from '../agent-supervisor.js';\nimport type { EventBus } from '../event-bus.js';\nimport { sendJson, parseBody, readBody } from './helpers.js';\n\n// ============================================================\n// Deps interface\n// ============================================================\n\nexport interface AgentRoutesDeps {\n supervisor: AgentSupervisor;\n bus: EventBus;\n}\n\n// ============================================================\n// Body-read helper with 413/400 guard (I5)\n// ============================================================\n\nasync function readBodyOrFail(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n): Promise<Buffer | null> {\n try {\n return await readBody(req);\n } catch (err: unknown) {\n if (err instanceof Error && (err as Error & { code?: string }).code === 'E_TOO_LARGE') {\n sendJson(res, 413, { error: 'body-too-large', max: 10 * 1024 * 1024 });\n return null;\n }\n sendJson(res, 400, { error: 'read-error' });\n return null;\n }\n}\n\n// ============================================================\n// Handlers\n// ============================================================\n\nexport function handleAgentList(res: http.ServerResponse, deps: AgentRoutesDeps): void {\n sendJson(res, 200, { agents: deps.supervisor.list() });\n}\n\nexport function handleAgentGet(res: http.ServerResponse, id: string, deps: AgentRoutesDeps): void {\n const status: AgentStatus | undefined = deps.supervisor.get(id);\n if (status === undefined) {\n sendJson(res, 404, { error: 'not-found' });\n return;\n }\n sendJson(res, 200, status);\n}\n\nexport async function handleAgentRegister(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n deps: AgentRoutesDeps,\n): Promise<void> {\n const buf = await readBodyOrFail(req, res);\n if (buf === null) return;\n const body = buf.length > 0 ? parseBody(buf) : undefined;\n if (!body || typeof body !== 'object') {\n sendJson(res, 400, { error: 'bad-json' });\n return;\n }\n\n const input = body as Record<string, unknown>;\n const id = typeof input['id'] === 'string' ? input['id'] : undefined;\n const name = typeof input['name'] === 'string' ? input['name'] : id;\n const command = typeof input['command'] === 'string' ? input['command'] : undefined;\n if (!id || !name || !command) {\n sendJson(res, 400, { error: 'id-name-command-required' });\n return;\n }\n\n const args = Array.isArray(input['args'])\n ? input['args'].filter((arg): arg is string => typeof arg === 'string')\n : undefined;\n const cwd = typeof input['cwd'] === 'string' ? input['cwd'] : undefined;\n const attachPid = typeof input['attachPid'] === 'number' ? input['attachPid'] : undefined;\n\n try {\n const existing = deps.supervisor.get(id);\n if (existing !== undefined) {\n sendJson(res, 200, { ok: true, alreadyRegistered: true, agent: existing });\n return;\n }\n\n deps.supervisor.register({ id, name, command, args, cwd, attachPid });\n sendJson(res, 201, { ok: true, agent: deps.supervisor.get(id) });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n sendJson(res, 409, { ok: false, error: message });\n }\n}\n\nexport async function handleAgentMessage(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n agentId: string,\n deps: AgentRoutesDeps,\n): Promise<void> {\n const buf = await readBodyOrFail(req, res);\n if (buf === null) return;\n const body = parseBody(buf);\n if (body === undefined) {\n sendJson(res, 400, { error: 'bad-json' });\n return;\n }\n const { type, payload } = body as { type: string; payload: unknown };\n deps.bus.publish('agent.message.in', { agentId, type, payload }, { source: 'http' });\n sendJson(res, 200, { ok: true });\n}\n\nexport async function handleAgentStop(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n agentId: string,\n deps: AgentRoutesDeps,\n): Promise<void> {\n const buf = await readBodyOrFail(req, res);\n if (buf === null) return;\n\n const body = buf.length > 0 ? parseBody(buf) : {};\n const reason = (body as { reason?: string })?.reason;\n\n const timeoutHandle = setTimeout(() => {\n if (!res.headersSent) {\n sendJson(res, 202, {\n accepted: true,\n note: 'stop initiated but agent not yet stopped — poll for status',\n });\n }\n }, 1000);\n\n try {\n await deps.supervisor.stop(agentId, reason);\n clearTimeout(timeoutHandle);\n if (!res.headersSent) {\n sendJson(res, 200, { ok: true });\n }\n } catch (err: unknown) {\n clearTimeout(timeoutHandle);\n if (!res.headersSent) {\n const msg = err instanceof Error ? err.message : String(err);\n sendJson(res, 404, { error: 'not-found', message: msg });\n }\n }\n}\n\nexport async function handleAgentApprove(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n agentId: string,\n deps: AgentRoutesDeps,\n): Promise<void> {\n const buf = await readBodyOrFail(req, res);\n if (buf === null) return;\n const body = parseBody(buf);\n if (body === undefined) {\n sendJson(res, 400, { error: 'bad-json' });\n return;\n }\n const { requestId, decision, scope } = body as {\n requestId: string;\n decision: 'allow' | 'deny';\n scope?: 'once' | 'session' | 'always';\n };\n deps.bus.publish('permission.decided', { agentId, requestId, decision, scope }, { source: 'http' });\n sendJson(res, 200, { ok: true });\n}\n","import * as crypto from 'node:crypto';\n\nexport interface PairOfferRecord {\n offer: string;\n uri: string;\n expiresAt: number;\n createdAt: number;\n paired: boolean;\n bindingId?: string;\n deviceName?: string;\n transport?: 'lan' | 'relay';\n clientPubKey?: string;\n}\n\nexport interface PairingStatus {\n paired: boolean;\n expired: boolean;\n bindingId?: string;\n deviceName?: string;\n transport?: 'lan' | 'relay';\n}\n\nconst DEFAULT_TTL_SEC = 300;\nconst MAX_TTL_SEC = 15 * 60;\n\nexport class PairingManager {\n private readonly offers = new Map<string, PairOfferRecord>();\n\n createOffer(ttlSec = DEFAULT_TTL_SEC): PairOfferRecord {\n this.cleanExpired();\n\n const safeTtlSec = Number.isFinite(ttlSec)\n ? Math.max(1, Math.min(Math.floor(ttlSec), MAX_TTL_SEC))\n : DEFAULT_TTL_SEC;\n const offer = crypto.randomBytes(24).toString('base64url');\n const record: PairOfferRecord = {\n offer,\n uri: `prismer://pair?offer=${encodeURIComponent(offer)}`,\n createdAt: Date.now(),\n expiresAt: Date.now() + safeTtlSec * 1000,\n paired: false,\n };\n this.offers.set(offer, record);\n return { ...record };\n }\n\n getStatus(offer: string): PairingStatus | null {\n const record = this.offers.get(offer);\n if (!record) return null;\n\n const expired = Date.now() > record.expiresAt;\n return {\n paired: record.paired,\n expired,\n bindingId: record.bindingId,\n deviceName: record.deviceName,\n transport: record.transport,\n };\n }\n\n confirm(\n offer: string,\n input: {\n bindingId?: string;\n deviceName?: string;\n transport?: 'lan' | 'relay';\n clientPubKey?: string;\n } = {},\n ): PairingStatus {\n const record = this.offers.get(offer);\n if (!record) {\n throw Object.assign(new Error('Pairing offer not found'), { status: 404 });\n }\n if (Date.now() > record.expiresAt) {\n throw Object.assign(new Error('Pairing offer expired'), { status: 410 });\n }\n\n record.paired = true;\n record.bindingId = input.bindingId ?? record.bindingId ?? crypto.randomUUID();\n record.deviceName = input.deviceName ?? record.deviceName ?? 'Paired Device';\n record.transport = input.transport ?? record.transport ?? 'lan';\n record.clientPubKey = input.clientPubKey ?? record.clientPubKey;\n return this.getStatus(offer)!;\n }\n\n cleanExpired(): void {\n const now = Date.now();\n for (const [offer, record] of this.offers) {\n if (!record.paired && now > record.expiresAt) {\n this.offers.delete(offer);\n }\n }\n }\n}\n","/**\n * Prismer Runtime — Evolution Gateway HTTP API\n *\n * Exposes evolution gateway operations via HTTP for daemon process.\n * Integrates with LLM Dispatcher for distillation triggers.\n *\n * Endpoints:\n * - POST /evolution/signal — Extract signals from tool output / log\n * - POST /evolution/record — Record gene execution outcome\n * - POST /evolution/analyze — Analyze signals and recommend gene\n * - POST /evolution/genes — Create new gene\n * - GET /evolution/genes — Query available genes\n * - GET /evolution/personality — Get agent personality\n * - POST /evolution/distill — Trigger distillation\n *\n * @see docs/version190/IMPLEMENTATION-PLAN-RUNTIME-GAP.md\n */\n\nimport type { EventBus } from './event-bus.js';\nimport type { LLMDispatcher } from './llm-dispatcher.js';\nimport type { AgentSupervisor } from './agent-supervisor.js';\nimport type { RouteHandler, AuthenticatedIdentity } from './daemon-http.js';\nimport { readBody, sendJson, extractBearer } from './http/helpers.js';\n\n// ============================================================\n// Public Types\n// ============================================================\n\nexport interface EvolutionGatewayOptions {\n eventBus: EventBus;\n supervisor: AgentSupervisor;\n llmDispatcher?: LLMDispatcher;\n /** Cloud API base URL (default: https://prismer.cloud) */\n cloudApiBase?: string;\n /** Authenticated identity (from Bearer token or API key) */\n authenticate?: (bearerToken: string | undefined) => AuthenticatedIdentity | null;\n /**\n * v1.9.0 B.7.a — API key used as the Bearer token when forwarding daemon\n * requests to the cloud Evolution API. When undefined, outbound requests\n * omit the Authorization header (callers get 401 from cloud until the\n * daemon is started with `apiKey`).\n */\n cloudApiKey?: string;\n}\n\nexport interface SignalExtractionRequest {\n toolOutput?: {\n toolName?: string;\n output?: string;\n exitCode?: number;\n error?: string;\n durationMs?: number;\n };\n logFile?: {\n logPath?: string;\n logContent?: string;\n timestamp?: string;\n };\n provider?: string;\n stage?: string;\n severity?: string;\n tags?: string[];\n}\n\nexport interface AnalyzeRequest {\n signals: string[];\n taskCapability?: string;\n provider?: string;\n stage?: string;\n severity?: string;\n}\n\nexport interface RecordRequest {\n geneId: string;\n signals: string[];\n outcome: 'success' | 'failed';\n score?: number;\n summary?: string;\n costCredits?: number;\n transitionReason?: 'gene_applied' | 'fallback_relaxed' | 'fallback_neighbor' | 'baseline';\n}\n\nexport interface CreateGeneRequest {\n category: 'repair' | 'optimize' | 'innovate' | 'diagnostic';\n signalsMatch: string[];\n strategy: string[];\n preconditions?: string[];\n constraints?: {\n maxCredits?: number;\n maxRetries?: number;\n maxExecutionTime?: number;\n };\n}\n\nexport interface DistillationRequest {\n /** Skip LLM verification and trigger immediately */\n dryRun?: boolean;\n}\n\n// ============================================================\n// Evolution Gateway HTTP Handler\n// ============================================================\n\nexport class EvolutionGatewayHttpHandler {\n private readonly eventBus: EventBus;\n private readonly supervisor: AgentSupervisor;\n private readonly llmDispatcher: LLMDispatcher | undefined;\n private readonly cloudApiBase: string;\n private readonly authenticate: EvolutionGatewayOptions['authenticate'];\n private readonly cloudApiKey: string | undefined;\n\n // Route registry\n private readonly routes = new Map<string, RouteHandler>();\n\n constructor(opts: EvolutionGatewayOptions) {\n this.eventBus = opts.eventBus;\n this.supervisor = opts.supervisor;\n this.llmDispatcher = opts.llmDispatcher;\n this.cloudApiBase = (opts.cloudApiBase || 'https://prismer.cloud').replace(/\\/api\\/?$/, '');\n this.authenticate = opts.authenticate;\n this.cloudApiKey = opts.cloudApiKey;\n\n this.registerRoutes();\n }\n\n private cloudAuthHeaders(agentId: string, extra: Record<string, string> = {}): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Prismer-AgentId': agentId,\n ...extra,\n };\n if (this.cloudApiKey !== undefined && this.cloudApiKey.length > 0) {\n headers['Authorization'] = `Bearer ${this.cloudApiKey}`;\n }\n return headers;\n }\n\n // ============================================================\n // Route Registration\n // ============================================================\n\n private registerRoutes(): void {\n // POST /evolution/signal — Extract signals\n this.routes.set('POST:/evolution/signal', this.handleExtractSignal.bind(this));\n\n // POST /evolution/analyze — Analyze signals and recommend gene\n this.routes.set('POST:/evolution/analyze', this.handleAnalyze.bind(this));\n\n // POST /evolution/record — Record gene execution outcome\n this.routes.set('POST:/evolution/record', this.handleRecord.bind(this));\n\n // POST /evolution/genes — Create new gene\n this.routes.set('POST:/evolution/genes', this.handleCreateGene.bind(this));\n\n // GET /evolution/genes — Query available genes\n this.routes.set('GET:/evolution/genes', this.handleQueryGenes.bind(this));\n\n // GET /evolution/personality — Get agent personality\n this.routes.set('GET:/evolution/personality', this.handleGetPersonality.bind(this));\n\n // POST /evolution/distill — Trigger distillation\n this.routes.set('POST:/evolution/distill', this.handleDistill.bind(this));\n\n // GET /evolution/unmatched — Get unmatched signals\n this.routes.set('GET:/evolution/unmatched', this.handleGetUnmatched.bind(this));\n }\n\n // ============================================================\n // Public API\n // ============================================================\n\n /** Get all registered routes */\n getRoutes(): Map<string, RouteHandler> {\n return new Map(this.routes);\n }\n\n /** Get a specific route handler */\n getRoute(method: string, path: string): RouteHandler | undefined {\n return this.routes.get(`${method}:${path}`);\n }\n\n // ============================================================\n // Route Handlers\n // ============================================================\n\n /**\n * POST /evolution/signal\n * Extract signals from tool output or log file.\n */\n private async handleExtractSignal(\n _req: import('node:http').IncomingMessage,\n res: import('node:http').ServerResponse,\n ctx: { authed: AuthenticatedIdentity | null; body: Buffer },\n ): Promise<void> {\n try {\n // Parse request body\n const body = JSON.parse(ctx.body.toString()) as SignalExtractionRequest;\n\n // Validate request\n if (!body.toolOutput && !body.logFile) {\n return sendJson(res, 400, {\n ok: false,\n error: 'Either toolOutput or logFile must be provided',\n });\n }\n\n // Extract signals locally (no cloud call needed)\n const signals = this.extractSignalsLocal(body);\n\n // Publish event to event bus\n await this.eventBus.publish('evolution:signal_extracted', {\n agentId: ctx.authed?.agentId,\n signals,\n source: body.toolOutput ? 'tool_output' : 'log_file',\n extractedAt: new Date().toISOString(),\n });\n\n sendJson(res, 200, {\n ok: true,\n data: signals,\n processedAt: new Date().toISOString(),\n });\n } catch (err) {\n console.error('[EvolutionGateway] Signal extraction error:', (err as Error).message);\n sendJson(res, 500, {\n ok: false,\n error: `Signal extraction failed: ${(err as Error).message}`,\n });\n }\n }\n\n /**\n * POST /evolution/analyze\n * Analyze signals and recommend the best gene.\n */\n private async handleAnalyze(\n _req: import('node:http').IncomingMessage,\n res: import('node:http').ServerResponse,\n ctx: { authed: AuthenticatedIdentity | null; body: Buffer },\n ): Promise<void> {\n if (!ctx.authed) {\n return sendJson(res, 401, { ok: false, error: 'Unauthorized' });\n }\n\n try {\n const body = JSON.parse(ctx.body.toString()) as AnalyzeRequest;\n\n // Validate request\n if (!body.signals || !Array.isArray(body.signals)) {\n return sendJson(res, 400, {\n ok: false,\n error: 'signals array is required',\n });\n }\n\n // Call Cloud IM API\n const advice = await this.callCloudAnalyze(body, ctx.authed.agentId);\n\n sendJson(res, 200, {\n ok: true,\n data: advice,\n processedAt: new Date().toISOString(),\n });\n } catch (err) {\n console.error('[EvolutionGateway] Analyze error:', (err as Error).message);\n sendJson(res, 500, {\n ok: false,\n error: `Analysis failed: ${(err as Error).message}`,\n });\n }\n }\n\n /**\n * POST /evolution/record\n * Record gene execution outcome.\n */\n private async handleRecord(\n _req: import('node:http').IncomingMessage,\n res: import('node:http').ServerResponse,\n ctx: { authed: AuthenticatedIdentity | null; body: Buffer },\n ): Promise<void> {\n if (!ctx.authed) {\n return sendJson(res, 401, { ok: false, error: 'Unauthorized' });\n }\n\n try {\n const body = JSON.parse(ctx.body.toString()) as RecordRequest;\n\n // Validate request\n if (!body.geneId || !body.outcome) {\n return sendJson(res, 400, {\n ok: false,\n error: 'geneId and outcome are required',\n });\n }\n\n // Call Cloud IM API\n const result = await this.callCloudRecord(body, ctx.authed.agentId);\n\n // Publish event to event bus\n await this.eventBus.publish('evolution:outcome_recorded', {\n agentId: ctx.authed.agentId,\n geneId: body.geneId,\n outcome: body.outcome,\n recordedAt: new Date().toISOString(),\n });\n\n sendJson(res, 200, {\n ok: true,\n data: result,\n recordedAt: new Date().toISOString(),\n });\n } catch (err) {\n console.error('[EvolutionGateway] Record error:', (err as Error).message);\n sendJson(res, 500, {\n ok: false,\n error: `Recording failed: ${(err as Error).message}`,\n });\n }\n }\n\n /**\n * POST /evolution/genes\n * Create a new gene.\n */\n private async handleCreateGene(\n _req: import('node:http').IncomingMessage,\n res: import('node:http').ServerResponse,\n ctx: { authed: AuthenticatedIdentity | null; body: Buffer },\n ): Promise<void> {\n if (!ctx.authed) {\n return sendJson(res, 401, { ok: false, error: 'Unauthorized' });\n }\n\n try {\n const body = JSON.parse(ctx.body.toString()) as CreateGeneRequest;\n\n // Validate request\n if (!body.category || !body.signalsMatch || !body.strategy) {\n return sendJson(res, 400, {\n ok: false,\n error: 'category, signalsMatch, and strategy are required',\n });\n }\n\n // Call Cloud IM API\n const gene = await this.callCloudCreateGene(body, ctx.authed.agentId);\n\n // Publish event to event bus\n await this.eventBus.publish('evolution:gene_created', {\n agentId: ctx.authed.agentId,\n geneId: (gene as { id?: string }).id,\n category: body.category,\n createdAt: new Date().toISOString(),\n });\n\n sendJson(res, 200, {\n ok: true,\n data: gene,\n createdAt: new Date().toISOString(),\n });\n } catch (err) {\n console.error('[EvolutionGateway] Create gene error:', (err as Error).message);\n sendJson(res, 500, {\n ok: false,\n error: `Gene creation failed: ${(err as Error).message}`,\n });\n }\n }\n\n /**\n * GET /evolution/genes\n * Query available genes.\n */\n private async handleQueryGenes(\n _req: import('node:http').IncomingMessage,\n res: import('node:http').ServerResponse,\n ctx: { authed: AuthenticatedIdentity | null; body: Buffer },\n ): Promise<void> {\n if (!ctx.authed) {\n return sendJson(res, 401, { ok: false, error: 'Unauthorized' });\n }\n\n try {\n // Call Cloud IM API\n const genes = await this.callCloudQueryGenes(ctx.authed.agentId);\n\n sendJson(res, 200, {\n ok: true,\n data: genes,\n queriedAt: new Date().toISOString(),\n });\n } catch (err) {\n console.error('[EvolutionGateway] Query genes error:', (err as Error).message);\n sendJson(res, 500, {\n ok: false,\n error: `Query failed: ${(err as Error).message}`,\n });\n }\n }\n\n /**\n * GET /evolution/personality\n * Get agent personality.\n */\n private async handleGetPersonality(\n _req: import('node:http').IncomingMessage,\n res: import('node:http').ServerResponse,\n ctx: { authed: AuthenticatedIdentity | null; body: Buffer },\n ): Promise<void> {\n if (!ctx.authed) {\n return sendJson(res, 401, { ok: false, error: 'Unauthorized' });\n }\n\n try {\n // Call Cloud IM API\n const personality = await this.callCloudGetPersonality(ctx.authed.agentId);\n\n sendJson(res, 200, {\n ok: true,\n data: personality,\n retrievedAt: new Date().toISOString(),\n });\n } catch (err) {\n console.error('[EvolutionGateway] Get personality error:', (err as Error).message);\n sendJson(res, 500, {\n ok: false,\n error: `Failed to get personality: ${(err as Error).message}`,\n });\n }\n }\n\n /**\n * POST /evolution/distill\n * Trigger gene distillation.\n */\n private async handleDistill(\n _req: import('node:http').IncomingMessage,\n res: import('node:http').ServerResponse,\n ctx: { authed: AuthenticatedIdentity | null; body: Buffer },\n ): Promise<void> {\n if (!ctx.authed) {\n return sendJson(res, 401, { ok: false, error: 'Unauthorized' });\n }\n\n try {\n const body = JSON.parse(ctx.body.toString()) as DistillationRequest;\n\n // Call Cloud IM API (or local distillation if LLM dispatcher available)\n const triggered = this.llmDispatcher\n ? await this.triggerLocalDistillation(ctx.authed.agentId, body.dryRun)\n : await this.callCloudDistill(ctx.authed.agentId);\n\n // Publish event to event bus\n await this.eventBus.publish('evolution:distillation_triggered', {\n agentId: ctx.authed.agentId,\n triggered,\n triggeredAt: new Date().toISOString(),\n });\n\n sendJson(res, 200, {\n ok: true,\n data: { triggered },\n triggeredAt: new Date().toISOString(),\n });\n } catch (err) {\n console.error('[EvolutionGateway] Distillation error:', (err as Error).message);\n sendJson(res, 500, {\n ok: false,\n error: `Distillation failed: ${(err as Error).message}`,\n });\n }\n }\n\n /**\n * GET /evolution/unmatched\n * Get unmatched signals (evolution frontier).\n */\n private async handleGetUnmatched(\n _req: import('node:http').IncomingMessage,\n res: import('node:http').ServerResponse,\n ctx: { authed: AuthenticatedIdentity | null; body: Buffer },\n ): Promise<void> {\n if (!ctx.authed) {\n return sendJson(res, 401, { ok: false, error: 'Unauthorized' });\n }\n\n try {\n // Call Cloud IM API\n const unmatched = await this.callCloudGetUnmatched();\n\n sendJson(res, 200, {\n ok: true,\n data: unmatched,\n retrievedAt: new Date().toISOString(),\n });\n } catch (err) {\n console.error('[EvolutionGateway] Get unmatched error:', (err as Error).message);\n sendJson(res, 500, {\n ok: false,\n error: `Failed to get unmatched signals: ${(err as Error).message}`,\n });\n }\n }\n\n // ============================================================\n // Cloud API Integration\n // ============================================================\n\n private async parseCloudResponse(response: Response): Promise<unknown> {\n const text = await response.text();\n\n if (!response.ok) {\n throw new Error(`Cloud API error (${response.status}): ${text}`);\n }\n\n const json = text ? JSON.parse(text) : {};\n if (json?.ok === false) {\n throw new Error(typeof json.error === 'string' ? json.error : JSON.stringify(json.error));\n }\n return json?.data ?? json;\n }\n\n private async callCloudAnalyze(body: AnalyzeRequest, agentId: string): Promise<unknown> {\n const url = `${this.cloudApiBase}/api/im/evolution/analyze`;\n const response = await fetch(url, {\n method: 'POST',\n headers: this.cloudAuthHeaders(agentId),\n body: JSON.stringify({\n signals: body.signals,\n task_capability: body.taskCapability,\n tags: [],\n provider: body.provider,\n stage: body.stage,\n severity: body.severity,\n }),\n });\n\n return await this.parseCloudResponse(response);\n }\n\n private async callCloudRecord(body: RecordRequest, agentId: string): Promise<unknown> {\n const url = `${this.cloudApiBase}/api/im/evolution/record`;\n const response = await fetch(url, {\n method: 'POST',\n headers: this.cloudAuthHeaders(agentId),\n body: JSON.stringify({\n gene_id: body.geneId,\n signals: body.signals,\n outcome: body.outcome,\n score: body.score,\n summary: body.summary,\n cost_credits: body.costCredits,\n transition_reason: body.transitionReason,\n }),\n });\n\n return await this.parseCloudResponse(response);\n }\n\n private async callCloudCreateGene(body: CreateGeneRequest, agentId: string): Promise<unknown> {\n const url = `${this.cloudApiBase}/api/im/evolution/genes`;\n const response = await fetch(url, {\n method: 'POST',\n headers: this.cloudAuthHeaders(agentId),\n body: JSON.stringify({\n category: body.category,\n signals_match: body.signalsMatch,\n strategy: body.strategy,\n preconditions: body.preconditions || [],\n constraints: body.constraints,\n }),\n });\n\n return await this.parseCloudResponse(response);\n }\n\n private async callCloudQueryGenes(agentId: string): Promise<unknown> {\n const url = `${this.cloudApiBase}/api/im/evolution/genes`;\n const response = await fetch(url, {\n method: 'GET',\n headers: this.cloudAuthHeaders(agentId),\n });\n\n return await this.parseCloudResponse(response);\n }\n\n private async callCloudGetPersonality(agentId: string): Promise<unknown> {\n const url = `${this.cloudApiBase}/api/im/evolution/personality/${encodeURIComponent(agentId)}`;\n const response = await fetch(url, {\n method: 'GET',\n headers: this.cloudAuthHeaders(agentId),\n });\n\n const data = await this.parseCloudResponse(response);\n return (data as { personality?: unknown }).personality ?? data;\n }\n\n private async callCloudDistill(agentId: string): Promise<boolean> {\n const url = `${this.cloudApiBase}/api/im/evolution/distill`;\n const response = await fetch(url, {\n method: 'POST',\n headers: this.cloudAuthHeaders(agentId),\n });\n\n const data = await this.parseCloudResponse(response);\n if (typeof data === 'boolean') return data;\n return Boolean((data as { triggered?: boolean }).triggered);\n }\n\n private async callCloudGetUnmatched(): Promise<unknown> {\n // Public endpoint — no AgentId, but Bearer still forwarded when available\n // so rate limits are tracked per-installation rather than per-IP.\n const url = `${this.cloudApiBase}/api/im/evolution/public/unmatched?limit=20`;\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (this.cloudApiKey !== undefined && this.cloudApiKey.length > 0) {\n headers['Authorization'] = `Bearer ${this.cloudApiKey}`;\n }\n const response = await fetch(url, { method: 'GET', headers });\n\n return await this.parseCloudResponse(response);\n }\n\n // ============================================================\n // Local Distillation (with LLM Dispatcher)\n // ============================================================\n\n private async triggerLocalDistillation(agentId: string, dryRun = false): Promise<boolean> {\n if (!this.llmDispatcher) {\n throw new Error('LLM Dispatcher not available for local distillation');\n }\n\n console.log(`[EvolutionGateway] Triggering local distillation for agent ${agentId} (dryRun=${dryRun})`);\n\n if (dryRun) {\n // Just check readiness\n return await this.callCloudDistill(agentId);\n }\n\n // TODO: Implement full local distillation pipeline\n // 1. Fetch success capsules\n // 2. Prepare LLM prompt\n // 3. Call LLM Dispatcher\n // 4. Parse and create new genes\n console.warn('[EvolutionGateway] Local distillation not yet implemented, falling back to cloud');\n return await this.callCloudDistill(agentId);\n }\n\n // ============================================================\n // Local Signal Extraction (no cloud call)\n // ============================================================\n\n private extractSignalsLocal(req: SignalExtractionRequest): string[] {\n const signals: string[] = [];\n\n // Extract from tool output\n if (req.toolOutput) {\n const output = req.toolOutput.output || '';\n const error = req.toolOutput.error || '';\n\n // Simple regex patterns (16 patterns from signal-extract.ts)\n const patterns: Array<[RegExp, string]> = [\n [/timeout|timed out/i, 'error:timeout'],\n [/econnrefused|connection refused/i, 'error:connection_refused'],\n [/enotfound|dns/i, 'error:dns_error'],\n [/rate.?limit|429/i, 'error:rate_limit'],\n [/unauthorized|401/i, 'error:auth_error'],\n [/forbidden|403/i, 'error:forbidden'],\n [/not.?found|404/i, 'error:not_found'],\n [/500|internal server/i, 'error:server_error'],\n [/typeerror/i, 'error:type_error'],\n [/syntaxerror/i, 'error:syntax_error'],\n [/referenceerror/i, 'error:reference_error'],\n [/out of memory|oom/i, 'error:oom'],\n [/crashloopbackoff|crash.?loop/i, 'error:crash_loop'],\n [/evicted|quota/i, 'error:resource_quota'],\n [/certificate|ssl|tls/i, 'error:tls_error'],\n [/deadlock/i, 'error:deadlock'],\n ];\n\n const text = `${output} ${error}`;\n for (const [pattern, signalType] of patterns) {\n if (pattern.test(text)) {\n const signal = req.provider ? `${signalType}|provider=${req.provider}` : signalType;\n if (!signals.includes(signal)) {\n signals.push(signal);\n }\n }\n }\n\n // Exit code signal\n if (req.toolOutput.exitCode && req.toolOutput.exitCode !== 0) {\n signals.push(`exit_error|exitCode=${req.toolOutput.exitCode}`);\n }\n\n // Duration signal (slow operation)\n if (req.toolOutput.durationMs && req.toolOutput.durationMs > 10_000) {\n signals.push(`perf:slow_operation|duration=${req.toolOutput.durationMs}ms`);\n }\n }\n\n // Add custom tags\n if (req.tags) {\n for (const tag of req.tags) {\n signals.push(`tag:${tag}`);\n }\n }\n\n return signals;\n }\n}\n","/**\n * Prismer Runtime — Task Router\n *\n * v1.9.0 Task Router: HTTP API for routing tasks to agents,\n * capability matching, and SSE streaming of task state changes.\n *\n * Integrates with:\n * - Cloud API (/api/im/tasks) for persistent task store\n * - AgentSupervisor for local agent status\n * - EventBus for SSE streaming\n *\n * Design reference: docs/version190/IMPLEMENTATION-PLAN-RUNTIME-GAP.md §P1\n */\n\nimport * as http from 'node:http';\nimport type { EventBus } from './event-bus.js';\nimport type { AgentSupervisor } from './agent-supervisor.js';\nimport { sendJson } from './http/helpers.js';\nimport { handleSse } from './http/sse.js';\nimport type { SseDeps } from './http/sse.js';\nimport type { RouteHandler } from './daemon-http.js';\n\n// ─── State Enum (§16.4) ───────────────────────────────\n\n/**\n * Task routing state machine per §16.4.\n *\n * State transitions:\n * created → dispatching → step_running → step_completed → (next step or completed)\n * step_running → step_failed → retrying (×3) → retry_exhausted → needs_human\n * step_running → step_timeout → rerouting → step_running (new agent)\n */\nexport enum TaskRouteState {\n Created = 'created',\n Dispatching = 'dispatching',\n StepRunning = 'step_running',\n StepCompleted = 'step_completed',\n StepFailed = 'step_failed',\n StepTimeout = 'step_timeout',\n Retrying = 'retrying',\n RetryExhausted = 'retry_exhausted',\n NeedsHuman = 'needs_human',\n Rerouting = 'rerouting',\n Completed = 'completed',\n Cancelled = 'cancelled',\n}\n\nconst MAX_STEP_RETRIES = 3;\n\n// ─── Types ─────────────────────────────────────────────\n\nexport interface TaskRouterOptions {\n eventBus: EventBus;\n supervisor: AgentSupervisor;\n cloudBaseUrl?: string; // default: https://prismer.cloud\n apiToken?: string; // Prismer API key for Cloud API calls\n}\n\nexport interface TaskInfo {\n id: string;\n title: string;\n status: TaskRouteState | string; // allow string for backwards compat with cloud API\n requiresCapability?: string | null;\n runtimeRoute?: unknown[] | null;\n assigneeId?: string | null;\n progress?: number | null;\n statusMessage?: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface RouteTaskRequest {\n taskId?: string;\n priority?: 'high' | 'normal' | 'low';\n preferredAgentId?: string;\n}\n\nexport interface RouteTaskResponse {\n taskId: string;\n agentId: string;\n capability: string;\n stepIdx: number;\n totalSteps: number;\n}\n\nexport interface AssignTaskRequest {\n agentId: string;\n taskId?: string;\n}\n\nexport interface StepCompletedRequest {\n taskId?: string;\n stepId: string;\n result?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n}\n\nexport interface CancelTaskRequest {\n taskId?: string;\n reason: string;\n}\n\nexport interface StepFailedRequest {\n taskId?: string;\n stepId: string;\n error?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface StepTimeoutRequest {\n taskId?: string;\n stepId: string;\n capability?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface AuthenticatedIdentity {\n agentId: string;\n bearerSub?: string;\n}\n\n// ─── TaskRouter ─────────────────────────────────────\n\nexport class TaskRouter {\n private readonly _bus: EventBus;\n private readonly _supervisor: AgentSupervisor;\n private readonly _cloudBaseUrl: string;\n private readonly _apiToken: string | undefined;\n\n private _sseClients = new Set<http.ServerResponse>();\n /** Per-step retry counters: key = `${taskId}:${stepId}` */\n private readonly _retryCounters = new Map<string, number>();\n\n constructor(opts: TaskRouterOptions) {\n this._bus = opts.eventBus;\n this._supervisor = opts.supervisor;\n this._cloudBaseUrl = opts.cloudBaseUrl ?? 'https://prismer.cloud';\n this._apiToken = opts.apiToken;\n }\n\n /**\n * Register HTTP routes with the daemon server.\n * Call this from daemon-http.ts to expose task router endpoints.\n */\n registerRoutes(server: {\n registerRoute: (\n method: 'GET' | 'POST' | 'PATCH' | 'DELETE',\n path: string,\n handler: RouteHandler,\n ) => void;\n }): void {\n // POST /tasks/:id/route — Route task to optimal agent\n server.registerRoute('POST', '/tasks/:id/route', async (req, res, ctx) => {\n await this._handleRouteTask(req, res, ctx.body);\n });\n\n // POST /tasks/:id/assign — Manually assign task to specific agent\n server.registerRoute('POST', '/tasks/:id/assign', async (req, res, ctx) => {\n await this._handleAssignTask(req, res, ctx.body);\n });\n\n // POST /tasks/:id/step-completed — Record step completion\n server.registerRoute('POST', '/tasks/:id/step-completed', async (req, res, ctx) => {\n await this._handleStepCompleted(req, res, ctx.body);\n });\n\n // POST /tasks/:id/cancel — Cancel a task\n server.registerRoute('POST', '/tasks/:id/cancel', async (req, res, ctx) => {\n await this._handleCancelTask(req, res, ctx.body);\n });\n\n // POST /tasks/:id/step-failed — Record step failure with retry logic\n server.registerRoute('POST', '/tasks/:id/step-failed', async (req, res, ctx) => {\n await this._handleStepFailed(req, res, ctx.body);\n });\n\n // POST /tasks/:id/step-timeout — Handle step timeout with rerouting\n server.registerRoute('POST', '/tasks/:id/step-timeout', async (req, res, ctx) => {\n await this._handleStepTimeout(req, res, ctx.body);\n });\n\n // GET /tasks/:id — Get task details\n server.registerRoute('GET', '/tasks/:id', async (req, res) => {\n await this._handleGetTask(req, res);\n });\n\n // GET /tasks — List tasks (filtered by status, agent, capability)\n server.registerRoute('GET', '/tasks', async (req, res) => {\n await this._handleListTasks(req, res);\n });\n\n // GET /tasks/events — SSE stream for task state changes\n server.registerRoute('GET', '/tasks/events', async (req, res) => {\n const url = new URL(req.url ?? '/', 'http://localhost');\n const sseDeps: SseDeps = {\n bus: this._bus,\n sseClients: this._sseClients,\n };\n await handleSse(req, res, url, sseDeps);\n });\n }\n\n // ─── Route Handlers ─────────────────────────────────\n\n private async _handleRouteTask(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n requestBody: Buffer,\n ): Promise<void> {\n try {\n // Extract taskId from URL path\n const match = req.url?.match(/\\/tasks\\/([^/]+)\\/route/);\n if (!match) {\n return sendJson(res, 400, { error: 'invalid-url' });\n }\n const taskId = match[1];\n\n const input: RouteTaskRequest = requestBody.length\n ? JSON.parse(requestBody.toString('utf8'))\n : {};\n\n // Validate input\n if (input.taskId !== undefined && input.taskId !== taskId) {\n return sendJson(res, 400, { error: 'taskId-mismatch' });\n }\n\n // Publish dispatching state before calling cloud API\n this._publishState(taskId, TaskRouteState.Dispatching);\n\n // Call Cloud API to route task\n const cloudResult = await this._callCloudApi(\n `/tasks/${taskId}/route`,\n 'POST',\n { ...input, taskId } as unknown as Record<string, unknown>,\n );\n\n if (!cloudResult.ok) {\n return sendJson(res, cloudResult.status || 500, {\n error: 'route-failed',\n message: cloudResult.error,\n });\n }\n\n // Emit routed event to local agents (backwards compat)\n const response = cloudResult.data as RouteTaskResponse;\n this._bus.publish('task.routed', {\n taskId: response.taskId,\n agentId: response.agentId,\n capability: response.capability,\n stepIdx: response.stepIdx,\n totalSteps: response.totalSteps,\n });\n\n // Publish step_running state\n this._publishState(taskId, TaskRouteState.StepRunning, {\n agentId: response.agentId,\n capability: response.capability,\n stepIdx: response.stepIdx,\n totalSteps: response.totalSteps,\n });\n\n sendJson(res, 200, response);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n sendJson(res, 500, { error: 'internal', message: msg });\n }\n }\n\n private async _handleAssignTask(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n requestBody: Buffer,\n ): Promise<void> {\n try {\n const match = req.url?.match(/\\/tasks\\/([^/]+)\\/assign/);\n if (!match) {\n return sendJson(res, 400, { error: 'invalid-url' });\n }\n const taskId = match[1];\n\n const input: AssignTaskRequest = requestBody.length\n ? JSON.parse(requestBody.toString('utf8'))\n : ({} as AssignTaskRequest);\n\n // Validate input\n if (input.taskId !== undefined && input.taskId !== taskId) {\n return sendJson(res, 400, { error: 'taskId-mismatch' });\n }\n if (!input.agentId) {\n return sendJson(res, 400, { error: 'agentId-required' });\n }\n\n // Verify agent exists locally\n const agentStatus = this._supervisor.get(input.agentId);\n if (!agentStatus) {\n return sendJson(res, 404, { error: 'agent-not-found' });\n }\n\n // Call Cloud API to assign task\n const cloudResult = await this._callCloudApi(\n `/tasks/${taskId}/assign`,\n 'POST',\n { ...input, taskId } as unknown as Record<string, unknown>,\n );\n\n if (!cloudResult.ok) {\n return sendJson(res, cloudResult.status || 500, {\n error: 'assign-failed',\n message: cloudResult.error,\n });\n }\n\n // Emit assigned event\n this._bus.publish('task.assigned', {\n taskId,\n agentId: input.agentId,\n });\n\n sendJson(res, 200, cloudResult.data);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n sendJson(res, 500, { error: 'internal', message: msg });\n }\n }\n\n private async _handleStepCompleted(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n requestBody: Buffer,\n ): Promise<void> {\n try {\n const match = req.url?.match(/\\/tasks\\/([^/]+)\\/step-completed/);\n if (!match) {\n return sendJson(res, 400, { error: 'invalid-url' });\n }\n const taskId = match[1];\n\n const input: StepCompletedRequest = requestBody.length\n ? JSON.parse(requestBody.toString('utf8'))\n : ({} as StepCompletedRequest);\n\n // Validate input\n if (input.taskId !== undefined && input.taskId !== taskId) {\n return sendJson(res, 400, { error: 'taskId-mismatch' });\n }\n if (!input.stepId) {\n return sendJson(res, 400, { error: 'stepId-required' });\n }\n\n // Call Cloud API to record step completion\n const cloudResult = await this._callCloudApi(\n `/tasks/${taskId}/step-completed`,\n 'POST',\n { ...input, taskId } as unknown as Record<string, unknown>,\n );\n\n if (!cloudResult.ok) {\n return sendJson(res, cloudResult.status || 500, {\n error: 'step-complete-failed',\n message: cloudResult.error,\n });\n }\n\n // Emit step.completed event (backwards compat)\n this._bus.publish('task.step.completed', {\n taskId,\n stepId: input.stepId,\n result: input.result,\n });\n\n // Publish step_completed state\n this._publishState(taskId, TaskRouteState.StepCompleted, {\n stepId: input.stepId,\n result: input.result,\n });\n\n // Check if this was the last step (cloud response may indicate)\n const cloudData = cloudResult.data as Record<string, unknown> | undefined;\n const hasMoreSteps = cloudData?.hasMoreSteps ?? cloudData?.nextStepIdx !== undefined;\n\n if (hasMoreSteps) {\n // More steps to run — publish step_running for the next step\n this._publishState(taskId, TaskRouteState.StepRunning, {\n stepIdx: cloudData?.nextStepIdx,\n agentId: cloudData?.nextAgentId,\n });\n } else {\n // All steps done — publish completed\n this._publishState(taskId, TaskRouteState.Completed);\n }\n\n // Clear retry counters for this task's completed step\n const retryKey = `${taskId}:${input.stepId}`;\n this._retryCounters.delete(retryKey);\n\n sendJson(res, 200, cloudResult.data);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n sendJson(res, 500, { error: 'internal', message: msg });\n }\n }\n\n private async _handleCancelTask(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n requestBody: Buffer,\n ): Promise<void> {\n try {\n const match = req.url?.match(/\\/tasks\\/([^/]+)\\/cancel/);\n if (!match) {\n return sendJson(res, 400, { error: 'invalid-url' });\n }\n const taskId = match[1];\n\n const input: CancelTaskRequest = requestBody.length\n ? JSON.parse(requestBody.toString('utf8'))\n : ({} as CancelTaskRequest);\n\n if (input.taskId !== undefined && input.taskId !== taskId) {\n return sendJson(res, 400, { error: 'taskId-mismatch' });\n }\n if (!input.reason) {\n return sendJson(res, 400, { error: 'reason-required' });\n }\n\n // Call Cloud API to cancel task\n const cloudResult = await this._callCloudApi(\n `/tasks/${taskId}/cancel`,\n 'POST',\n { ...input, taskId } as unknown as Record<string, unknown>,\n );\n\n if (!cloudResult.ok) {\n return sendJson(res, cloudResult.status || 500, {\n error: 'cancel-failed',\n message: cloudResult.error,\n });\n }\n\n // Emit cancelled event (backwards compat)\n this._bus.publish('task.cancelled', {\n taskId,\n reason: input.reason,\n });\n\n // Publish cancelled state\n this._publishState(taskId, TaskRouteState.Cancelled, {\n reason: input.reason,\n });\n\n // Clean up retry counters for this task to prevent memory leak (I1 review fix)\n for (const key of this._retryCounters.keys()) {\n if (key.startsWith(taskId + ':')) {\n this._retryCounters.delete(key);\n }\n }\n\n sendJson(res, 200, cloudResult.data);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n sendJson(res, 500, { error: 'internal', message: msg });\n }\n }\n\n private async _handleStepFailed(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n requestBody: Buffer,\n ): Promise<void> {\n try {\n const match = req.url?.match(/\\/tasks\\/([^/]+)\\/step-failed/);\n if (!match) {\n return sendJson(res, 400, { error: 'invalid-url' });\n }\n const taskId = match[1];\n\n const input: StepFailedRequest = requestBody.length\n ? JSON.parse(requestBody.toString('utf8'))\n : ({} as StepFailedRequest);\n\n if (input.taskId !== undefined && input.taskId !== taskId) {\n return sendJson(res, 400, { error: 'taskId-mismatch' });\n }\n if (!input.stepId) {\n return sendJson(res, 400, { error: 'stepId-required' });\n }\n\n // Publish step_failed state\n this._publishState(taskId, TaskRouteState.StepFailed, {\n stepId: input.stepId,\n error: input.error,\n });\n\n // Track retries per step\n const retryKey = `${taskId}:${input.stepId}`;\n const currentRetries = this._retryCounters.get(retryKey) ?? 0;\n\n if (currentRetries < MAX_STEP_RETRIES) {\n const attempt = currentRetries + 1;\n this._retryCounters.set(retryKey, attempt);\n\n // Publish retrying state\n this._publishState(taskId, TaskRouteState.Retrying, {\n stepId: input.stepId,\n attempt,\n maxRetries: MAX_STEP_RETRIES,\n });\n\n sendJson(res, 200, {\n retry: true,\n attempt,\n maxRetries: MAX_STEP_RETRIES,\n });\n } else {\n // Retries exhausted\n this._publishState(taskId, TaskRouteState.RetryExhausted, {\n stepId: input.stepId,\n attempts: currentRetries,\n });\n\n this._publishState(taskId, TaskRouteState.NeedsHuman, {\n stepId: input.stepId,\n reason: 'retry_exhausted',\n });\n\n // Clean up retry counter\n this._retryCounters.delete(retryKey);\n\n sendJson(res, 200, {\n retry: false,\n needsHuman: true,\n attempts: currentRetries,\n });\n }\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n sendJson(res, 500, { error: 'internal', message: msg });\n }\n }\n\n private async _handleStepTimeout(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n requestBody: Buffer,\n ): Promise<void> {\n try {\n const match = req.url?.match(/\\/tasks\\/([^/]+)\\/step-timeout/);\n if (!match) {\n return sendJson(res, 400, { error: 'invalid-url' });\n }\n const taskId = match[1];\n\n const input: StepTimeoutRequest = requestBody.length\n ? JSON.parse(requestBody.toString('utf8'))\n : ({} as StepTimeoutRequest);\n\n if (input.taskId !== undefined && input.taskId !== taskId) {\n return sendJson(res, 400, { error: 'taskId-mismatch' });\n }\n if (!input.stepId) {\n return sendJson(res, 400, { error: 'stepId-required' });\n }\n\n // Publish step_timeout state\n this._publishState(taskId, TaskRouteState.StepTimeout, {\n stepId: input.stepId,\n });\n\n // Publish rerouting state\n this._publishState(taskId, TaskRouteState.Rerouting, {\n stepId: input.stepId,\n capability: input.capability,\n });\n\n // Attempt to find another agent via the supervisor\n const allAgents = this._supervisor.list();\n const runningAgents = allAgents.filter(\n (a) => a.state === 'running' || a.state === 'degraded',\n );\n\n // If a capability was specified, try to reroute via cloud API\n if (input.capability && runningAgents.length > 0) {\n const cloudResult = await this._callCloudApi(\n `/tasks/${taskId}/route`,\n 'POST',\n {\n taskId,\n capability: input.capability,\n excludeTimedOut: true,\n } as unknown as Record<string, unknown>,\n );\n\n if (cloudResult.ok) {\n const routeData = cloudResult.data as RouteTaskResponse;\n\n // Publish step_running with the new agent\n this._publishState(taskId, TaskRouteState.StepRunning, {\n agentId: routeData.agentId,\n capability: routeData.capability,\n stepIdx: routeData.stepIdx,\n rerouted: true,\n });\n\n sendJson(res, 200, {\n rerouted: true,\n agentId: routeData.agentId,\n capability: routeData.capability,\n stepIdx: routeData.stepIdx,\n });\n return;\n }\n }\n\n // Could not reroute — escalate to human\n this._publishState(taskId, TaskRouteState.NeedsHuman, {\n stepId: input.stepId,\n reason: 'reroute_failed',\n capability: input.capability,\n });\n\n sendJson(res, 200, {\n rerouted: false,\n needsHuman: true,\n reason: 'no_available_agent',\n });\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n sendJson(res, 500, { error: 'internal', message: msg });\n }\n }\n\n private async _handleGetTask(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ): Promise<void> {\n try {\n const match = req.url?.match(/\\/tasks\\/([^/]+)$/);\n if (!match) {\n return sendJson(res, 400, { error: 'invalid-url' });\n }\n const taskId = match[1];\n\n const cloudResult = await this._callCloudApi(`/tasks/${taskId}`, 'GET');\n\n if (!cloudResult.ok) {\n return sendJson(res, cloudResult.status || 500, {\n error: 'get-failed',\n message: cloudResult.error,\n });\n }\n\n sendJson(res, 200, cloudResult.data);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n sendJson(res, 500, { error: 'internal', message: msg });\n }\n }\n\n private async _handleListTasks(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n ): Promise<void> {\n try {\n const url = new URL(req.url ?? '/', 'http://localhost');\n const params = new URLSearchParams(url.search);\n const status = params.get('status');\n const capability = params.get('capability');\n const agent = params.get('agent');\n const limit = params.get('limit');\n\n const cloudResult = await this._callCloudApi('/tasks', 'GET', undefined, {\n status: status || undefined,\n capability: capability || undefined,\n assigneeId: agent || undefined,\n limit: limit || undefined,\n });\n\n if (!cloudResult.ok) {\n return sendJson(res, cloudResult.status || 500, {\n error: 'list-failed',\n message: cloudResult.error,\n });\n }\n\n sendJson(res, 200, cloudResult.data);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n sendJson(res, 500, { error: 'internal', message: msg });\n }\n }\n\n // ─── State Publishing ─────────────────────────────\n\n /** Publish a task.state event with the given TaskRouteState and optional extra fields. */\n private _publishState(\n taskId: string,\n state: TaskRouteState,\n extra?: Record<string, unknown>,\n ): void {\n this._bus.publish('task.state', {\n taskId,\n state,\n timestamp: new Date().toISOString(),\n ...extra,\n });\n }\n\n // ─── Cloud API Client ─────────────────────────────\n\n private async _callCloudApi(\n path: string,\n method: 'GET' | 'POST',\n body?: Record<string, unknown>,\n queryParams?: Record<string, string | undefined>,\n ): Promise<{ ok: boolean; status?: number; data?: unknown; error?: string }> {\n const apiPath = path.startsWith('/api/') ? path : `/api/im${path}`;\n const url = new URL(apiPath, this._cloudBaseUrl);\n\n // Add query params\n if (queryParams) {\n Object.entries(queryParams).forEach(([key, value]) => {\n if (value !== undefined) {\n url.searchParams.append(key, value);\n }\n });\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (this._apiToken) {\n headers['Authorization'] = `Bearer ${this._apiToken}`;\n }\n\n const response = await fetch(url, {\n method,\n headers: {\n ...headers,\n },\n body: body && method === 'POST' ? JSON.stringify(body) : undefined,\n });\n\n const responseBody = await response.text();\n let parsed: any = undefined;\n try {\n parsed = responseBody ? JSON.parse(responseBody) : undefined;\n } catch {\n parsed = undefined;\n }\n\n return {\n ok: response.ok && parsed?.ok !== false,\n status: response.status,\n data: parsed?.data ?? parsed,\n error: parsed?.error?.message ?? parsed?.error ?? (response.ok ? undefined : responseBody),\n };\n }\n}\n","// T9 — LLM Dispatcher: routes complete() calls across multiple providers\n// with priority/fallback/cost/latency policies.\n\nexport interface LLMMessage {\n role: 'system' | 'user' | 'assistant';\n content: string;\n}\n\nexport interface LLMRequest {\n messages: LLMMessage[];\n maxTokens?: number;\n temperature?: number;\n maxCostUsd?: number;\n maxLatencyMs?: number;\n capabilities?: string[];\n}\n\nexport interface LLMResponse {\n content: string;\n usage: { promptTokens: number; completionTokens: number; totalTokens: number };\n provider: string;\n model: string;\n latencyMs: number;\n costUsd?: number;\n}\n\nexport interface LLMProvider {\n name: string;\n model: string;\n priority: number;\n capabilities?: string[];\n pricing?: { inputPer1kUsd: number; outputPer1kUsd: number };\n invoke: (req: LLMRequest, signal: AbortSignal) => Promise<Omit<LLMResponse, 'provider' | 'model' | 'latencyMs'>>;\n healthCheck?: () => Promise<boolean>;\n}\n\nexport interface RoutingPolicy {\n strategy: 'priority' | 'cheapest' | 'fastest' | 'round-robin';\n retryOnFailure?: boolean;\n maxRetries?: number;\n healthCheckIntervalMs?: number;\n timeoutMs?: number;\n}\n\nexport interface ProviderStats {\n invocations: number;\n successes: number;\n failures: number;\n p50Ms: number;\n p95Ms: number;\n avgCostUsd: number;\n}\n\nexport class AllProvidersFailedError extends Error {\n attempts: Array<{ provider: string; error: string }>;\n\n constructor(attempts: AllProvidersFailedError['attempts']) {\n super(`All ${attempts.length} providers failed`);\n this.name = 'AllProvidersFailedError';\n this.attempts = attempts;\n }\n}\n\n// Circular buffer for rolling window of last N values.\nclass RollingBuffer {\n private buf: number[];\n private pos = 0;\n private len = 0;\n private readonly cap: number;\n\n constructor(capacity: number) {\n this.cap = capacity;\n this.buf = new Array<number>(capacity).fill(0);\n }\n\n push(val: number): void {\n this.buf[this.pos] = val;\n this.pos = (this.pos + 1) % this.cap;\n if (this.len < this.cap) this.len++;\n }\n\n get count(): number {\n return this.len;\n }\n\n sorted(): number[] {\n return this.buf.slice(0, this.len).sort((a, b) => a - b);\n }\n\n sum(): number {\n return this.buf.slice(0, this.len).reduce((a, b) => a + b, 0);\n }\n}\n\nfunction percentile(sorted: number[], p: number): number {\n if (sorted.length === 0) return 0;\n const idx = Math.ceil((p / 100) * sorted.length) - 1;\n return sorted[Math.max(0, idx)];\n}\n\nconst ROLLING_WINDOW = 100;\nconst COST_HEURISTIC_MAX_TOKENS = 1024;\nconst DEFAULT_HEALTH_INTERVAL_MS = 60_000;\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_RETRIES = 2;\n\nfunction applyPolicyDefaults(policy: RoutingPolicy): Required<RoutingPolicy> {\n return {\n strategy: policy.strategy,\n retryOnFailure: policy.retryOnFailure !== undefined ? policy.retryOnFailure : true,\n maxRetries: policy.maxRetries !== undefined ? policy.maxRetries : DEFAULT_MAX_RETRIES,\n healthCheckIntervalMs: policy.healthCheckIntervalMs !== undefined ? policy.healthCheckIntervalMs : DEFAULT_HEALTH_INTERVAL_MS,\n timeoutMs: policy.timeoutMs !== undefined ? policy.timeoutMs : DEFAULT_TIMEOUT_MS,\n };\n}\n\ninterface ProviderState {\n manualDown: boolean;\n healthDown: boolean;\n healthDownUntil: number; // timestamp; 0 = not set\n latencies: RollingBuffer;\n costs: RollingBuffer;\n invocations: number;\n successes: number;\n failures: number;\n}\n\nexport class LLMDispatcher {\n private readonly providers: LLMProvider[];\n private policy: Required<RoutingPolicy>;\n private readonly state: Map<string, ProviderState> = new Map();\n private rrCounter = 0;\n private healthTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor(providers: LLMProvider[], policy?: RoutingPolicy) {\n this.providers = providers.slice();\n this.policy = applyPolicyDefaults(policy ?? { strategy: 'priority' });\n\n for (const p of this.providers) {\n this.state.set(p.name, {\n manualDown: false,\n healthDown: false,\n healthDownUntil: 0,\n latencies: new RollingBuffer(ROLLING_WINDOW),\n costs: new RollingBuffer(ROLLING_WINDOW),\n invocations: 0,\n successes: 0,\n failures: 0,\n });\n }\n\n this.startHealthChecks();\n }\n\n async complete(req: LLMRequest): Promise<LLMResponse> {\n const ordered = this.selectProviders(req);\n\n if (ordered.length === 0) {\n throw new AllProvidersFailedError([]);\n }\n\n const shouldRetry = this.policy.retryOnFailure !== false;\n const maxAttempts = shouldRetry ? 1 + (this.policy.maxRetries ?? DEFAULT_MAX_RETRIES) : 1;\n const attempts: Array<{ provider: string; error: string }> = [];\n const timeoutMs = this.policy.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n for (let i = 0; i < ordered.length && attempts.length < maxAttempts; i++) {\n const provider = ordered[i];\n const st = this.state.get(provider.name)!;\n st.invocations++;\n\n const ac = new AbortController();\n const t0 = performance.now();\n\n try {\n const timeoutPromise = new Promise<never>((_, reject) => {\n const t = setTimeout(() => {\n ac.abort();\n reject(new Error(`provider timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n // Allow the timer to be cleaned up if invoke resolves first.\n if (t.unref) t.unref();\n });\n\n const partial = await Promise.race([provider.invoke(req, ac.signal), timeoutPromise]);\n const latencyMs = Math.round(performance.now() - t0);\n\n const costUsd = computeCost(provider, partial.usage);\n st.latencies.push(latencyMs);\n if (costUsd !== undefined) st.costs.push(costUsd);\n st.successes++;\n\n if (this.policy.strategy === 'round-robin') {\n this.rrCounter++;\n }\n\n return {\n ...partial,\n provider: provider.name,\n model: provider.model,\n latencyMs,\n costUsd,\n };\n } catch (err: unknown) {\n st.failures++;\n const msg = err instanceof Error ? err.message : String(err);\n attempts.push({ provider: provider.name, error: msg });\n\n if (!shouldRetry) break;\n }\n }\n\n throw new AllProvidersFailedError(attempts);\n }\n\n get stats(): Record<string, ProviderStats> {\n const result: Record<string, ProviderStats> = {};\n for (const p of this.providers) {\n const st = this.state.get(p.name)!;\n const sortedLat = st.latencies.sorted();\n const sortedCost = st.costs.sorted();\n result[p.name] = {\n invocations: st.invocations,\n successes: st.successes,\n failures: st.failures,\n p50Ms: percentile(sortedLat, 50),\n p95Ms: percentile(sortedLat, 95),\n avgCostUsd: st.costs.count > 0 ? st.costs.sum() / st.costs.count : 0,\n };\n }\n return result;\n }\n\n setPolicy(policy: RoutingPolicy): void {\n this.policy = applyPolicyDefaults(policy);\n // Reset round-robin counter when strategy changes.\n this.rrCounter = 0;\n // Restart health checks with potentially new interval.\n this.stopHealthChecks();\n this.startHealthChecks();\n }\n\n markProviderDown(name: string): void {\n const st = this.state.get(name);\n if (st) st.manualDown = true;\n }\n\n markProviderUp(name: string): void {\n const st = this.state.get(name);\n if (st) {\n st.manualDown = false;\n st.healthDown = false;\n st.healthDownUntil = 0;\n }\n }\n\n stopHealthChecks(): void {\n if (this.healthTimer !== null) {\n clearInterval(this.healthTimer);\n this.healthTimer = null;\n }\n }\n\n private startHealthChecks(): void {\n const interval = this.policy.healthCheckIntervalMs ?? DEFAULT_HEALTH_INTERVAL_MS;\n const providersWithCheck = this.providers.filter((p) => p.healthCheck !== undefined);\n if (providersWithCheck.length === 0) return;\n\n this.healthTimer = setInterval(() => {\n void this.runHealthChecks(interval);\n }, interval);\n\n // Do not hold the event loop open for health checks.\n if (this.healthTimer.unref) {\n this.healthTimer.unref();\n }\n }\n\n private async runHealthChecks(intervalMs: number): Promise<void> {\n for (const p of this.providers) {\n if (!p.healthCheck) continue;\n const st = this.state.get(p.name)!;\n\n // If previously health-down, check if TTL expired (auto-recover probe).\n if (st.healthDown && st.healthDownUntil > 0 && Date.now() >= st.healthDownUntil) {\n st.healthDown = false;\n st.healthDownUntil = 0;\n }\n\n try {\n const healthy = await p.healthCheck();\n if (!healthy) {\n st.healthDown = true;\n st.healthDownUntil = Date.now() + intervalMs;\n } else {\n st.healthDown = false;\n st.healthDownUntil = 0;\n }\n } catch {\n st.healthDown = true;\n st.healthDownUntil = Date.now() + intervalMs;\n }\n }\n }\n\n // Trigger a health check round immediately (used in tests with fake timers).\n async _runHealthChecksNow(): Promise<void> {\n await this.runHealthChecks(this.policy.healthCheckIntervalMs ?? DEFAULT_HEALTH_INTERVAL_MS);\n }\n\n private isDown(name: string): boolean {\n const st = this.state.get(name);\n if (!st) return true;\n if (st.manualDown) return true;\n if (st.healthDown) {\n // Auto-recover if TTL has passed.\n if (st.healthDownUntil > 0 && Date.now() >= st.healthDownUntil) {\n st.healthDown = false;\n st.healthDownUntil = 0;\n return false;\n }\n return true;\n }\n return false;\n }\n\n private estimateCostUsd(provider: LLMProvider, req: LLMRequest): number | undefined {\n if (!provider.pricing) return undefined;\n // Rough prompt token heuristic: sum of chars / 4.\n const promptChars = req.messages.reduce((s, m) => s + m.content.length, 0);\n const promptTokens = Math.ceil(promptChars / 4);\n const completionTokens = req.maxTokens ?? COST_HEURISTIC_MAX_TOKENS;\n return (\n (promptTokens / 1000) * provider.pricing.inputPer1kUsd +\n (completionTokens / 1000) * provider.pricing.outputPer1kUsd\n );\n }\n\n private selectProviders(req: LLMRequest): LLMProvider[] {\n let candidates = this.providers.filter((p) => !this.isDown(p.name));\n\n // Capability filter.\n if (req.capabilities && req.capabilities.length > 0) {\n candidates = candidates.filter((p) => {\n const caps = p.capabilities ?? [];\n return req.capabilities!.every((c) => caps.includes(c));\n });\n }\n\n // Cost filter.\n if (req.maxCostUsd !== undefined) {\n candidates = candidates.filter((p) => {\n const est = this.estimateCostUsd(p, req);\n if (est === undefined) return true; // no pricing info — allow through\n return est <= req.maxCostUsd!;\n });\n }\n\n // Latency filter.\n if (req.maxLatencyMs !== undefined) {\n candidates = candidates.filter((p) => {\n const st = this.state.get(p.name)!;\n if (st.latencies.count === 0) return true; // no data yet — allow through\n const sortedLat = st.latencies.sorted();\n return percentile(sortedLat, 95) <= req.maxLatencyMs!;\n });\n }\n\n // Sort by strategy.\n switch (this.policy.strategy) {\n case 'priority':\n candidates.sort((a, b) => b.priority - a.priority);\n break;\n\n case 'cheapest':\n candidates.sort((a, b) => {\n const ca = this.estimateCostUsd(a, req) ?? 0;\n const cb = this.estimateCostUsd(b, req) ?? 0;\n return ca !== cb ? ca - cb : b.priority - a.priority;\n });\n break;\n\n case 'fastest': {\n candidates.sort((a, b) => {\n const sta = this.state.get(a.name)!;\n const stb = this.state.get(b.name)!;\n const pa50 = sta.latencies.count > 0 ? percentile(sta.latencies.sorted(), 50) : Infinity;\n const pb50 = stb.latencies.count > 0 ? percentile(stb.latencies.sorted(), 50) : Infinity;\n return pa50 !== pb50 ? pa50 - pb50 : b.priority - a.priority;\n });\n break;\n }\n\n case 'round-robin': {\n if (candidates.length === 0) break;\n // Rotate the start index by rrCounter mod count.\n const start = this.rrCounter % candidates.length;\n candidates = [...candidates.slice(start), ...candidates.slice(0, start)];\n break;\n }\n }\n\n return candidates;\n }\n}\n\nfunction computeCost(\n provider: LLMProvider,\n usage: { promptTokens: number; completionTokens: number },\n): number | undefined {\n if (!provider.pricing) return undefined;\n return (\n (usage.promptTokens / 1000) * provider.pricing.inputPer1kUsd +\n (usage.completionTokens / 1000) * provider.pricing.outputPer1kUsd\n );\n}\n","// T10 — Keychain: macOS Keychain / libsecret / pass / encrypted-file backends\n\nimport * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { execFile as execFileCb } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execFile = promisify(execFileCb);\n\n// ============================================================\n// Public types\n// ============================================================\n\nexport type KeychainBackend = 'macos-keychain' | 'libsecret' | 'pass' | 'encrypted-file';\n\nexport interface KeychainAdapter {\n name: KeychainBackend;\n available(): Promise<boolean>;\n get(service: string, account: string): Promise<string | null>;\n set(service: string, account: string, value: string): Promise<void>;\n delete(service: string, account: string): Promise<void>;\n list(service: string): Promise<string[]>;\n}\n\nexport interface KeychainOptions {\n preferredBackend?: KeychainBackend;\n masterPassphrase?: string;\n encryptedFilePath?: string;\n}\n\n// ============================================================\n// Errors\n// ============================================================\n\nexport class NoKeychainBackendError extends Error {\n constructor() {\n super('No keychain backend available and no master passphrase configured');\n this.name = 'NoKeychainBackendError';\n }\n}\n\nexport class KeychainOperationError extends Error {\n constructor(op: string, cause: unknown) {\n super(`Keychain ${op} failed: ${String(cause)}`);\n this.name = 'KeychainOperationError';\n }\n}\n\n/**\n * Raised when the OS keychain is available but the user (or a SAP / policy)\n * denied access. `cli/ui.error` consumers display this with a §15.3-style\n * What / Cause / Fix / Alt block.\n */\nexport class KeychainAccessDeniedError extends Error {\n readonly backend: KeychainBackend;\n constructor(backend: KeychainBackend, op: string) {\n super(`Keychain access denied during ${op} (backend=${backend})`);\n this.name = 'KeychainAccessDeniedError';\n this.backend = backend;\n }\n}\n\n// macOS security(1) exit codes — see /usr/include/Security/SecBase.h\n// errSecAuthFailed (-25293) surfaces as exit 51 via shell\n// errAuthorizationCanceled (-60006) surfaces as exit 128+45=128 / exit 1 depending on SDK\n// errSecInteractionNotAllowed surfaces as \"User interaction is not allowed\" on stderr\nfunction isMacAccessDenied(err: unknown): boolean {\n if (typeof err !== 'object' || err === null) return false;\n const rec = err as { code?: unknown; stderr?: unknown };\n if (rec.code === 51 || rec.code === 45) return true;\n if (typeof rec.stderr === 'string') {\n const msg = rec.stderr.toLowerCase();\n if (msg.includes('user interaction is not allowed')) return true;\n if (msg.includes('authentication failed')) return true;\n if (msg.includes('user canceled')) return true;\n }\n return false;\n}\n\n// ============================================================\n// Side-index helper (shared by macOS + libsecret + pass)\n// ============================================================\n\ninterface IndexData {\n [service: string]: string[];\n}\n\nfunction readIndex(indexPath: string): IndexData {\n try {\n const raw = fs.readFileSync(indexPath, 'utf-8');\n return JSON.parse(raw) as IndexData;\n } catch {\n return {};\n }\n}\n\nfunction writeIndex(indexPath: string, data: IndexData): void {\n const tmp = indexPath + '.tmp';\n fs.writeFileSync(tmp, JSON.stringify(data, null, 2), 'utf-8');\n fs.renameSync(tmp, indexPath);\n}\n\nfunction indexAdd(indexPath: string, service: string, account: string): void {\n const data = readIndex(indexPath);\n if (!data[service]) data[service] = [];\n if (!data[service].includes(account)) data[service].push(account);\n writeIndex(indexPath, data);\n}\n\nfunction indexRemove(indexPath: string, service: string, account: string): void {\n const data = readIndex(indexPath);\n if (!data[service]) return;\n data[service] = data[service].filter((a) => a !== account);\n if (data[service].length === 0) delete data[service];\n writeIndex(indexPath, data);\n}\n\nfunction indexList(indexPath: string, service: string): string[] {\n const data = readIndex(indexPath);\n return (data[service] ?? []).slice().sort();\n}\n\n// ============================================================\n// macOS Keychain adapter\n// ============================================================\n\nconst NATIVE_INDEX_PATH = path.join(os.homedir(), '.prismer', 'keychain-index.json');\n\nfunction ensureDir(p: string): void {\n fs.mkdirSync(path.dirname(p), { recursive: true });\n}\n\nclass MacOSKeychainAdapter implements KeychainAdapter {\n readonly name: KeychainBackend = 'macos-keychain';\n\n async available(): Promise<boolean> {\n if (process.platform !== 'darwin') return false;\n try {\n await execFile('which', ['security']);\n await execFile('security', ['list-keychains']);\n return true;\n } catch {\n return false;\n }\n }\n\n async get(service: string, account: string): Promise<string | null> {\n try {\n const { stdout } = await execFile('security', [\n 'find-generic-password',\n '-s', service,\n '-a', account,\n '-w',\n ]);\n return stdout.trim();\n } catch (err: unknown) {\n // exit code 44 = not found\n if (isExitCode44(err)) return null;\n if (isMacAccessDenied(err)) throw new KeychainAccessDeniedError(this.name, 'get');\n throw new KeychainOperationError('get', err);\n }\n }\n\n async set(service: string, account: string, value: string): Promise<void> {\n try {\n // C3: use -X <hex> instead of -w <plaintext> so the secret never appears in\n // ps argv output. security(1) man page: \"-X Specify password data to be added\n // as a hexadecimal string\". find-generic-password -w decodes it back correctly.\n const hexValue = Buffer.from(value, 'utf-8').toString('hex');\n await execFile('security', [\n 'add-generic-password',\n '-s', service,\n '-a', account,\n '-X', hexValue,\n '-U',\n ]);\n ensureDir(NATIVE_INDEX_PATH);\n // I6: ensure ~/.prismer/ is owner-only; best-effort in case of unusual perms\n try { fs.chmodSync(path.dirname(NATIVE_INDEX_PATH), 0o700); } catch { /* ignore */ }\n indexAdd(NATIVE_INDEX_PATH, service, account);\n } catch (err: unknown) {\n if (isMacAccessDenied(err)) throw new KeychainAccessDeniedError(this.name, 'set');\n throw new KeychainOperationError('set', err);\n }\n }\n\n async delete(service: string, account: string): Promise<void> {\n try {\n await execFile('security', [\n 'delete-generic-password',\n '-s', service,\n '-a', account,\n ]);\n indexRemove(NATIVE_INDEX_PATH, service, account);\n } catch (err: unknown) {\n if (isExitCode44(err)) return; // not found — silent success\n throw new KeychainOperationError('delete', err);\n }\n }\n\n async list(service: string): Promise<string[]> {\n return indexList(NATIVE_INDEX_PATH, service);\n }\n}\n\nfunction isExitCode44(err: unknown): boolean {\n if (typeof err === 'object' && err !== null && 'code' in err) {\n return (err as { code: unknown }).code === 44;\n }\n return false;\n}\n\n// secret-tool exits 1 when the secret is simply not found (documented behaviour).\n// Any other non-zero exit (dbus broken, permission denied, etc.) is a real error.\nfunction isLibsecretNotFound(err: unknown): boolean {\n if (typeof err === 'object' && err !== null && 'code' in err) {\n return (err as { code: unknown }).code === 1;\n }\n return false;\n}\n\n// ============================================================\n// Linux libsecret adapter (secret-tool)\n// ============================================================\n\nclass LibsecretAdapter implements KeychainAdapter {\n readonly name: KeychainBackend = 'libsecret';\n\n async available(): Promise<boolean> {\n if (process.platform !== 'linux') return false;\n try {\n await execFile('which', ['secret-tool']);\n // Verify dbus session is available by running a harmless lookup\n await execFile('secret-tool', ['lookup', 'prismer-probe', 'unavailable']);\n return true;\n } catch (err: unknown) {\n // secret-tool exits non-zero when not found, but that's OK for availability —\n // what we care about is that the binary runs at all (dbus available).\n // If \"which\" succeeded but the lookup exits with \"connected\" error, dbus works.\n if (isWhichError(err)) return false;\n return true;\n }\n }\n\n async get(service: string, account: string): Promise<string | null> {\n try {\n const { stdout } = await execFile('secret-tool', [\n 'lookup',\n 'prismer-service', service,\n 'prismer-account', account,\n ]);\n const trimmed = stdout.trim();\n return trimmed.length > 0 ? trimmed : null;\n } catch (err: unknown) {\n if (isLibsecretNotFound(err)) return null;\n throw new KeychainOperationError('get', err);\n }\n }\n\n async set(service: string, account: string, value: string): Promise<void> {\n try {\n // secret-tool reads password from stdin\n const child = execFileCb('secret-tool', [\n 'store',\n '--label', `${service}:${account}`,\n 'prismer-service', service,\n 'prismer-account', account,\n ]);\n child.stdin!.write(value);\n child.stdin!.end();\n await new Promise<void>((resolve, reject) => {\n child.on('close', (code) => (code === 0 ? resolve() : reject(new Error(`exit ${code}`))));\n child.on('error', reject);\n });\n ensureDir(NATIVE_INDEX_PATH);\n indexAdd(NATIVE_INDEX_PATH, service, account);\n } catch (err: unknown) {\n throw new KeychainOperationError('set', err);\n }\n }\n\n async delete(service: string, account: string): Promise<void> {\n try {\n await execFile('secret-tool', [\n 'clear',\n 'prismer-service', service,\n 'prismer-account', account,\n ]);\n indexRemove(NATIVE_INDEX_PATH, service, account);\n } catch {\n // non-existent — silent\n }\n }\n\n async list(service: string): Promise<string[]> {\n return indexList(NATIVE_INDEX_PATH, service);\n }\n}\n\nfunction isWhichError(err: unknown): boolean {\n if (typeof err === 'object' && err !== null && 'cmd' in err) {\n const cmd = (err as { cmd?: string }).cmd ?? '';\n return cmd.startsWith('which');\n }\n return false;\n}\n\n// ============================================================\n// Linux `pass` adapter\n// ============================================================\n\nclass PassAdapter implements KeychainAdapter {\n readonly name: KeychainBackend = 'pass';\n\n async available(): Promise<boolean> {\n if (process.platform !== 'linux') return false;\n try {\n await execFile('which', ['pass']);\n await execFile('pass', ['--version']);\n return true;\n } catch {\n return false;\n }\n }\n\n async get(service: string, account: string): Promise<string | null> {\n try {\n const { stdout } = await execFile('pass', [\n 'show',\n `prismer/${service}/${account}`,\n ]);\n return stdout.trim();\n } catch {\n return null;\n }\n }\n\n async set(service: string, account: string, value: string): Promise<void> {\n try {\n const child = execFileCb('pass', [\n 'insert',\n '-m',\n `prismer/${service}/${account}`,\n ]);\n child.stdin!.write(value);\n child.stdin!.end();\n await new Promise<void>((resolve, reject) => {\n child.on('close', (code) => (code === 0 ? resolve() : reject(new Error(`exit ${code}`))));\n child.on('error', reject);\n });\n ensureDir(NATIVE_INDEX_PATH);\n indexAdd(NATIVE_INDEX_PATH, service, account);\n } catch (err: unknown) {\n throw new KeychainOperationError('set', err);\n }\n }\n\n async delete(service: string, account: string): Promise<void> {\n try {\n await execFile('pass', [\n 'rm',\n '-f',\n `prismer/${service}/${account}`,\n ]);\n indexRemove(NATIVE_INDEX_PATH, service, account);\n } catch {\n // not found — silent\n }\n }\n\n async list(service: string): Promise<string[]> {\n return indexList(NATIVE_INDEX_PATH, service);\n }\n}\n\n// ============================================================\n// Encrypted-file backend\n// ============================================================\n\nconst SCRYPT_SALT_BYTES = 16;\nconst AES_NONCE_BYTES = 12;\nconst AES_TAG_BYTES = 16;\nconst SCRYPT_KEY_BYTES = 32;\nconst FILE_FORMAT_VERSION = 1;\n\ninterface SecretsStore {\n version: number;\n secrets: { [service: string]: { [account: string]: string } };\n}\n\nfunction deriveKey(passphrase: string, salt: Buffer): Buffer {\n return crypto.scryptSync(passphrase, salt, SCRYPT_KEY_BYTES) as Buffer;\n}\n\nfunction encryptStore(store: SecretsStore, passphrase: string): Buffer {\n const salt = crypto.randomBytes(SCRYPT_SALT_BYTES);\n const nonce = crypto.randomBytes(AES_NONCE_BYTES);\n const key = deriveKey(passphrase, salt);\n const plaintext = Buffer.from(JSON.stringify(store), 'utf-8');\n\n const cipher = crypto.createCipheriv('aes-256-gcm', key, nonce);\n const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);\n const tag = cipher.getAuthTag();\n\n return Buffer.concat([salt, nonce, ciphertext, tag]);\n}\n\nfunction decryptStore(data: Buffer, passphrase: string): SecretsStore {\n if (data.length < SCRYPT_SALT_BYTES + AES_NONCE_BYTES + AES_TAG_BYTES) {\n throw new KeychainOperationError('decrypt', 'tamper detected or wrong passphrase');\n }\n\n const salt = data.subarray(0, SCRYPT_SALT_BYTES);\n const nonce = data.subarray(SCRYPT_SALT_BYTES, SCRYPT_SALT_BYTES + AES_NONCE_BYTES);\n const tag = data.subarray(data.length - AES_TAG_BYTES);\n const ciphertext = data.subarray(SCRYPT_SALT_BYTES + AES_NONCE_BYTES, data.length - AES_TAG_BYTES);\n\n const key = deriveKey(passphrase, salt);\n\n try {\n const decipher = crypto.createDecipheriv('aes-256-gcm', key, nonce);\n decipher.setAuthTag(tag);\n const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return JSON.parse(plaintext.toString('utf-8')) as SecretsStore;\n } catch {\n throw new KeychainOperationError('decrypt', 'tamper detected or wrong passphrase');\n }\n}\n\nclass EncryptedFileAdapter implements KeychainAdapter {\n readonly name: KeychainBackend = 'encrypted-file';\n private readonly filePath: string;\n private readonly passphrase: string;\n\n constructor(filePath: string, passphrase: string) {\n this.filePath = filePath;\n this.passphrase = passphrase;\n // Q5: cleanup stray sidecar from v1.9.0-dev; encrypted store is canonical\n const stale = filePath + '.index.json';\n try { if (fs.existsSync(stale)) fs.unlinkSync(stale); } catch { /* best effort */ }\n }\n\n async available(): Promise<boolean> {\n return true;\n }\n\n private readStore(): SecretsStore {\n if (!fs.existsSync(this.filePath)) {\n return { version: FILE_FORMAT_VERSION, secrets: {} };\n }\n const data = fs.readFileSync(this.filePath);\n return decryptStore(data, this.passphrase);\n }\n\n private writeStore(store: SecretsStore): void {\n ensureDir(this.filePath);\n // I6: chmod dir to 0700 (owner-only) — best-effort; may fail on system dirs during tests\n try { fs.chmodSync(path.dirname(this.filePath), 0o700); } catch { /* ignore if not owner */ }\n const encrypted = encryptStore(store, this.passphrase);\n const tmp = this.filePath + '.tmp';\n fs.writeFileSync(tmp, encrypted);\n // I6: chmod encrypted file to 0600 before atomic rename\n fs.chmodSync(tmp, 0o600);\n fs.renameSync(tmp, this.filePath);\n }\n\n async get(service: string, account: string): Promise<string | null> {\n const store = this.readStore();\n return store.secrets[service]?.[account] ?? null;\n }\n\n async set(service: string, account: string, value: string): Promise<void> {\n const store = this.readStore();\n if (!store.secrets[service]) store.secrets[service] = {};\n store.secrets[service][account] = value;\n this.writeStore(store);\n // Q5: no sidecar write — encrypted store is the canonical enumerable source\n }\n\n async delete(service: string, account: string): Promise<void> {\n if (!fs.existsSync(this.filePath)) return;\n const store = this.readStore();\n if (!store.secrets[service]) return;\n delete store.secrets[service][account];\n if (Object.keys(store.secrets[service]).length === 0) {\n delete store.secrets[service];\n }\n this.writeStore(store);\n // Q5: no sidecar removal needed — sidecar is gone\n }\n\n async list(service: string): Promise<string[]> {\n if (!fs.existsSync(this.filePath)) return [];\n // Q5: enumerate directly from the encrypted store (no plaintext sidecar needed)\n const store = this.readStore();\n return Object.keys(store.secrets[service] ?? {}).sort();\n }\n}\n\n// ============================================================\n// Keychain class — auto-detect and delegate\n// ============================================================\n\nconst DEFAULT_ENCRYPTED_FILE = path.join(os.homedir(), '.prismer', 'credentials.json.enc');\n\nexport class Keychain {\n private readonly opts: KeychainOptions;\n private resolvedBackend: KeychainAdapter | null = null;\n private detecting = false;\n\n constructor(opts?: KeychainOptions) {\n this.opts = opts ?? {};\n }\n\n async backend(): Promise<KeychainAdapter> {\n if (this.resolvedBackend) return this.resolvedBackend;\n\n const preferred = this.opts.preferredBackend;\n\n // Build candidate list in priority order\n const candidates: KeychainAdapter[] = preferred\n ? [this.makeAdapter(preferred)]\n : this.buildCandidateList();\n\n for (const candidate of candidates) {\n if (await candidate.available()) {\n this.resolvedBackend = candidate;\n return candidate;\n }\n }\n\n throw new NoKeychainBackendError();\n }\n\n private buildCandidateList(): KeychainAdapter[] {\n const candidates: KeychainAdapter[] = [];\n if (process.platform === 'darwin') {\n candidates.push(new MacOSKeychainAdapter());\n } else if (process.platform === 'linux') {\n candidates.push(new LibsecretAdapter());\n candidates.push(new PassAdapter());\n }\n // Encrypted-file as last resort — only if passphrase is configured\n const passphrase = this.opts.masterPassphrase ?? process.env['PRISMER_MASTER_PASSPHRASE'];\n if (passphrase) {\n const filePath = this.opts.encryptedFilePath ?? DEFAULT_ENCRYPTED_FILE;\n candidates.push(new EncryptedFileAdapter(filePath, passphrase));\n }\n return candidates;\n }\n\n private makeAdapter(name: KeychainBackend): KeychainAdapter {\n switch (name) {\n case 'macos-keychain':\n return new MacOSKeychainAdapter();\n case 'libsecret':\n return new LibsecretAdapter();\n case 'pass':\n return new PassAdapter();\n case 'encrypted-file': {\n const passphrase = this.opts.masterPassphrase ?? process.env['PRISMER_MASTER_PASSPHRASE'];\n if (!passphrase) throw new NoKeychainBackendError();\n const filePath = this.opts.encryptedFilePath ?? DEFAULT_ENCRYPTED_FILE;\n return new EncryptedFileAdapter(filePath, passphrase);\n }\n }\n }\n\n async get(service: string, account: string): Promise<string | null> {\n return (await this.backend()).get(service, account);\n }\n\n async set(service: string, account: string, value: string): Promise<void> {\n return (await this.backend()).set(service, account, value);\n }\n\n async delete(service: string, account: string): Promise<void> {\n return (await this.backend()).delete(service, account);\n }\n\n async list(service: string): Promise<string[]> {\n return (await this.backend()).list(service);\n }\n}\n","// T11 — config.toml loader + $KEYRING resolution\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport TOML from '@iarna/toml';\nimport type { Keychain } from './keychain.js';\n\n// ============================================================\n// Public types\n// ============================================================\n\nexport interface PrismerConfig {\n apiKey?: string;\n apiBase?: string;\n daemon?: {\n host?: string;\n port?: number;\n };\n agents?: Record<string, {\n enabled?: boolean;\n apiKey?: string;\n [key: string]: unknown;\n }>;\n [key: string]: unknown;\n}\n\nexport interface LoadConfigOptions {\n path?: string;\n keychain?: Keychain;\n resolvePlaceholders?: boolean;\n}\n\n// ============================================================\n// Errors\n// ============================================================\n\nexport class ConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ConfigError';\n }\n}\n\n// ============================================================\n// Placeholder parsing\n// ============================================================\n\nconst KEYRING_PREFIX = '$KEYRING:';\n\nexport function parseKeyringPlaceholder(value: string): { service: string; account: string } | null {\n if (!value.startsWith(KEYRING_PREFIX)) return null;\n const rest = value.slice(KEYRING_PREFIX.length);\n const slashIdx = rest.indexOf('/');\n if (slashIdx < 1 || slashIdx === rest.length - 1) {\n throw new ConfigError(`malformed $KEYRING placeholder: \"${value}\" — expected $KEYRING:<service>/<account>`);\n }\n return {\n service: rest.slice(0, slashIdx),\n account: rest.slice(slashIdx + 1),\n };\n}\n\n// ============================================================\n// Recursive walker — resolves placeholders in-place\n// ============================================================\n\ntype JsonValue = string | number | boolean | null | JsonValue[] | { [k: string]: JsonValue };\n\nasync function walkAndResolve(\n value: JsonValue,\n keychain: Keychain,\n resolvePlaceholders: boolean,\n): Promise<JsonValue> {\n if (typeof value === 'string') {\n const parsed = parseKeyringPlaceholder(value);\n if (parsed === null) return value;\n if (!resolvePlaceholders) return value;\n const secret = await keychain.get(parsed.service, parsed.account);\n if (secret === null) {\n throw new ConfigError(`missing secret: ${parsed.service}/${parsed.account}`);\n }\n return secret;\n }\n\n if (Array.isArray(value)) {\n const results: JsonValue[] = [];\n for (const item of value) {\n results.push(await walkAndResolve(item, keychain, resolvePlaceholders));\n }\n return results;\n }\n\n if (value !== null && typeof value === 'object') {\n const resolved: { [k: string]: JsonValue } = {};\n for (const [k, v] of Object.entries(value)) {\n resolved[k] = await walkAndResolve(v as JsonValue, keychain, resolvePlaceholders);\n }\n return resolved;\n }\n\n return value;\n}\n\n// ============================================================\n// Default config path\n// ============================================================\n\nfunction defaultConfigPath(): string {\n return path.join(os.homedir(), '.prismer', 'config.toml');\n}\n\n// ============================================================\n// loadConfig\n// ============================================================\n\nexport async function loadConfig(opts?: LoadConfigOptions): Promise<PrismerConfig> {\n const configPath = opts?.path ?? defaultConfigPath();\n const resolvePlaceholders = opts?.resolvePlaceholders ?? true;\n\n let raw: string | null = null;\n try {\n raw = fs.readFileSync(configPath, 'utf-8');\n } catch (err) {\n const e = err as NodeJS.ErrnoException;\n if (e.code !== 'ENOENT') {\n throw new ConfigError(`Cannot read config at ${configPath}: ${e.message}`);\n }\n }\n\n let parsed: TOML.JsonMap = {};\n if (raw !== null) {\n try {\n parsed = TOML.parse(raw);\n } catch (err) {\n throw new ConfigError(`failed to parse config TOML: ${String(err)}`);\n }\n }\n\n // Runtime-only view of the config — the TOML schema nests api_key under\n // [default], so lift it to the top-level `apiKey` field expected by\n // callers like commands/daemon.ts. The keychain placeholder resolver still\n // runs across the full tree below.\n const defaultSection = (parsed as { default?: { api_key?: string; base_url?: string; environment?: string } }).default;\n const flat: PrismerConfig = {\n ...(parsed as unknown as PrismerConfig),\n };\n if (defaultSection?.api_key !== undefined && flat.apiKey === undefined) {\n flat.apiKey = defaultSection.api_key;\n }\n if (defaultSection?.base_url !== undefined && flat.apiBase === undefined) {\n flat.apiBase = defaultSection.base_url;\n }\n\n // v1.9.0 B.2: PRISMER_API_KEY env is the final fallback for out-of-band\n // injection (Docker -e, CI, non-interactive installs). Env wins over missing\n // config but does NOT override an existing config value, so a deliberately\n //-selected key in config.toml stays authoritative.\n if (flat.apiKey === undefined) {\n const envKey = process.env['PRISMER_API_KEY'];\n if (envKey !== undefined && envKey.length > 0) {\n flat.apiKey = envKey;\n }\n }\n\n if (!opts?.keychain || !resolvePlaceholders) {\n return flat;\n }\n\n const resolved = await walkAndResolve(flat as unknown as JsonValue, opts.keychain, resolvePlaceholders);\n return resolved as unknown as PrismerConfig;\n}\n\n// ============================================================\n// writeConfig\n// ============================================================\n\nexport async function writeConfig(config: PrismerConfig, opts?: { path?: string }): Promise<void> {\n const configPath = opts?.path ?? defaultConfigPath();\n const parentDir = path.dirname(configPath);\n fs.mkdirSync(parentDir, { recursive: true, mode: 0o700 });\n // Best-effort: clamp existing parent dir to owner-only (mkdirSync won't chmod an existing dir)\n try { fs.chmodSync(parentDir, 0o700); } catch { /* not critical */ }\n\n const serialized = TOML.stringify(config as TOML.JsonMap);\n const tmp = configPath + '.tmp';\n // Write with owner-only mode so the file is never world-readable, even momentarily\n fs.writeFileSync(tmp, serialized, { encoding: 'utf-8', mode: 0o600 });\n // Defensive chmod in case the file already existed with looser permissions\n try { fs.chmodSync(tmp, 0o600); } catch { /* best-effort */ }\n fs.renameSync(tmp, configPath);\n}\n","// T11 — migrate-secrets command: scan config.toml, move plaintext secrets to keychain\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport TOML from '@iarna/toml';\nimport { parseKeyringPlaceholder, ConfigError } from '../config.js';\nimport type { Keychain } from '../keychain.js';\n\n// ============================================================\n// Public types\n// ============================================================\n\nexport interface MigrateStep {\n level: 'info' | 'ok' | 'warn' | 'error';\n message: string;\n detail?: string;\n}\n\nexport interface MigrateSecretsOptions {\n configPath?: string;\n keychain: Keychain;\n dryRun?: boolean;\n onStep?: (step: MigrateStep) => void;\n}\n\nexport interface MigrateSecretsResult {\n migrated: Array<{ path: string; service: string; account: string }>;\n skipped: Array<{ path: string; reason: string }>;\n errors: Array<{ path: string; error: string }>;\n}\n\n// ============================================================\n// Secret detection heuristics\n// ============================================================\n\nconst SECRET_KEY_NAMES = new Set([\n 'apikey', 'api_key', 'token', 'accesstoken', 'secret', 'password',\n]);\n\n// I7: expanded to cover common vendor-prefixed token shapes in addition to sk-*\n// Patterns: sk-* (OpenAI/Prismer), xox[bpa]-* (Slack), gh[pousr]_* (GitHub),\n// AKIA* (AWS access key), AIza* (Google API key), pk/sk_live/test_* (Stripe)\nconst SECRET_VALUE_RE = /^(sk-[a-zA-Z0-9_-]{20,}|xox[bpa]-[a-zA-Z0-9-]{20,}|gh[pousr]_[a-zA-Z0-9_]{20,}|AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{35}|(?:pk|sk)_(?:live|test)_[a-zA-Z0-9]{20,})$/;\n\n// I7: high-entropy pattern — matches long alphanum strings that did NOT auto-migrate;\n// used to emit a warning only (not auto-migrate)\nconst HIGH_ENTROPY_RE = /^[A-Za-z0-9_-]{20,}$/;\n\nfunction isSecretKey(keyName: string): boolean {\n return SECRET_KEY_NAMES.has(keyName.toLowerCase());\n}\n\nfunction isSecretValue(value: string): boolean {\n return SECRET_VALUE_RE.test(value);\n}\n\nfunction shouldMigrate(keyBasename: string, value: string): boolean {\n if (isSecretKey(keyBasename)) return true;\n if (isSecretValue(value)) return true;\n return false;\n}\n\nfunction looksHighEntropy(value: string): boolean {\n return value.length > 20 && HIGH_ENTROPY_RE.test(value);\n}\n\n// ============================================================\n// Recursive tree walker\n// ============================================================\n\ntype JsonValue = string | number | boolean | null | JsonValue[] | { [k: string]: JsonValue };\n\nasync function walkTree(\n node: JsonValue,\n keyPath: string[],\n keychain: Keychain,\n dryRun: boolean,\n result: MigrateSecretsResult,\n emit: (step: MigrateStep) => void,\n): Promise<JsonValue> {\n if (typeof node === 'string') {\n const dotPath = keyPath.join('.');\n const basename = keyPath[keyPath.length - 1] ?? '';\n\n if (node.startsWith('$KEYRING:')) {\n result.skipped.push({ path: dotPath, reason: 'already a $KEYRING reference' });\n emit({ level: 'info', message: `Skipping ${dotPath} (already a $KEYRING reference)` });\n return node;\n }\n\n if (!shouldMigrate(basename, node)) {\n // I7: warn on long high-entropy strings that weren't auto-migrated\n if (looksHighEntropy(node)) {\n emit({\n level: 'warn',\n message: `${dotPath} looks secret-like (${node.slice(0, 6)}…); migrate manually if needed`,\n });\n }\n return node;\n }\n\n const slug = keyPath.join('_');\n const service = 'prismer-config';\n const account = slug;\n const placeholder = `$KEYRING:${service}/${account}`;\n\n try {\n emit({ level: 'info', message: `Migrating ${dotPath} → keychain (${service}/${account})` });\n\n if (!dryRun) {\n await keychain.set(service, account, node);\n }\n\n result.migrated.push({ path: dotPath, service, account });\n emit({ level: 'ok', message: `Migrated ${dotPath} → keychain (${service}/${account})` });\n return placeholder;\n } catch (err) {\n const errMsg = String(err);\n result.errors.push({ path: dotPath, error: errMsg });\n emit({ level: 'error', message: `Failed to migrate ${dotPath}: ${errMsg}` });\n return node;\n }\n }\n\n if (Array.isArray(node)) {\n const results: JsonValue[] = [];\n for (let i = 0; i < node.length; i++) {\n const item = await walkTree(node[i], [...keyPath, String(i)], keychain, dryRun, result, emit);\n results.push(item);\n }\n return results;\n }\n\n if (node !== null && typeof node === 'object') {\n const updated: { [k: string]: JsonValue } = {};\n for (const [k, v] of Object.entries(node)) {\n updated[k] = await walkTree(v as JsonValue, [...keyPath, k], keychain, dryRun, result, emit);\n }\n return updated;\n }\n\n return node;\n}\n\n// ============================================================\n// Backup helper\n// ============================================================\n\nfunction backupConfig(configPath: string): void {\n const bakPath = configPath + '.bak';\n if (fs.existsSync(bakPath)) {\n const ts = Date.now();\n const tsBakPath = `${configPath}.bak.${ts}`;\n fs.copyFileSync(configPath, tsBakPath);\n // I6: backup file must not be world-readable\n fs.chmodSync(tsBakPath, 0o600);\n } else {\n fs.copyFileSync(configPath, bakPath);\n // I6: backup file must not be world-readable\n fs.chmodSync(bakPath, 0o600);\n }\n}\n\n// ============================================================\n// Default config path\n// ============================================================\n\nfunction defaultConfigPath(): string {\n return path.join(os.homedir(), '.prismer', 'config.toml');\n}\n\n// ============================================================\n// migrateSecrets\n// ============================================================\n\nexport async function migrateSecrets(opts: MigrateSecretsOptions): Promise<MigrateSecretsResult> {\n const configPath = opts.configPath ?? defaultConfigPath();\n const dryRun = opts.dryRun ?? false;\n const emit = opts.onStep ?? (() => undefined);\n\n const result: MigrateSecretsResult = { migrated: [], skipped: [], errors: [] };\n\n emit({ level: 'info', message: `Reading config from ${configPath}` });\n\n if (!fs.existsSync(configPath)) {\n emit({ level: 'info', message: 'no config to migrate' });\n return result;\n }\n\n let raw: string;\n try {\n raw = fs.readFileSync(configPath, 'utf-8');\n } catch (err) {\n emit({ level: 'error', message: `Failed to read config: ${String(err)}` });\n return result;\n }\n\n let parsed: TOML.JsonMap;\n try {\n parsed = TOML.parse(raw);\n } catch (err) {\n throw new ConfigError(`failed to parse config TOML: ${String(err)}`);\n }\n\n const updated = await walkTree(\n parsed as unknown as JsonValue,\n [],\n opts.keychain,\n dryRun,\n result,\n emit,\n );\n\n if (!dryRun && result.migrated.length > 0) {\n backupConfig(configPath);\n emit({ level: 'info', message: `Backed up original config to ${configPath}.bak` });\n\n const serialized = TOML.stringify(updated as unknown as TOML.JsonMap);\n const tmp = configPath + '.tmp';\n fs.writeFileSync(tmp, serialized, 'utf-8');\n // I6: rewritten config must not be world-readable before atomic rename\n fs.chmodSync(tmp, 0o600);\n fs.renameSync(tmp, configPath);\n emit({ level: 'ok', message: `Config rewritten with $KEYRING references` });\n }\n\n emit({\n level: 'ok',\n message: `Done. ${result.migrated.length} migrated, ${result.skipped.length} skipped, ${result.errors.length} errors.`,\n });\n\n return result;\n}\n\n// Re-export parseKeyringPlaceholder for test convenience\nexport { parseKeyringPlaceholder, ConfigError };\n","// T14 — Composed daemon runner: DaemonProcess + EventBus + AgentSupervisor + DaemonHttpServer\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport * as crypto from 'node:crypto';\nimport { DaemonProcess } from '../daemon-process.js';\nimport { EventBus } from '../event-bus.js';\nimport { TraceWriterManager } from '../trace-writer.js';\nimport { AgentSupervisor } from '../agent-supervisor.js';\nimport { DaemonHttpServer } from '../daemon-http.js';\nimport { TransportManager } from '../multi-path-transport.js';\nimport { MemoryGatewayAPI } from '../memory-gateway.js';\nimport { EvolutionGatewayHttpHandler } from '../evolution-gateway.js';\nimport { TaskRouter } from '../task-router.js';\nimport { generateKeyPair, serializeKeyPair, type KeyPair } from '../e2ee-crypto.js';\nimport type { AuthenticatedIdentity } from '../daemon-http.js';\nimport { deriveWsFromHttp } from '../cloud-url.js';\nimport { EventsTailer } from './events-tailer.js';\nimport { loadPublishedRegistry } from '../agents/published-registry.js';\nimport type { FsContext } from '@prismer/sandbox-runtime';\n\n// ============================================================\n// Types\n// ============================================================\n\nexport interface DaemonRunnerOptions {\n host?: string;\n port?: number; // default 3210\n pidFile?: string;\n dataDir?: string;\n installSignalHandlers?: boolean;\n authBearer?: string; // optional single-token bearer auth; undefined = localhost trust\n apiKey?: string; // Prismer API key for relay connection\n daemonId?: string; // Daemon ID for relay registration\n userId?: string; // User ID for relay registration\n enableTransport?: boolean; // enable multi-path transport (default: true)\n forceProbe?: boolean; // force re-probe on startup\n workspace?: string; // default FS sandbox workspace\n /**\n * v1.9.0 B.7.a — cloud base URL (https://prismer.cloud for prod,\n * https://cloud.prismer.dev for test). Forwarded to EvolutionGateway so\n * daemon→cloud calls hit the same env the API key was issued against.\n */\n cloudApiBase?: string;\n}\n\nexport interface DaemonRunnerHandle {\n stop(): Promise<void>;\n readonly url: string;\n readonly pid: number;\n readonly dataDir: string;\n}\n\n// ============================================================\n// startDaemonRunner\n// ============================================================\n\nexport async function startDaemonRunner(opts?: DaemonRunnerOptions): Promise<DaemonRunnerHandle> {\n const home = os.homedir();\n const pidFile = opts?.pidFile ?? path.join(home, '.prismer', 'daemon.pid');\n const dataDir = opts?.dataDir ?? path.join(home, '.prismer');\n const port = opts?.port ?? 3210;\n const host = opts?.host ?? '127.0.0.1';\n const lanHost = resolveLanHostForDaemon(host);\n const enableTransport = opts?.enableTransport ?? true;\n const forceProbe = opts?.forceProbe ?? false;\n\n // 1. Start DaemonProcess (writes PID, installs signal handlers per opt)\n const daemonProcess = new DaemonProcess({\n pidFile,\n dataDir,\n installSignalHandlers: opts?.installSignalHandlers ?? true,\n });\n await daemonProcess.start();\n\n // 2. EventBus\n const eventBus = new EventBus();\n\n // 2b. PARA L8 session trace writer — captures pre-compaction event stream\n // to <dataDir>/trace/<sessionId>.jsonl.zst (append-only + zstd frames).\n // See docs/version190/03-para-spec.md §4.2 L8.\n const traceManager = new TraceWriterManager({ traceDir: path.join(dataDir, 'trace') });\n eventBus.subscribe('*', traceManager.handle);\n\n // 3. AgentSupervisor\n const supervisor = new AgentSupervisor({ eventBus });\n\n // 3b. AdapterRegistry + DispatchMux (Sprint A3, D4 dispatch)\n // The registry is the single source-of-truth for which adapters this\n // daemon can dispatch to. Adapter modules (claude-code-plugin,\n // openclaw-channel, prismer-adapter-hermes) register themselves on\n // load via adapterRegistry.register(). Cloud task → daemon command →\n // dispatchMux.dispatch() → adapter.dispatch() → result back to cloud.\n const { AdapterRegistry } = await import('../adapter-registry.js');\n const { DispatchMux } = await import('../dispatch-mux.js');\n const adapterRegistry = new AdapterRegistry();\n const dispatchMux = new DispatchMux(adapterRegistry);\n // Expose globally so adapter plug-ins loaded out-of-band can register.\n (globalThis as any).__prismerAdapterRegistry = adapterRegistry;\n (globalThis as any).__prismerDispatchMux = dispatchMux;\n\n // Auto-detect installed agents and register CLI-spawn adapters for\n // each. Adapters that publish their own AdapterImpl module register\n // themselves first and the auto-registrar yields to them.\n try {\n const { autoRegisterAdapters } = await import('../adapters/auto-register.js');\n const auto = await autoRegisterAdapters(adapterRegistry);\n if (auto.registered.length > 0) {\n console.log(\n '[DaemonRunner] Auto-registered adapters:',\n auto.registered.map((r) => `${r.name}(${r.binary})`).join(', '),\n );\n }\n if (auto.skipped.length > 0) {\n const notInstalled = auto.skipped.filter((s) => s.reason === 'not_installed').map((s) => s.name);\n if (notInstalled.length > 0) {\n console.log('[DaemonRunner] Adapters not installed (skipped):', notInstalled.join(', '));\n }\n const errors = auto.skipped.filter((s) => s.reason !== 'not_installed' && s.reason !== 'already_registered');\n for (const e of errors) {\n console.warn(`[DaemonRunner] Adapter skipped (${e.name}): ${e.reason}`);\n }\n }\n } catch (err) {\n console.warn('[DaemonRunner] Adapter auto-register failed:', err);\n }\n\n // 4. Generate or load the daemon E2EE keypair. Pairing offers need this even\n // when cloud transport is not configured yet.\n const keypairFile = path.join(dataDir, 'e2ee-keypair.json');\n let localKeyPair: KeyPair | undefined;\n try {\n fs.mkdirSync(dataDir, { recursive: true });\n if (fs.existsSync(keypairFile)) {\n const keypairData = JSON.parse(fs.readFileSync(keypairFile, 'utf-8'));\n localKeyPair = {\n publicKey: Buffer.from(keypairData.publicKey, 'base64'),\n privateKey: Buffer.from(keypairData.privateKey, 'base64'),\n };\n console.log('[DaemonRunner] Loaded existing E2EE keypair');\n } else {\n localKeyPair = generateKeyPair();\n const serialized = serializeKeyPair(localKeyPair);\n fs.writeFileSync(keypairFile, JSON.stringify(serialized, null, 2), {\n encoding: 'utf-8',\n mode: 0o600,\n });\n console.log('[DaemonRunner] Generated new E2EE keypair');\n }\n } catch (err) {\n console.warn('[DaemonRunner] Failed to load/generate E2EE keypair:', err);\n }\n\n // 5. Multi-path Transport Manager (optional)\n let transportManager: TransportManager | undefined;\n if (enableTransport && opts?.apiKey && opts?.daemonId && opts?.userId && opts?.cloudApiBase) {\n console.log('[DaemonRunner] Initializing multi-path transport');\n\n if (localKeyPair) {\n transportManager = new TransportManager({\n apiKey: opts.apiKey!,\n daemonId: opts.daemonId!,\n userId: opts.userId!,\n cloudApiBase: opts.cloudApiBase!,\n localKeyPair,\n dataDir,\n lanPort: port,\n lanHost,\n });\n\n // Bug B: publish the manager on globalThis BEFORE start() resolves so the\n // HTTP /transport/status handler can see it during the initial probe pass.\n // Previously this ran after `await transportManager.start()` — which takes\n // 10–30s of WSS handshakes on cold-boot — causing the handler to fall back\n // to the \"disabled\" canned response while the prober was actively firing.\n (globalThis as any).__transportManager = transportManager;\n\n // Set up transport event handlers\n transportManager.on('connected', (info) => {\n console.log('[DaemonRunner] Transport connected:', info);\n });\n\n transportManager.on('disconnected', (info) => {\n console.log('[DaemonRunner] Transport disconnected:', info);\n });\n\n transportManager.on('switched', (info) => {\n console.log('[DaemonRunner] Transport switched:', info);\n });\n\n transportManager.on('error', (err) => {\n console.error('[DaemonRunner] Transport error:', err);\n });\n\n transportManager.on('command', async (command) => {\n console.log('[DaemonRunner] Received remote command:', command);\n eventBus.publish('remote-command', command);\n\n // v1.9.x remote command dispatch. Currently iOS scope: 'agent_restart' only (Q-005 (C)).\n // Semantic: route to the adapter's reset() (v1.9.27+) — NOT supervisor.restart.\n // PARA adapters are not long-running processes; restart means \"adapter clears per-agent state\".\n // See docs/mobile190/ARCHITECTURE.md §[AgentSupervisor vs AdapterRegistry].\n let result: { ok: boolean; [key: string]: unknown };\n try {\n const agentId = (command.payload && (command.payload as any).agentId) as string | undefined;\n switch (command.type) {\n case 'agent_restart': {\n if (!agentId) {\n result = { ok: false, error: 'agentId required in envelope for agent_restart' };\n break;\n }\n // G-22: cloud sends cloudAgentId; resolve to the published-agents\n // entry for this daemon so we know which adapter owns it and what\n // short name to pass to reset().\n let entry: { name: string; adapter?: string; localAgentId?: string } | undefined;\n try {\n entry = loadPublishedRegistry().find((a) => a.cloudAgentId === agentId);\n } catch (err) {\n // Registry read failure: log + fall through to the missing-entry branch.\n console.warn('[DaemonRunner] published-agents registry read failed:', (err as Error).message);\n }\n if (!entry) {\n result = {\n ok: false,\n error: `unknown agentId for this daemon: ${agentId} (not in published-agents.toml)`,\n };\n break;\n }\n // Adapter name: prefer entry.adapter, fall back to entry.name\n // (older publish writes didn't set adapter explicitly).\n const adapterName = entry.adapter ?? entry.name;\n const adapter = adapterRegistry.get(adapterName);\n if (!adapter) {\n result = {\n ok: false,\n error: `adapter not registered: ${adapterName}`,\n agentId,\n adapter: adapterName,\n };\n break;\n }\n if (typeof adapter.reset !== 'function') {\n // Adapter predates the reset() contract. Ack cleanly so cloud\n // doesn't treat it as a hard failure — iOS shows \"restarted\"\n // even though no state actually changed.\n result = {\n ok: true,\n state: 'no_reset_support',\n agentId,\n adapter: adapterName,\n };\n break;\n }\n const resetResult = await adapter.reset(entry.name);\n result = {\n ...resetResult,\n ok: resetResult.ok,\n agentId,\n adapter: adapterName,\n };\n break;\n }\n // 'agent_start' / 'agent_stop' intentionally unimplemented in v1.9.x (Q-005 (C) @prismer 2026-04-21)\n default:\n console.warn('[DaemonRunner] Unhandled remote command type:', command.type);\n result = { ok: false, error: `unsupported command type: ${command.type}` };\n }\n } catch (err) {\n console.error('[DaemonRunner] Remote command dispatch failed:', err);\n result = { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n\n // Ack back to cloud — best-effort. Failure to send ack should not crash the handler.\n try {\n const tm = transportManager as unknown as {\n sendControl?: (msg: unknown) => boolean;\n };\n tm.sendControl?.({ type: 'command.result', commandId: command.id, result });\n } catch (ackErr) {\n console.warn('[DaemonRunner] Failed to ack remote command:', ackErr);\n }\n });\n\n // Sprint C0 — bridge cloud rpc.request 'task.dispatch' to DispatchMux\n // so cloud's TaskRouter can run a task step on the local adapter.\n // v1.9.x Task 2 — wire ArtifactUploader so adapter-produced artifacts\n // get uploaded to cloud and stamped with cloudUploadId on the result.\n try {\n const { registerDispatchRpcHandlers } = await import('../dispatch-rpc.js');\n const { ArtifactUploader } = await import('../artifacts-uploader.js');\n const artifactUploader =\n opts?.apiKey && opts?.cloudApiBase\n ? new ArtifactUploader({ apiKey: opts.apiKey, cloudApiBase: opts.cloudApiBase })\n : undefined;\n registerDispatchRpcHandlers(transportManager as any, {\n mux: dispatchMux,\n registry: adapterRegistry,\n ...(artifactUploader ? { artifactUploader } : {}),\n });\n console.log(\n `[DaemonRunner] Dispatch RPC handlers registered (task.dispatch / list / resolve)${\n artifactUploader ? ' + artifact uploader' : ''\n }`,\n );\n } catch (err) {\n console.warn('[DaemonRunner] Failed to register dispatch RPC handlers:', err);\n }\n\n // Bug A: start the transport manager in the background rather than\n // awaiting it. `start()` synchronously calls `probeAndSelect()`, which\n // runs 5× WSS handshakes against the relay — on a cold Docker container\n // with an unreachable cloud this blocks ~15–30s. Awaiting it delayed\n // `httpServer.start()` + the `daemon.port` sidecar write by the same\n // margin, during which the CLI reported \"Daemon started\" but no\n // port file existed yet and the HTTP server wasn't accepting requests.\n // Fire-and-forget is safe: TransportManager handles its own errors\n // (logs 'relay: FAILED', schedules retries) and state is published via\n // __transportManager + getStatus() so the HTTP handler can reflect the\n // probing/unreachable state as it evolves.\n void transportManager.start().then(async () => {\n if (forceProbe) {\n console.log('[DaemonRunner] Force re-probing transport paths');\n await transportManager!.forceReprobe();\n }\n }).catch((err) => {\n console.error('[DaemonRunner] Transport manager start failed:', err);\n });\n\n // Register transport shutdown handler\n daemonProcess.onShutdown({\n name: 'transport-manager',\n handler: async () => {\n if (transportManager) {\n await transportManager.stop();\n }\n },\n });\n }\n } else if (enableTransport) {\n console.log('[DaemonRunner] Multi-path transport disabled (missing apiKey/daemonId/userId/cloudApiBase)');\n }\n\n // 5b. Heartbeat loop for published agents (Sprint A2.3, D3 liveness).\n // Only runs when this daemon has cloud identity — otherwise there is\n // no cloud to heartbeat to. The loop loads the published-agents\n // registry on every tick so `prismer agent publish/unpublish` reflects\n // immediately without restarting the daemon.\n if (opts?.apiKey && opts?.daemonId && opts?.cloudApiBase) {\n const { startHeartbeatLoop } = await import('../agents/heartbeat-loop.js');\n const heartbeatLoop = startHeartbeatLoop({\n apiKey: opts.apiKey,\n daemonId: opts.daemonId,\n cloudApiBase: opts.cloudApiBase,\n });\n daemonProcess.onShutdown({\n name: 'heartbeat-loop',\n handler: async () => heartbeatLoop.stop(),\n });\n console.log('[DaemonRunner] Heartbeat loop started (30s interval)');\n } else {\n console.log('[DaemonRunner] Heartbeat loop disabled (missing apiKey/daemonId/cloudApiBase)');\n }\n\n // 4. Authenticate: if authBearer is set, only accept that exact token.\n // /health is always public (handled inside DaemonHttpServer before auth check).\n //\n // v1.9.0 B.7.b — derive a stable agentId from the user-supplied identity\n // rather than hard-coding `__http_client__`. The cloud evolution service uses\n // this value as the `X-Prismer-AgentId` header, so collapsing every caller\n // into one literal led to unusable rollups. Fingerprint keeps the raw API\n // key off the wire while still being deterministic across daemon restarts.\n const authBearerFingerprint =\n opts?.authBearer !== undefined\n ? crypto.createHash('sha256').update(opts.authBearer).digest('hex').slice(0, 16)\n : undefined;\n const authenticate = opts?.authBearer !== undefined\n ? (token: string | undefined): AuthenticatedIdentity | null => {\n if (token !== opts.authBearer) return null;\n const derivedAgentId = opts.userId ?? `daemon:${authBearerFingerprint ?? 'anon'}`;\n return { agentId: derivedAgentId };\n }\n : undefined;\n\n // 5. Default FS context. More specific agent/workspace policy registries can\n // layer on top later; the product path must still expose a working sandbox.\n const defaultWorkspace = path.resolve(opts?.workspace ?? process.cwd());\n const fsContextProvider = (req: { agentId: string; workspace?: string }): FsContext | undefined => {\n const requestedWorkspace = path.resolve(req.workspace ?? defaultWorkspace);\n const workspace = requestedWorkspace === defaultWorkspace || requestedWorkspace.startsWith(defaultWorkspace + path.sep)\n ? requestedWorkspace\n : defaultWorkspace;\n return {\n agentId: req.agentId,\n workspace,\n mode: 'default',\n rules: [],\n };\n };\n\n // 5b. Register FS RPC handlers on the transport manager so cloud relay\n // (mobile → cloud → daemon) can reach the sandbox. Same FS primitives as\n // the local HTTP path, just different transport and audit callPath.\n if (transportManager) {\n const { registerFsRpcHandlers } = await import('../http/fs-rpc.js');\n registerFsRpcHandlers(transportManager, { fsContextProvider });\n }\n\n // 6. DaemonHttpServer\n const httpServer = new DaemonHttpServer({\n host,\n port,\n eventBus,\n supervisor,\n authenticate,\n fsContextProvider,\n });\n\n const memoryGateway = new MemoryGatewayAPI({ enabled: false }, {\n filePath: path.join(dataDir, 'memory.json'),\n });\n memoryGateway.registerRoutes(httpServer);\n\n const taskRouter = new TaskRouter({\n eventBus,\n supervisor,\n apiToken: opts?.apiKey,\n });\n taskRouter.registerRoutes(httpServer);\n\n const evolutionGateway = new EvolutionGatewayHttpHandler({\n eventBus,\n supervisor,\n authenticate,\n // v1.9.0 B.7.a — forward the daemon's API key as the outbound Bearer so\n // cloud /api/im/evolution/* sees an authenticated caller instead of 401.\n cloudApiKey: opts?.apiKey,\n cloudApiBase: opts?.cloudApiBase,\n });\n for (const [key, handler] of evolutionGateway.getRoutes()) {\n const sep = key.indexOf(':');\n if (sep < 0) continue;\n const method = key.slice(0, sep) as 'GET' | 'POST' | 'PATCH' | 'DELETE';\n const routePath = key.slice(sep + 1);\n httpServer.registerRoute(method, routePath, handler);\n }\n\n // v1.9.0 Track T3: PARA events tailer — polls ~/.prismer/para/events.jsonl\n // and uploads new lines to cloud POST /api/im/para/events. Only starts when\n // we have an apiKey + cloudApiBase (same gate as relay).\n let eventsTailer: EventsTailer | undefined;\n if (opts?.apiKey && opts?.cloudApiBase) {\n eventsTailer = new EventsTailer({\n apiKey: opts.apiKey,\n cloudApiBase: opts.cloudApiBase,\n });\n eventsTailer.start();\n daemonProcess.onShutdown({\n name: 'events-tailer',\n handler: async () => eventsTailer?.stop(),\n });\n } else {\n console.log('[DaemonRunner] PARA events tailer disabled (missing apiKey/cloudApiBase)');\n }\n\n const pairingOffers = new Map<string, { expiresAt: number; deviceName?: string }>();\n httpServer.registerRoute('POST', '/pair/offer', (_req, res, ctx) => {\n let ttlSec = 300;\n try {\n if (ctx.body.length > 0) {\n const parsed = JSON.parse(ctx.body.toString('utf8')) as { ttlSec?: number; deviceName?: string };\n if (typeof parsed.ttlSec === 'number' && parsed.ttlSec > 0) {\n ttlSec = Math.min(parsed.ttlSec, 15 * 60);\n }\n }\n } catch {\n // Keep the default TTL for malformed optional body fields.\n }\n const offer = cryptoRandomToken();\n const expiresAt = Date.now() + ttlSec * 1000;\n pairingOffers.set(offer, { expiresAt });\n const daemonPubKey = localKeyPair\n ? serializeKeyPair(localKeyPair).publicKey\n : undefined;\n const payload = JSON.stringify({\n offer,\n uri: `prismer://pair?offer=${encodeURIComponent(offer)}`,\n expiresAt,\n daemonId: opts?.daemonId,\n daemonPubKey,\n relayUrl: opts?.apiKey ? deriveWsFromHttp(opts?.cloudApiBase) : undefined,\n lanHost,\n lanPort: boundPortForOffer(httpServer),\n });\n res.writeHead(200, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) });\n res.end(payload);\n });\n\n // Sprint A3 — Adapter Registry HTTP surface (path /api/v1/adapters\n // is mounted by daemon-http.ts via the /api/v1 prefix).\n httpServer.registerRoute('GET', '/adapters', (_req, res) => {\n const list = adapterRegistry.list();\n const payload = JSON.stringify({ ok: true, adapters: list });\n res.writeHead(200, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) });\n res.end(payload);\n });\n\n // v1.9.x Task 3 — Mode B AdapterImpl registration.\n // Plug-ins running in a sibling agent process (e.g. OpenClaw with the\n // @prismer/openclaw-channel plug-in) POST { name, loopbackUrl } here.\n // We validate the loopback URL is 127.0.0.1:<port>, build a Mode B\n // AdapterImpl whose dispatch() bridges to that loopback, and call\n // adapterRegistry.register(...) which REPLACES any existing CLI-shim\n // entry. Localhost-only — no auth (loopback validation is the boundary).\n httpServer.registerRoute('POST', '/adapters/register-mode-b', async (_req, res, ctx) => {\n let body: any;\n try {\n body = ctx.body.length > 0 ? JSON.parse(ctx.body.toString('utf8')) : {};\n } catch {\n const err = JSON.stringify({ ok: false, error: 'invalid_json' });\n res.writeHead(400, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(err) });\n res.end(err);\n return;\n }\n if (typeof body !== 'object' || body === null) {\n const err = JSON.stringify({ ok: false, error: 'body must be an object' });\n res.writeHead(400, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(err) });\n res.end(err);\n return;\n }\n if (typeof body.name !== 'string' || body.name.length === 0) {\n const err = JSON.stringify({ ok: false, error: 'name (string) required' });\n res.writeHead(400, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(err) });\n res.end(err);\n return;\n }\n if (typeof body.loopbackUrl !== 'string' || body.loopbackUrl.length === 0) {\n const err = JSON.stringify({ ok: false, error: 'loopbackUrl (string) required' });\n res.writeHead(400, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(err) });\n res.end(err);\n return;\n }\n // Adapter must exist in the catalog so iOS / cloud know what it is.\n const { getAgent } = await import('../agents/registry.js');\n const catalogEntry = getAgent(body.name);\n if (!catalogEntry) {\n const err = JSON.stringify({\n ok: false,\n error: `unknown_adapter:${body.name} (not in catalog)`,\n });\n res.writeHead(400, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(err) });\n res.end(err);\n return;\n }\n let modeBAdapter;\n try {\n const { buildModeBAdapter } = await import('../adapters/mode-b.js');\n modeBAdapter = buildModeBAdapter({\n name: body.name,\n loopbackUrl: body.loopbackUrl,\n tiersSupported: catalogEntry.tiersSupported,\n capabilityTags: catalogEntry.capabilityTags,\n });\n } catch (err) {\n const payload = JSON.stringify({\n ok: false,\n error: `invalid_loopback:${(err as Error).message}`,\n });\n res.writeHead(400, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) });\n res.end(payload);\n return;\n }\n const replaced = adapterRegistry.has(body.name);\n try {\n adapterRegistry.register(modeBAdapter);\n } catch (err) {\n const payload = JSON.stringify({\n ok: false,\n error: `register_failed:${(err as Error).message}`,\n });\n res.writeHead(500, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) });\n res.end(payload);\n return;\n }\n console.log(\n `[DaemonRunner] Mode B adapter registered: ${body.name} → ${body.loopbackUrl}` +\n (replaced ? ' (replaced existing CLI shim)' : ''),\n );\n const ok = JSON.stringify({ ok: true, replaced });\n res.writeHead(200, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(ok) });\n res.end(ok);\n });\n\n httpServer.registerRoute('POST', '/adapters/dispatch', async (_req, res, ctx) => {\n let body: any;\n try {\n body = ctx.body.length > 0 ? JSON.parse(ctx.body.toString('utf8')) : {};\n } catch {\n const err = JSON.stringify({ ok: false, error: 'invalid_json' });\n res.writeHead(400, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(err) });\n res.end(err);\n return;\n }\n if (typeof body.taskId !== 'string' || typeof body.capability !== 'string' || typeof body.prompt !== 'string') {\n const err = JSON.stringify({ ok: false, error: 'taskId, capability, prompt required' });\n res.writeHead(400, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(err) });\n res.end(err);\n return;\n }\n const result = await dispatchMux.dispatch({\n taskId: body.taskId,\n stepIdx: typeof body.stepIdx === 'number' ? body.stepIdx : undefined,\n capability: body.capability,\n prompt: body.prompt,\n metadata: body.metadata,\n preferAdapter: typeof body.preferAdapter === 'string' ? body.preferAdapter : undefined,\n deadlineAt: typeof body.deadlineAt === 'number' ? body.deadlineAt : undefined,\n });\n const status = result.ok ? 200 : 400;\n const payload = JSON.stringify({ ok: result.ok, result });\n res.writeHead(status, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) });\n res.end(payload);\n });\n\n httpServer.registerRoute('GET', '/pair/status', (req, res) => {\n const url = new URL(req.url ?? '/', 'http://localhost');\n const offer = url.searchParams.get('offer') ?? '';\n const record = pairingOffers.get(offer);\n const paired = false;\n if (record && record.expiresAt <= Date.now()) {\n pairingOffers.delete(offer);\n }\n const payload = JSON.stringify({\n paired,\n expiresAt: record?.expiresAt,\n });\n res.writeHead(200, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) });\n res.end(payload);\n });\n\n const portFile = path.join(dataDir, 'daemon.port');\n\n let serverUrl: string;\n let boundPort: number;\n try {\n const bound = await httpServer.start();\n serverUrl = `http://${bound.host}:${bound.port}`;\n boundPort = bound.port;\n } catch (err) {\n // If HTTP bind fails, shut down the daemon process cleanly before rethrowing.\n await daemonProcess.shutdown('manual');\n throw err;\n }\n\n // Write bound port to sidecar file (atomic tmp+rename, mode 0600).\n // Trailing newline matches README promise + is friendlier to `cat`.\n try {\n fs.mkdirSync(dataDir, { recursive: true });\n const tmp = portFile + '.tmp';\n fs.writeFileSync(tmp, String(boundPort) + '\\n', { encoding: 'utf-8', mode: 0o600 });\n fs.renameSync(tmp, portFile);\n } catch (err) {\n // Best-effort — don't crash the daemon if sidecar write fails. Log so\n // Docker/CI operators can diagnose FS permission issues on the data dir.\n console.warn(`[DaemonRunner] Failed to write ${portFile}:`, err);\n }\n\n // 7. Register LIFO shutdown handlers on DaemonProcess:\n // Order matters: supervisor shuts down first, then HTTP server.\n daemonProcess.onShutdown({\n name: 'http-server',\n handler: async () => {\n memoryGateway.shutdown();\n await httpServer.stop(5000);\n },\n });\n\n daemonProcess.onShutdown({\n name: 'agent-supervisor',\n handler: async () => {\n await supervisor.shutdown();\n },\n });\n\n daemonProcess.onShutdown({\n name: 'trace-writer-manager',\n handler: async () => {\n traceManager.shutdown();\n },\n });\n\n // Remove port sidecar on clean shutdown\n daemonProcess.onShutdown({\n name: 'port-sidecar-cleanup',\n handler: async () => {\n try { fs.rmSync(portFile, { force: true }); } catch { /* ignore */ }\n },\n });\n\n // 8. Return handle\n const handle: DaemonRunnerHandle = {\n get url() { return serverUrl; },\n get pid() { return process.pid; },\n get dataDir() { return dataDir; },\n async stop() {\n await daemonProcess.shutdown('manual');\n },\n };\n\n return handle;\n}\n\nfunction cryptoRandomToken(): string {\n return crypto.randomBytes(24).toString('base64url');\n}\n\nfunction boundPortForOffer(httpServer: DaemonHttpServer): number | undefined {\n const url = httpServer.url;\n if (!url) return undefined;\n const port = Number(new URL(url).port);\n return Number.isFinite(port) && port > 0 ? port : undefined;\n}\n\nfunction resolveLanHostForDaemon(host: string): string | undefined {\n if (host === '0.0.0.0' || host === '::') {\n return findLanIPv4();\n }\n if (host === 'localhost' || host === '::1' || host.startsWith('127.') || host.startsWith('169.254.')) {\n return undefined;\n }\n return host;\n}\n\nfunction findLanIPv4(): string | undefined {\n const nets = os.networkInterfaces();\n for (const entries of Object.values(nets)) {\n for (const entry of entries ?? []) {\n if (entry.family !== 'IPv4' || entry.internal) continue;\n if (entry.address.startsWith('127.') || entry.address.startsWith('169.254.')) continue;\n return entry.address;\n }\n }\n return undefined;\n}\n","/**\n * PARA L8 — Session Export Trace Writer\n *\n * Per PARA spec §4.2 L8 (docs/version190/03-para-spec.md):\n * session export 必须是 pre-compaction 的原始 trace。compaction 会把历史消息替换为 summary——\n * 这种 adapter 必须额外持久化原始 trace 到 `.prismer/trace/<sessionId>.jsonl.zst`\n * (append-only + zstd 压缩),compaction 只影响 working memory,不动 trace。\n *\n * Implementation:\n * - Each `append()` JSON-stringifies the envelope, adds '\\n', zstd-compresses it,\n * then sync-appends the compressed bytes to the trace file.\n * - zstd supports concatenated frames — multiple independent compressed blobs\n * catenated together decompress back to the concatenation of their inputs.\n * This is what makes append-only valid without holding a long-lived stream.\n * - File mode 0o600 (trace may contain sensitive payloads).\n * - Node 22+ gives us native `zlib.zstdCompressSync`. Older Node: append is a no-op\n * and a single stderr warning is emitted at construction time. We do NOT throw\n * or crash the daemon — daemon must still start on Node 20.\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport * as zlib from 'node:zlib';\nimport type { EventBusEnvelope } from './event-bus.js';\n\n// ──────────────────────────────────────────────────────────\n// Runtime capability detection (Node 22+ required for zstd)\n// ──────────────────────────────────────────────────────────\n\ntype ZstdCompressSync = (buf: Buffer | Uint8Array) => Buffer;\n\nfunction detectZstdCompressSync(): ZstdCompressSync | undefined {\n const anyZlib = zlib as unknown as { zstdCompressSync?: ZstdCompressSync };\n if (typeof anyZlib.zstdCompressSync === 'function') {\n return anyZlib.zstdCompressSync.bind(zlib);\n }\n return undefined;\n}\n\n// Session ID path-safety: allow [a-zA-Z0-9_.-]+ but require an alnum/underscore\n// at the start (blocks '..', '.hidden', '-flag', '.', '-', etc. from becoming\n// path traversal or hidden files). Max 128 chars as a sanity bound.\nexport const SESSION_ID_PATTERN = /^[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,127}$/;\n\n/**\n * Validate a session id against the TraceWriter's path-safety rules.\n *\n * Rules: must match `SESSION_ID_PATTERN` (first char alnum/underscore, then\n * alnum/underscore/dot/dash, 1–128 chars) AND must not contain `..`.\n *\n * Exported so CLI surfaces (e.g. `prismer session export <id>`) can reject\n * hostile input with the exact same policy the core writer uses — no\n * asymmetry between core and CLI.\n *\n * @internal — not part of the stable public API; do not re-export from\n * `src/index.ts`. Callers inside this package may import directly.\n */\nexport function isValidSessionId(sessionId: string): boolean {\n if (typeof sessionId !== 'string') return false;\n if (!SESSION_ID_PATTERN.test(sessionId)) return false;\n // Explicitly reject '..' anywhere in the id even though the anchor above\n // already blocks it at position 0.\n if (sessionId.includes('..')) return false;\n return true;\n}\n\n// ──────────────────────────────────────────────────────────\n// Types\n// ──────────────────────────────────────────────────────────\n\nexport interface TraceWriterOptions {\n sessionId: string;\n /**\n * Override home directory; trace file will live at\n * `<homeDir>/.prismer/trace/<sessionId>.jsonl.zst`. Defaults to `os.homedir()`.\n */\n homeDir?: string;\n /**\n * Explicit trace directory. Overrides homeDir if provided. Useful when the\n * daemon runs with a non-default `dataDir`.\n */\n traceDir?: string;\n}\n\n// ──────────────────────────────────────────────────────────\n// TraceWriter\n// ──────────────────────────────────────────────────────────\n\nexport class TraceWriter {\n private readonly _sessionId: string;\n private readonly _filePath: string;\n private readonly _compress: ZstdCompressSync | undefined;\n private _bytesWritten = 0;\n private _warnedAppendError = false;\n private _closed = false;\n\n constructor(opts: TraceWriterOptions) {\n if (!isValidSessionId(opts.sessionId)) {\n throw new Error(\n `[TraceWriter] Invalid sessionId \"${opts.sessionId}\": must match ${SESSION_ID_PATTERN} and cannot contain '..'`,\n );\n }\n\n this._sessionId = opts.sessionId;\n\n const traceDir = opts.traceDir ?? path.join(opts.homeDir ?? os.homedir(), '.prismer', 'trace');\n this._filePath = path.join(traceDir, `${opts.sessionId}.jsonl.zst`);\n\n this._compress = detectZstdCompressSync();\n\n if (!this._compress) {\n // Emit one-shot warning. Daemon must not crash on Node 20.\n try {\n process.stderr.write(\n '[TraceWriter] Session trace disabled: requires Node 22+ (zstdCompressSync unavailable)\\n',\n );\n } catch {\n // ignore — stderr unreachable\n }\n return;\n }\n\n // Ensure parent directory exists. Permissions kept to user default for dir\n // (so users can `ls` / copy); files themselves are 0o600.\n const parentDir = path.dirname(this._filePath);\n try {\n fs.mkdirSync(parentDir, { recursive: true });\n } catch (err) {\n // mkdir failure is non-fatal; first append() will surface the problem once.\n try {\n process.stderr.write(\n `[TraceWriter] Failed to create trace dir ${parentDir}: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n } catch { /* ignore */ }\n }\n }\n\n /** Absolute path of the trace file: `<home>/.prismer/trace/<sessionId>.jsonl.zst`. */\n get filePath(): string {\n return this._filePath;\n }\n\n /** Session ID this writer is bound to. */\n get sessionId(): string {\n return this._sessionId;\n }\n\n /** Total compressed bytes appended since construction. */\n get bytesWritten(): number {\n return this._bytesWritten;\n }\n\n /** True if zstd is unavailable (Node < 22); append() is a no-op. */\n get disabled(): boolean {\n return this._compress === undefined;\n }\n\n /**\n * Synchronously append one event envelope to the trace as a new zstd frame.\n * Safe to call after close() — becomes a no-op. Errors are logged once and swallowed.\n */\n append(event: EventBusEnvelope): void {\n if (this._closed) return;\n if (!this._compress) return;\n\n let compressed: Buffer;\n try {\n const line = JSON.stringify(event) + '\\n';\n compressed = this._compress(Buffer.from(line, 'utf8'));\n } catch (err) {\n if (!this._warnedAppendError) {\n this._warnedAppendError = true;\n try {\n process.stderr.write(\n `[TraceWriter] Failed to serialize/compress event for session ${this._sessionId}: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n } catch { /* ignore */ }\n }\n return;\n }\n\n try {\n fs.appendFileSync(this._filePath, compressed, { mode: 0o600 });\n this._bytesWritten += compressed.byteLength;\n } catch (err) {\n if (!this._warnedAppendError) {\n this._warnedAppendError = true;\n try {\n process.stderr.write(\n `[TraceWriter] Failed to append trace for session ${this._sessionId}: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n } catch { /* ignore */ }\n }\n }\n }\n\n /**\n * Close the writer. Currently a no-op because we use sync append with one\n * self-contained zstd frame per event. The API exists so callers can switch to\n * a streaming implementation later without changing integration code.\n */\n close(): void {\n this._closed = true;\n }\n}\n\n// ──────────────────────────────────────────────────────────\n// TraceWriterManager — one writer per active session\n// ──────────────────────────────────────────────────────────\n\nexport interface TraceWriterManagerOptions {\n /** Override home directory (tests). Defaults to os.homedir(). */\n homeDir?: string;\n /** Explicit trace directory — takes precedence over homeDir when set. */\n traceDir?: string;\n}\n\n/**\n * Routes events from the EventBus (`bus.subscribe('*', ...)`) to the per-session\n * TraceWriter.\n *\n * agent.session.started → open writer for payload.sessionId\n * agent.session.ended → close + remove writer\n * any other event → pick the writer by payload.sessionId if present;\n * events without sessionId are skipped (not guessed)\n */\nexport class TraceWriterManager {\n private readonly _writers = new Map<string, TraceWriter>();\n private readonly _homeDir: string | undefined;\n private readonly _traceDir: string | undefined;\n // Dedup per-sessionId — a misbehaving adapter spamming the same bad\n // sessionId must not flood stderr. Each distinct sessionId warns at most once.\n private readonly _warnedOpenFailures = new Set<string>();\n\n constructor(opts?: TraceWriterManagerOptions) {\n this._homeDir = opts?.homeDir;\n this._traceDir = opts?.traceDir;\n }\n\n /** Event-bus subscription handler. Pass via `bus.subscribe('*', mgr.handle)`. */\n readonly handle = (ev: EventBusEnvelope): void => {\n const sessionId = extractSessionId(ev);\n\n if (ev.topic === 'agent.session.started') {\n if (sessionId) {\n this._openWriter(sessionId);\n const writer = this._writers.get(sessionId);\n if (writer) writer.append(ev);\n }\n return;\n }\n\n if (ev.topic === 'agent.session.ended') {\n if (sessionId) {\n const writer = this._writers.get(sessionId);\n if (writer) writer.append(ev);\n this._closeWriter(sessionId);\n }\n return;\n }\n\n if (!sessionId) {\n // No session association — skip (do not guess).\n return;\n }\n\n const writer = this._writers.get(sessionId);\n if (writer) {\n writer.append(ev);\n }\n };\n\n /** Close all writers — call on daemon shutdown. */\n shutdown(): void {\n for (const writer of this._writers.values()) {\n writer.close();\n }\n this._writers.clear();\n }\n\n /** Test / introspection helper. */\n activeSessions(): string[] {\n return [...this._writers.keys()];\n }\n\n private _openWriter(sessionId: string): void {\n if (this._writers.has(sessionId)) return;\n try {\n const writer = new TraceWriter({\n sessionId,\n ...(this._homeDir !== undefined ? { homeDir: this._homeDir } : {}),\n ...(this._traceDir !== undefined ? { traceDir: this._traceDir } : {}),\n });\n this._writers.set(sessionId, writer);\n } catch (err) {\n // Invalid session id or similar — skip but log once *per sessionId*.\n // A misbehaving adapter that repeatedly sends the same bad id must not\n // flood stderr; only the first occurrence warns.\n if (!this._warnedOpenFailures.has(sessionId)) {\n this._warnedOpenFailures.add(sessionId);\n try {\n process.stderr.write(\n `[TraceWriterManager] Failed to open writer for session ${sessionId}: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n } catch { /* ignore */ }\n }\n }\n }\n\n private _closeWriter(sessionId: string): void {\n const writer = this._writers.get(sessionId);\n if (writer) {\n writer.close();\n this._writers.delete(sessionId);\n }\n }\n}\n\n// ──────────────────────────────────────────────────────────\n// Helpers\n// ──────────────────────────────────────────────────────────\n\nfunction extractSessionId(ev: EventBusEnvelope): string | undefined {\n const payload = ev.payload;\n if (!payload || typeof payload !== 'object') return undefined;\n const p = payload as Record<string, unknown>;\n const candidate = p['sessionId'] ?? p['session'];\n if (typeof candidate === 'string' && candidate.length > 0) {\n return candidate;\n }\n return undefined;\n}\n","/**\n * Prismer Runtime — Multi-Path Transport Manager (v1.9.0)\n *\n * Orchestrates multiple transport paths and seamless switching.\n *\n * Supports:\n * - LAN Direct (encrypted, low latency)\n * - WSS Relay (cloud, high reliability)\n * - Auto-fallback on connection loss\n * - Seamless switching (< 100ms)\n *\n * Architecture:\n * 1. Probe all paths on startup\n * 2. Select best path (latency < 100ms)\n * 3. Establish connection\n * 4. Monitor health (heartbeats)\n * 5. Auto-switch on failure (with exponential backoff)\n */\n\nimport { EventEmitter } from 'node:events';\nimport { ConnectionProber, ConnectionSelection, type ConnectionType } from './connection-prober.js';\nimport { RelayClient } from './relay-client.js';\nimport type { E2EEContext } from './e2ee-crypto.js';\nimport { createE2EEContext, type KeyPair } from './e2ee-crypto.js';\nimport { deriveWsFromHttp, deriveHostFromHttp } from './cloud-url.js';\n\n// ============================================================\n// Types\n// ============================================================\n\nexport interface TransportManagerOptions {\n apiKey: string;\n daemonId: string;\n userId: string;\n /**\n * Cloud HTTP base URL (e.g. `https://cloud.prismer.dev`). Relay host + WSS URL\n * are derived from this — there is no separate relay subdomain.\n */\n cloudApiBase: string;\n localKeyPair: KeyPair;\n remotePublicKey?: Buffer; // For LAN E2EE\n lanPort?: number;\n lanHost?: string;\n dataDir?: string;\n probeIntervalMs?: number; // How often to re-probe (default: 5min)\n healthCheckIntervalMs?: number; // How often to check health (default: 30s)\n /**\n * Latency gate for the path-switching heuristic only: when a health check\n * on the currently-active path measures above this, we kick off a re-probe\n * to see if something faster is now available. Default 200ms.\n *\n * NOTE: this is **not** the gate for deciding whether a path is usable at\n * all — that's `pathUsableLatencyMs`. A 200ms \"switch\" threshold is fine\n * for LAN/same-region, but would falsely reject cross-continent WS (which\n * routinely handshakes in 500–1500ms).\n */\n switchLatencyThresholdMs?: number;\n /**\n * Max latency for a path to be considered usable at all. Default 2000ms.\n * Distinct from `switchLatencyThresholdMs` which governs path SWITCHING\n * heuristics. Cross-continent WS handshake can run 500–1500ms; a tight\n * \"switch\" threshold shouldn't reject otherwise-usable paths.\n *\n * Can also be overridden at runtime via the\n * `PRISMER_PATH_USABLE_LATENCY_MS` env var (useful for ops debugging\n * without a rebuild); an explicit option value always wins.\n */\n pathUsableLatencyMs?: number;\n /**\n * Minimum qualityScore (0-100) for a probed path to be considered usable\n * by `selectBest`. Default 20. Lowered from ConnectionProber's 50 default\n * because `calculateQualityScore` hardcodes latency baseline at 500ms —\n * cross-continent WS handshake (800-1500ms) scores <50 even with perfect\n * jitter/loss, tripping the selector. Env override:\n * `PRISMER_MIN_QUALITY_SCORE`.\n */\n minQualityScore?: number;\n}\n\nexport interface TransportStatus {\n currentPath: ConnectionType | null;\n currentEndpoint: string | null;\n connected: boolean;\n latencyMs: number;\n lastHealthCheck: number;\n /** True once probeAndSelect has returned at least once (success or failure). */\n probesCompleted: boolean;\n /** Last probe/switch error message — used to surface \"unreachable\" detail. */\n lastError: string | null;\n paths: {\n [key in ConnectionType]: {\n available: boolean;\n latencyMs: number;\n lastProbed: number;\n };\n };\n}\n\n// ============================================================\n// Constants\n// ============================================================\n\nconst DEFAULT_PROBE_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes\nconst DEFAULT_HEALTH_CHECK_INTERVAL_MS = 30 * 1000; // 30 seconds\nconst DEFAULT_SWITCH_LATENCY_THRESHOLD_MS = 200;\nconst DEFAULT_PATH_USABLE_LATENCY_MS = 2000;\nconst DEFAULT_MIN_QUALITY_SCORE = 20;\nconst HEALTH_CHECK_TIMEOUT_MS = 3000; // 3 seconds\n\n// ============================================================\n// TransportManager\n// ============================================================\n\nexport class TransportManager extends EventEmitter {\n private apiKey: string;\n private cloudApiBase: string;\n private daemonId: string;\n private userId: string;\n private localKeyPair: KeyPair;\n private remotePublicKey?: Buffer;\n private dataDir: string;\n private probeIntervalMs: number;\n private healthCheckIntervalMs: number;\n private switchLatencyThresholdMs: number;\n private pathUsableLatencyMs: number;\n private minQualityScore: number;\n\n private connectionProber: ConnectionProber;\n private relayClient?: RelayClient;\n private e2eeContext?: E2EEContext;\n\n private currentSelection: ConnectionSelection | null = null;\n private isSwitching = false;\n private shutdownRequested = false;\n\n private probeTimer?: NodeJS.Timeout;\n private healthCheckTimer?: NodeJS.Timeout;\n\n private status: TransportStatus = {\n currentPath: null,\n currentEndpoint: null,\n connected: false,\n latencyMs: 0,\n lastHealthCheck: 0,\n probesCompleted: false,\n lastError: null,\n paths: {\n lan: { available: false, latencyMs: Infinity, lastProbed: 0 },\n relay: { available: false, latencyMs: Infinity, lastProbed: 0 },\n http: { available: false, latencyMs: Infinity, lastProbed: 0 },\n },\n };\n\n constructor(opts: TransportManagerOptions) {\n super();\n\n if (!opts.cloudApiBase) {\n throw new Error('TransportManager: cloudApiBase is required');\n }\n this.apiKey = opts.apiKey;\n this.daemonId = opts.daemonId;\n this.userId = opts.userId;\n this.cloudApiBase = opts.cloudApiBase;\n this.localKeyPair = opts.localKeyPair;\n this.remotePublicKey = opts.remotePublicKey;\n this.dataDir = opts.dataDir ?? '.prismer';\n this.probeIntervalMs = opts.probeIntervalMs ?? DEFAULT_PROBE_INTERVAL_MS;\n this.healthCheckIntervalMs = opts.healthCheckIntervalMs ?? DEFAULT_HEALTH_CHECK_INTERVAL_MS;\n this.switchLatencyThresholdMs = opts.switchLatencyThresholdMs ?? DEFAULT_SWITCH_LATENCY_THRESHOLD_MS;\n // Resolve pathUsableLatencyMs — explicit option wins, then env var\n // (belt + suspenders for ops debug without rebuild; NaN ignored), then default.\n const envUsable = Number(process.env.PRISMER_PATH_USABLE_LATENCY_MS);\n this.pathUsableLatencyMs =\n opts.pathUsableLatencyMs ??\n (Number.isFinite(envUsable) && envUsable > 0 ? envUsable : undefined) ??\n DEFAULT_PATH_USABLE_LATENCY_MS;\n // Resolve minQualityScore — explicit option wins, then env var (NaN /\n // out-of-range [0,100] ignored), then default. See G-17 second-pass\n // notes in TransportManagerOptions.minQualityScore docstring.\n const envMinQ = Number(process.env.PRISMER_MIN_QUALITY_SCORE);\n this.minQualityScore =\n opts.minQualityScore ??\n (Number.isFinite(envMinQ) && envMinQ >= 0 && envMinQ <= 100 ? envMinQ : undefined) ??\n DEFAULT_MIN_QUALITY_SCORE;\n\n const relayHost = deriveHostFromHttp(this.cloudApiBase);\n if (!relayHost) {\n throw new Error(`TransportManager: invalid cloudApiBase (cannot derive relay host): ${this.cloudApiBase}`);\n }\n // Derive probe scheme from cloudApiBase so HTTPS → wss:// and HTTP → ws://.\n // The prober itself would fall back on the port heuristic, but we know the\n // truth here and passing it avoids the 80/3000/443-only assumption.\n const relayScheme: 'ws' | 'wss' = /^https:/i.test(this.cloudApiBase) ? 'wss' : 'ws';\n this.connectionProber = new ConnectionProber({\n dataDir: this.dataDir,\n lanPort: opts.lanPort,\n lanHost: opts.lanHost,\n relayHost,\n relayScheme,\n });\n\n // NOTE: do NOT hydrate `currentSelection` from the on-disk cache here.\n // The persisted selection file is useful as a hint for future probe\n // ordering, but treating it as live state at boot causes the exact bug\n // observed in v1.9.24: constructor sets currentSelection → first probe\n // returns the same path → `needsSwitch` evaluates false → switchToPath\n // (the only code that constructs a RelayClient) is never called →\n // `this.relayClient` stays undefined → healthCheck throws \"Relay client\n // not initialized\" forever. The first probe cycle in `start()` will\n // populate currentSelection naturally; loading from cache adds nothing\n // but risk.\n this.currentSelection = null;\n\n // Set up E2EE context if remote public key is available\n if (this.remotePublicKey) {\n this.e2eeContext = createE2EEContext(\n this.localKeyPair,\n this.remotePublicKey\n );\n }\n }\n\n /**\n * Start transport manager\n */\n async start(): Promise<void> {\n console.log('[TransportManager] Starting transport manager');\n\n // Probe all paths on startup\n await this.probeAndSelect();\n\n // Start periodic health checks\n this.startHealthChecks();\n\n // Start periodic re-probing\n this.startPeriodicProbing();\n }\n\n /**\n * Stop transport manager\n */\n async stop(): Promise<void> {\n console.log('[TransportManager] Stopping transport manager');\n this.shutdownRequested = true;\n\n // Clear timers\n if (this.probeTimer) {\n clearTimeout(this.probeTimer);\n this.probeTimer = undefined;\n }\n\n if (this.healthCheckTimer) {\n clearTimeout(this.healthCheckTimer);\n this.healthCheckTimer = undefined;\n }\n\n // Disconnect relay client if active\n if (this.relayClient) {\n await this.relayClient.disconnect();\n this.relayClient = undefined;\n }\n\n this.status.connected = false;\n this.emit('stopped');\n }\n\n /**\n * Get current transport status\n */\n getStatus(): TransportStatus {\n return { ...this.status };\n }\n\n /**\n * Send data via current transport path\n */\n async sendData(data: Buffer): Promise<boolean> {\n if (!this.status.connected) {\n console.warn('[TransportManager] Cannot send data: not connected');\n return false;\n }\n\n switch (this.status.currentPath) {\n case 'lan':\n return this.sendLANData(data);\n\n case 'relay':\n return this.sendRelayData(data);\n\n case 'http':\n return this.sendHTTPData(data);\n\n default:\n console.warn('[TransportManager] Unknown current path:', this.status.currentPath);\n return false;\n }\n }\n\n /**\n * Force re-probe and re-select transport\n */\n async forceReprobe(): Promise<void> {\n console.log('[TransportManager] Force re-probe requested');\n this.connectionProber.clearSelection();\n await this.probeAndSelect();\n }\n\n /**\n * Update remote public key (for new pairing)\n */\n updateRemotePublicKey(remotePublicKey: Buffer): void {\n this.remotePublicKey = remotePublicKey;\n this.e2eeContext = createE2EEContext(\n this.localKeyPair,\n remotePublicKey\n );\n console.log('[TransportManager] Updated remote public key');\n }\n\n // ============================================================\n // Private methods\n // ============================================================\n\n /**\n * Probe all paths and select best one\n */\n private async probeAndSelect(): Promise<void> {\n try {\n console.log('[TransportManager] Probing all connection paths');\n\n const results = await this.connectionProber.probeAll();\n\n // Update path status\n for (const result of results) {\n const path = result.candidate.type;\n this.status.paths[path] = {\n available: result.success,\n latencyMs: result.success ? result.latencyMs : Infinity,\n lastProbed: result.timestamp,\n };\n\n console.log(\n `[TransportManager] ${path}: ${result.success ? `OK (${result.latencyMs.toFixed(2)}ms)` : 'FAILED'}`\n );\n }\n\n // Select best path. Use the \"usable\" threshold (default 2000ms), NOT\n // the \"switch\" threshold (default 200ms) — a tight 200ms gate rejects\n // otherwise-fine cross-continent WS paths. See GAPS G-17.\n //\n // Also lower minQualityScore below ConnectionProber's 50 default\n // (G-17 second-pass): `calculateQualityScore` hardcodes a 500ms\n // latency baseline, so any path >500ms — including a perfectly-fine\n // ~860ms cross-continent relay — gets `latencyScore=0` and tops out\n // at 50 (jitter .3 + loss .2). We keep the prober's scoring intact\n // and relax the gate to 20 here; the deeper fix belongs in the\n // prober's formula and is left for a future round.\n const selection = this.connectionProber.selectBest(results, {\n maxLatencyMs: this.pathUsableLatencyMs,\n minQualityScore: this.minQualityScore,\n });\n\n // Mark that the first probe pass finished — needed by /transport/status to\n // distinguish \"probing\" (no results yet) from \"unreachable\" (all failed).\n this.status.probesCompleted = true;\n\n if (!selection) {\n console.warn('[TransportManager] No suitable path found - will retry later');\n const failed = results.filter((r) => !r.success);\n if (failed.length > 0) {\n const summary = failed\n .map((r) => `${r.candidate.type}:${r.error ?? 'unreachable'}`)\n .join('; ');\n this.status.lastError = `No reachable path (${summary})`;\n } else {\n this.status.lastError = 'No path met the latency threshold';\n }\n return;\n }\n\n // Check if we need to switch. In addition to type/endpoint change,\n // the transport for the selected type MUST actually be live — if the\n // persisted or in-memory selection says \"relay\" but relayClient is\n // missing / disconnected, we still need to reconnect. Without this\n // guard, a cached selection that matches the fresh probe bypasses\n // switchToPath entirely and the RelayClient is never constructed.\n const currentPathLive = this.currentSelection\n ? this.isCurrentPathLive(this.currentSelection.type)\n : false;\n const needsSwitch =\n !this.currentSelection ||\n this.currentSelection.type !== selection.type ||\n this.currentSelection.endpoint !== selection.endpoint ||\n !currentPathLive;\n\n if (needsSwitch) {\n await this.switchToPath(selection);\n } else {\n console.log('[TransportManager] Current path still optimal');\n }\n\n this.currentSelection = selection;\n this.connectionProber.persistSelection(selection);\n this.status.lastError = null;\n } catch (err) {\n console.error('[TransportManager] Probe failed:', err);\n this.status.probesCompleted = true;\n this.status.lastError = err instanceof Error ? err.message : String(err);\n }\n }\n\n /**\n * Is the transport for the given path type actually up and ready to send?\n * Used by `probeAndSelect` so that a stale `currentSelection` (cached or\n * otherwise) can't satisfy the \"path still optimal\" branch when the\n * underlying client never connected (or has since dropped).\n */\n private isCurrentPathLive(type: ConnectionType): boolean {\n switch (type) {\n case 'relay': {\n if (!this.relayClient) return false;\n const status = this.relayClient.getStatus();\n return status.controlConnected === true && status.dataConnected === true;\n }\n case 'lan':\n // LAN has no persistent client in this codebase; treat as live only\n // when the manager itself has been marked connected by connectLAN().\n return this.status.connected === true;\n case 'http':\n // HTTP is stateless request/response — always ready if selected.\n return true;\n default:\n return false;\n }\n }\n\n /**\n * Switch to a different transport path\n */\n private async switchToPath(selection: ConnectionSelection): Promise<void> {\n if (this.isSwitching) {\n console.log('[TransportManager] Already switching, ignoring request');\n return;\n }\n\n const startTime = Date.now();\n this.isSwitching = true;\n console.log(\n `[TransportManager] Switching to ${selection.type} at ${selection.endpoint}`\n );\n\n try {\n // Disconnect current path\n await this.disconnectCurrent();\n\n // Connect new path\n switch (selection.type) {\n case 'lan':\n await this.connectLAN();\n break;\n\n case 'relay':\n await this.connectRelay();\n break;\n\n case 'http':\n await this.connectHTTP();\n break;\n }\n\n // Update status\n const switchTime = Date.now() - startTime;\n console.log(`[TransportManager] Switched to ${selection.type} in ${switchTime}ms`);\n\n if (switchTime > 100) {\n console.warn('[TransportManager] Switch time exceeded 100ms:', switchTime);\n }\n\n this.status.currentPath = selection.type;\n this.status.currentEndpoint = selection.endpoint;\n this.status.latencyMs = selection.latencyMs;\n this.status.connected = true;\n this.status.lastHealthCheck = Date.now();\n\n this.emit('switched', { type: selection.type, endpoint: selection.endpoint, latencyMs: selection.latencyMs });\n } catch (err) {\n console.error('[TransportManager] Failed to switch path:', err);\n this.status.connected = false;\n this.status.lastError = err instanceof Error ? err.message : String(err);\n this.emit('error', err);\n\n // Try to reconnect to previous path if available\n if (this.currentSelection) {\n await this.connectPath(this.currentSelection.type);\n }\n } finally {\n this.isSwitching = false;\n }\n }\n\n /**\n * Disconnect current transport path\n */\n private async disconnectCurrent(): Promise<void> {\n if (this.relayClient) {\n await this.relayClient.disconnect();\n this.relayClient = undefined;\n }\n\n // LAN and HTTP don't have persistent connections to disconnect\n }\n\n /**\n * Connect to LAN path\n */\n private async connectLAN(): Promise<void> {\n if (!this.e2eeContext) {\n throw new Error('Cannot connect LAN: E2EE context not available');\n }\n\n console.log('[TransportManager] Connecting LAN path');\n // LAN is established via the daemon HTTP server on port 3210\n // No explicit connection needed - just mark as ready\n this.status.connected = true;\n }\n\n /** Pending RPC handler registrations to apply once the relay client connects.\n * Daemon code can call registerRpcHandler() before Relay is up; we queue\n * them and wire them into the relay client after connectRelay(). */\n private pendingRpcHandlers = new Map<string, (params: unknown) => Promise<unknown>>();\n\n /**\n * Register an RPC handler for cloud-initiated requests (e.g. FS relay).\n * Idempotent across relay reconnects — the same handler is re-attached on\n * every reconnect without the caller having to re-register.\n */\n registerRpcHandler(method: string, handler: (params: unknown) => Promise<unknown>): void {\n this.pendingRpcHandlers.set(method, handler);\n if (this.relayClient) {\n this.relayClient.registerRpcHandler(method, handler);\n }\n }\n\n /**\n * Send a JSON control message to cloud via the relay control channel.\n * v1.9.x — best-effort passthrough used by daemon code (e.g. remote\n * command ack). Returns false if relay client is not connected.\n */\n sendControl(message: unknown): boolean {\n if (!this.relayClient) return false;\n return this.relayClient.sendControl(message);\n }\n\n /**\n * Connect to Relay path\n */\n private async connectRelay(): Promise<void> {\n console.log('[TransportManager] Connecting Relay path');\n\n const relayUrl = deriveWsFromHttp(this.cloudApiBase);\n if (!relayUrl) {\n throw new Error(`TransportManager: invalid cloudApiBase (cannot derive relay URL): ${this.cloudApiBase}`);\n }\n this.relayClient = new RelayClient({\n apiKey: this.apiKey,\n daemonId: this.daemonId,\n userId: this.userId,\n relayUrl,\n autoReconnect: true,\n });\n\n // Set up event handlers\n this.relayClient.on('connected', () => {\n console.log('[TransportManager] Relay connected');\n this.status.connected = true;\n this.emit('connected', { type: 'relay' });\n });\n\n this.relayClient.on('disconnected', () => {\n console.log('[TransportManager] Relay disconnected');\n this.status.connected = false;\n this.emit('disconnected', { type: 'relay' });\n\n // Trigger re-probe if not shutting down\n if (!this.shutdownRequested) {\n void this.probeAndSelect();\n }\n });\n\n this.relayClient.on('error', (err) => {\n console.error('[TransportManager] Relay error:', err);\n this.emit('error', err);\n });\n\n this.relayClient.on('command', (command) => {\n this.emit('command', command);\n });\n\n this.relayClient.on('data', (data) => {\n this.emit('data', data);\n });\n\n // Re-attach any pending RPC handlers registered before Relay was up.\n for (const [method, handler] of this.pendingRpcHandlers) {\n this.relayClient.registerRpcHandler(method, handler);\n }\n\n await this.relayClient.connect();\n }\n\n /**\n * Connect to HTTP path (fallback)\n */\n private async connectHTTP(): Promise<void> {\n console.log('[TransportManager] Connecting HTTP path');\n // HTTP is request/response, no persistent connection\n this.status.connected = true;\n }\n\n /**\n * Connect to a specific path type\n */\n private async connectPath(type: ConnectionType): Promise<void> {\n switch (type) {\n case 'lan':\n await this.connectLAN();\n break;\n case 'relay':\n await this.connectRelay();\n break;\n case 'http':\n await this.connectHTTP();\n break;\n }\n }\n\n /**\n * Send data via LAN path\n */\n private sendLANData(data: Buffer): boolean {\n if (!this.e2eeContext) {\n console.error('[TransportManager] Cannot send LAN data: no E2EE context');\n return false;\n }\n\n // Encrypt data using E2EE\n const encrypted = this.e2eeContext.sendKey\n ? this.e2eeContext.sendKey\n : data;\n\n // Send via daemon HTTP server\n // This is handled by the daemon's HTTP routes\n this.emit('send', encrypted);\n return true;\n }\n\n /**\n * Send data via Relay path\n */\n private sendRelayData(data: Buffer): boolean {\n if (!this.relayClient) {\n console.error('[TransportManager] Cannot send relay data: no relay client');\n return false;\n }\n\n return this.relayClient.sendCommand(data);\n }\n\n /**\n * Send data via HTTP path\n */\n private sendHTTPData(data: Buffer): boolean {\n // HTTP path is not used for streaming\n console.warn('[TransportManager] HTTP path not supported for streaming');\n return false;\n }\n\n /**\n * Start periodic health checks\n */\n private startHealthChecks(): void {\n this.healthCheckTimer = setInterval(async () => {\n if (this.shutdownRequested) return;\n\n await this.performHealthCheck();\n }, this.healthCheckIntervalMs);\n }\n\n /**\n * Perform health check on current path\n */\n private async performHealthCheck(): Promise<void> {\n const currentPath = this.status.currentPath;\n if (!currentPath) return;\n\n try {\n const startTime = Date.now();\n\n switch (currentPath) {\n case 'lan':\n await this.checkLANHealth();\n break;\n\n case 'relay':\n await this.checkRelayHealth();\n break;\n\n case 'http':\n await this.checkHTTPHealth();\n break;\n }\n\n const latency = Date.now() - startTime;\n this.status.latencyMs = latency;\n this.status.lastHealthCheck = Date.now();\n\n // Check if latency is too high, consider switching\n if (latency > this.switchLatencyThresholdMs) {\n console.warn(\n `[TransportManager] Current path latency (${latency}ms) exceeds threshold`\n );\n void this.probeAndSelect();\n }\n } catch (err) {\n console.error('[TransportManager] Health check failed:', err);\n this.status.connected = false;\n\n // Trigger re-probe\n if (!this.shutdownRequested) {\n void this.probeAndSelect();\n }\n }\n }\n\n /**\n * Check LAN health\n */\n private async checkLANHealth(): Promise<void> {\n // LAN health is always good if daemon is running\n // The daemon HTTP server is our health indicator\n if (!this.status.connected) {\n throw new Error('LAN not connected');\n }\n }\n\n /**\n * Check Relay health\n */\n private async checkRelayHealth(): Promise<void> {\n if (!this.relayClient) {\n throw new Error('Relay client not initialized');\n }\n\n const status = this.relayClient.getStatus();\n if (!status.controlConnected || !status.dataConnected) {\n throw new Error('Relay not connected');\n }\n\n // Check if heartbeat is recent (within 60s)\n if (status.lastHeartbeat && Date.now() - status.lastHeartbeat > 60000) {\n throw new Error('Relay heartbeat stale');\n }\n }\n\n /**\n * Check HTTP health\n */\n private async checkHTTPHealth(): Promise<void> {\n // TODO: Implement HTTP health check\n // For now, assume HTTP is always available\n }\n\n /**\n * Start periodic re-probing\n */\n private startPeriodicProbing(): void {\n this.probeTimer = setInterval(async () => {\n if (this.shutdownRequested || this.isSwitching) return;\n\n console.log('[TransportManager] Periodic re-probe');\n await this.probeAndSelect();\n }, this.probeIntervalMs);\n }\n}\n","/**\n * Prismer Runtime — Connection Probe Service (v1.9.0)\n *\n * Multi-path transport: discovers and selects best connection path\n * between daemon and cloud/moblie client.\n *\n * Supported paths:\n * 1. LAN Direct TCP (:3210) - E2EE encrypted\n * 2. Cloud WSS Relay — same host as the HTTP API (no separate subdomain)\n * 3. Cloud HTTP API (fallback)\n *\n * Probes all candidates in parallel, selects lowest latency path,\n * and persists selection for fast reconnection.\n *\n * Connection quality scoring (v1.9.0):\n * - Latency (RTT): lower is better\n * - Jitter: consistency matters (measured via multiple pings)\n * - Packet loss: measured via failed probes\n * - Stability: based on historical success rate\n */\n\nimport * as net from 'node:net';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport * as crypto from 'node:crypto';\nimport WebSocket from 'ws';\nimport { performance } from 'node:perf_hooks';\n\n// ============================================================\n// Types\n// ============================================================\n\nexport type ConnectionType = 'lan' | 'relay' | 'http';\n\nexport interface ConnectionCandidate {\n type: ConnectionType;\n endpoint: string;\n priority: number; // Lower = higher priority\n}\n\nexport interface ProbeResult {\n candidate: ConnectionCandidate;\n latencyMs: number;\n jitterMs: number; // Measured via multiple pings\n success: boolean;\n error?: string;\n timestamp: number;\n qualityScore: number; // 0-100 (higher is better)\n}\n\nexport interface ConnectionSelection {\n type: ConnectionType;\n endpoint: string;\n latencyMs: number;\n selectedAt: number;\n}\n\nexport interface ConnectionProberOptions {\n dataDir?: string;\n maxLatencyMs?: number; // Max acceptable latency (default: 500ms)\n probeTimeoutMs?: number; // Per-probe timeout (default: 3000ms)\n maxConcurrentProbes?: number; // Max concurrent probes (default: 3)\n lanPort?: number; // LAN bind port (default: 3210)\n lanHost?: string; // Explicit LAN-reachable host/IP. If omitted, first non-internal IPv4 is used.\n /**\n * Relay server host. REQUIRED — derive from the cloud HTTP base URL\n * (e.g. `cloud.prismer.dev` when `cloudApiBase=https://cloud.prismer.dev`)\n * via `deriveHostFromHttp()` in `cloud-url.ts`.\n */\n relayHost: string;\n relayPort?: number; // Relay server port (default: 443)\n /**\n * WebSocket scheme for the relay probe. When omitted, derived from the\n * relay port (443 → `wss`, anything else → `ws`). Callers that know the\n * cloud base URL should pass this explicitly from `cloudApiBase` instead\n * of relying on the port heuristic.\n */\n relayScheme?: 'ws' | 'wss';\n pingCount?: number; // Number of pings per probe for jitter measurement (default: 5)\n}\n\n// ============================================================\n// Constants\n// ============================================================\n\nconst DEFAULT_MAX_LATENCY_MS = 500;\nconst DEFAULT_PROBE_TIMEOUT_MS = 3000;\nconst DEFAULT_MAX_CONCURRENT_PROBES = 3;\nconst DEFAULT_LAN_PORT = 3210;\nconst DEFAULT_RELAY_PORT = 443;\nconst DEFAULT_PING_COUNT = 5;\nconst SELECTION_FILE = 'connection-selection.json';\n\n// ============================================================\n// ConnectionProber\n// ============================================================\n\nexport class ConnectionProber {\n private dataDir: string;\n private selectionPath: string;\n private maxLatencyMs: number;\n private probeTimeoutMs: number;\n private maxConcurrentProbes: number;\n private lanPort: number;\n private lanHost?: string;\n private relayHost: string;\n private relayPort: number;\n private relayScheme: 'ws' | 'wss';\n private pingCount: number;\n\n constructor(opts: ConnectionProberOptions) {\n if (!opts.relayHost) {\n throw new Error('ConnectionProber: relayHost is required (derive from cloudApiBase via deriveHostFromHttp)');\n }\n this.dataDir = opts.dataDir ?? path.join(os.homedir(), '.prismer');\n this.selectionPath = path.join(this.dataDir, SELECTION_FILE);\n this.maxLatencyMs = opts.maxLatencyMs ?? DEFAULT_MAX_LATENCY_MS;\n this.probeTimeoutMs = opts.probeTimeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;\n this.maxConcurrentProbes = opts.maxConcurrentProbes ?? DEFAULT_MAX_CONCURRENT_PROBES;\n this.lanPort = opts.lanPort ?? DEFAULT_LAN_PORT;\n this.lanHost = Object.prototype.hasOwnProperty.call(opts, 'lanHost')\n ? normalizeLanHost(opts.lanHost)\n : findLanIPv4();\n // Normalize relay host: when the caller passes `host:port` (e.g. from\n // `deriveHostFromHttp(\"http://localhost:3000\")`), the embedded port wins\n // over the default `relayPort`. Without this, `getCandidates()` emits\n // endpoints like `localhost:3000:443` which fail to parse in `wsPing`\n // and `tcpPing`. Only a bare IPv4/hostname with a single trailing port\n // is split; IPv6 literals (with multiple colons) are left untouched.\n const { host: normalizedRelayHost, port: embeddedRelayPort } =\n splitHostPort(opts.relayHost);\n this.relayHost = normalizedRelayHost;\n this.relayPort = embeddedRelayPort ?? opts.relayPort ?? DEFAULT_RELAY_PORT;\n this.relayScheme = opts.relayScheme ?? (this.relayPort === 443 ? 'wss' : 'ws');\n this.pingCount = opts.pingCount ?? DEFAULT_PING_COUNT;\n\n // Ensure data dir exists\n fs.mkdirSync(this.dataDir, { recursive: true });\n }\n\n /**\n * Get all connection candidates to probe\n */\n getCandidates(): ConnectionCandidate[] {\n const candidates: ConnectionCandidate[] = [];\n if (this.lanHost) {\n candidates.push({\n type: 'lan',\n endpoint: `${this.lanHost}:${this.lanPort}`,\n priority: 1, // Highest priority\n });\n }\n candidates.push(\n {\n type: 'relay',\n endpoint: `${this.relayHost}:${this.relayPort}`,\n priority: 2,\n },\n // HTTP fallback is not probed (always available)\n // {\n // type: 'http',\n // endpoint: 'api.prismer.cloud',\n // priority: 3,\n // },\n );\n return candidates;\n }\n\n /**\n * Probe all connection candidates with concurrency limit\n */\n async probeAll(candidates?: ConnectionCandidate[]): Promise<ProbeResult[]> {\n const targets = candidates ?? this.getCandidates();\n\n // Probe with concurrency limit\n const results: ProbeResult[] = [];\n for (let i = 0; i < targets.length; i += this.maxConcurrentProbes) {\n const batch = targets.slice(i, i + this.maxConcurrentProbes);\n const batchResults = await Promise.all(\n batch.map((candidate) => this.probeCandidate(candidate))\n );\n results.push(...batchResults);\n }\n\n // Sort by quality score (highest first), then latency, then priority\n results.sort((a, b) => {\n if (a.success !== b.success) {\n return b.success ? 1 : -1; // Success first\n }\n if (b.qualityScore !== a.qualityScore) {\n return b.qualityScore - a.qualityScore; // Higher quality first\n }\n if (a.latencyMs !== b.latencyMs) {\n return a.latencyMs - b.latencyMs; // Lower latency first\n }\n return a.candidate.priority - b.candidate.priority; // Higher priority first\n });\n\n return results;\n }\n\n /**\n * Select the best connection from probe results based on quality score\n */\n selectBest(results: ProbeResult[], opts?: { maxLatencyMs?: number; minQualityScore?: number }): ConnectionSelection | null {\n const threshold = opts?.maxLatencyMs ?? this.maxLatencyMs;\n const minQuality = opts?.minQualityScore ?? 50; // Minimum quality score (0-100)\n\n for (const result of results) {\n if (result.success &&\n result.latencyMs <= threshold &&\n result.qualityScore >= minQuality) {\n return {\n type: result.candidate.type,\n endpoint: result.candidate.endpoint,\n latencyMs: result.latencyMs,\n selectedAt: result.timestamp,\n };\n }\n }\n\n return null;\n }\n\n /**\n * Persist connection selection to disk\n */\n persistSelection(selection: ConnectionSelection): void {\n try {\n const tmpPath = this.selectionPath + '.tmp';\n fs.writeFileSync(tmpPath, JSON.stringify(selection, null, 2), {\n encoding: 'utf-8',\n mode: 0o600,\n });\n fs.renameSync(tmpPath, this.selectionPath);\n } catch (err) {\n // Best-effort — don't crash if persistence fails\n console.error('[ConnectionProber] Failed to persist selection:', err);\n }\n }\n\n /**\n * Load persisted connection selection\n */\n loadSelection(): ConnectionSelection | null {\n try {\n if (!fs.existsSync(this.selectionPath)) {\n return null;\n }\n\n const data = fs.readFileSync(this.selectionPath, 'utf-8');\n const parsed = JSON.parse(data) as ConnectionSelection;\n\n // Validate required fields\n if (!parsed.type || !parsed.endpoint || typeof parsed.latencyMs !== 'number') {\n return null;\n }\n\n return parsed;\n } catch {\n return null;\n }\n }\n\n /**\n * Clear persisted selection (force re-probe on next start)\n */\n clearSelection(): void {\n try {\n fs.unlinkSync(this.selectionPath);\n } catch {\n // Ignore if file doesn't exist\n }\n }\n\n /**\n * Probe a single connection candidate with quality scoring\n */\n private async probeCandidate(candidate: ConnectionCandidate): Promise<ProbeResult> {\n try {\n if (candidate.type === 'lan') {\n return await this.probeLAN(candidate);\n } else if (candidate.type === 'relay') {\n return await this.probeRelay(candidate);\n } else if (candidate.type === 'http') {\n return await this.probeHTTP(candidate);\n } else {\n throw new Error(`Unknown connection type: ${candidate.type}`);\n }\n } catch (err) {\n return {\n candidate,\n latencyMs: this.probeTimeoutMs,\n jitterMs: 0,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n timestamp: Date.now(),\n qualityScore: 0,\n };\n }\n }\n\n /**\n * Probe LAN connection (TCP socket test with multiple pings for jitter)\n */\n private async probeLAN(candidate: ConnectionCandidate): Promise<ProbeResult> {\n const [host, portStr] = candidate.endpoint.split(':');\n const port = parseInt(portStr, 10);\n\n // Perform multiple pings to measure jitter\n const latencies: number[] = [];\n let successCount = 0;\n\n for (let i = 0; i < this.pingCount; i++) {\n try {\n const latency = await this.tcpPing(host, port);\n latencies.push(latency);\n successCount++;\n\n // Small delay between pings to avoid flooding\n if (i < this.pingCount - 1) {\n await new Promise(resolve => setTimeout(resolve, 50));\n }\n } catch (err) {\n // Continue trying even if some pings fail\n console.warn(`[ConnectionProber] LAN ping ${i + 1}/${this.pingCount} failed:`, err);\n }\n }\n\n if (latencies.length === 0) {\n return {\n candidate,\n latencyMs: this.probeTimeoutMs,\n jitterMs: 0,\n success: false,\n error: 'All pings failed',\n timestamp: Date.now(),\n qualityScore: 0,\n };\n }\n\n // Calculate statistics\n const avgLatency = latencies.reduce((sum, lat) => sum + lat, 0) / latencies.length;\n const minLatency = Math.min(...latencies);\n const maxLatency = Math.max(...latencies);\n const jitter = maxLatency - minLatency;\n const packetLoss = ((this.pingCount - successCount) / this.pingCount) * 100;\n\n // Calculate quality score (0-100)\n const qualityScore = this.calculateQualityScore({\n avgLatency,\n jitter,\n packetLoss,\n });\n\n return {\n candidate,\n latencyMs: avgLatency,\n jitterMs: jitter,\n success: true,\n timestamp: Date.now(),\n qualityScore,\n };\n }\n\n /**\n * Perform a single TCP ping to measure latency\n */\n private async tcpPing(host: string, port: number): Promise<number> {\n return new Promise((resolve, reject) => {\n const startTime = performance.now();\n const socket = new net.Socket();\n let connected = false;\n\n socket.setTimeout(this.probeTimeoutMs, () => {\n if (!connected) {\n socket.destroy();\n reject(new Error('Connection timeout'));\n }\n });\n\n socket.on('connect', () => {\n connected = true;\n const latency = performance.now() - startTime;\n socket.destroy();\n resolve(latency);\n });\n\n socket.on('error', (err) => {\n socket.destroy();\n reject(err);\n });\n\n socket.connect(port, host);\n });\n }\n\n /**\n * Calculate connection quality score based on latency, jitter, and packet loss\n */\n private calculateQualityScore(metrics: {\n avgLatency: number;\n jitter: number;\n packetLoss: number;\n }): number {\n const { avgLatency, jitter, packetLoss } = metrics;\n\n // Normalize metrics to 0-1 range\n // Latency: < 10ms = 1, > 500ms = 0\n const latencyScore = Math.max(0, 1 - (avgLatency / 500));\n\n // Jitter: < 10ms = 1, > 100ms = 0\n const jitterScore = Math.max(0, 1 - (jitter / 100));\n\n // Packet loss: 0% = 1, > 20% = 0\n const lossScore = Math.max(0, 1 - (packetLoss / 20));\n\n // Weighted average (latency is most important)\n const qualityScore = (latencyScore * 0.5) + (jitterScore * 0.3) + (lossScore * 0.2);\n\n return Math.round(qualityScore * 100);\n }\n\n /**\n * Probe Relay connection (WSS handshake test with quality scoring)\n */\n private async probeRelay(candidate: ConnectionCandidate): Promise<ProbeResult> {\n const [host, portStr] = candidate.endpoint.split(':');\n const port = parseInt(portStr, 10);\n\n // Perform multiple WebSocket handshakes to measure quality\n const latencies: number[] = [];\n let successCount = 0;\n\n for (let i = 0; i < this.pingCount; i++) {\n try {\n const latency = await this.wsPing(host, port);\n latencies.push(latency);\n successCount++;\n\n // Small delay between pings\n if (i < this.pingCount - 1) {\n await new Promise(resolve => setTimeout(resolve, 50));\n }\n } catch (err) {\n console.warn(`[ConnectionProber] Relay ping ${i + 1}/${this.pingCount} failed:`, err);\n }\n }\n\n if (latencies.length === 0) {\n return {\n candidate,\n latencyMs: this.probeTimeoutMs,\n jitterMs: 0,\n success: false,\n error: 'All WebSocket handshakes failed',\n timestamp: Date.now(),\n qualityScore: 0,\n };\n }\n\n // Calculate statistics\n const avgLatency = latencies.reduce((sum, lat) => sum + lat, 0) / latencies.length;\n const minLatency = Math.min(...latencies);\n const maxLatency = Math.max(...latencies);\n const jitter = maxLatency - minLatency;\n const packetLoss = ((this.pingCount - successCount) / this.pingCount) * 100;\n\n // Calculate quality score\n const qualityScore = this.calculateQualityScore({\n avgLatency,\n jitter,\n packetLoss,\n });\n\n return {\n candidate,\n latencyMs: avgLatency,\n jitterMs: jitter,\n success: true,\n timestamp: Date.now(),\n qualityScore,\n };\n }\n\n /**\n * Perform a single WebSocket handshake to measure latency\n */\n private async wsPing(host: string, port: number): Promise<number> {\n return new Promise((resolve, reject) => {\n const startTime = performance.now();\n // v1.9.0: canonical probe path is /ws/probe (no-auth handshake) on the\n // same host as the cloud HTTP API. Scheme is derived from the cloud\n // base URL by the caller (TransportManager) — don't hardcode ws:// here.\n const wsUrl = `${this.relayScheme}://${host}:${port}/ws/probe`;\n\n const ws = new WebSocket(wsUrl, {\n handshakeTimeout: this.probeTimeoutMs,\n });\n\n ws.on('open', () => {\n const latency = performance.now() - startTime;\n ws.close();\n resolve(latency);\n });\n\n ws.on('error', (err) => {\n ws.close();\n reject(err);\n });\n\n // Fallback timeout\n setTimeout(() => {\n if (ws.readyState === WebSocket.CONNECTING) {\n ws.close();\n reject(new Error('WebSocket handshake timeout'));\n }\n }, this.probeTimeoutMs);\n });\n }\n\n /**\n * Probe HTTP connection (simple GET request with quality scoring)\n */\n private async probeHTTP(candidate: ConnectionCandidate): Promise<ProbeResult> {\n // Perform multiple HTTP requests to measure quality\n const latencies: number[] = [];\n let successCount = 0;\n\n for (let i = 0; i < this.pingCount; i++) {\n try {\n const latency = await this.httpPing(candidate.endpoint);\n latencies.push(latency);\n successCount++;\n\n // Small delay between pings\n if (i < this.pingCount - 1) {\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n } catch (err) {\n console.warn(`[ConnectionProber] HTTP ping ${i + 1}/${this.pingCount} failed:`, err);\n }\n }\n\n if (latencies.length === 0) {\n return {\n candidate,\n latencyMs: this.probeTimeoutMs,\n jitterMs: 0,\n success: false,\n error: 'All HTTP requests failed',\n timestamp: Date.now(),\n qualityScore: 0,\n };\n }\n\n // Calculate statistics\n const avgLatency = latencies.reduce((sum, lat) => sum + lat, 0) / latencies.length;\n const minLatency = Math.min(...latencies);\n const maxLatency = Math.max(...latencies);\n const jitter = maxLatency - minLatency;\n const packetLoss = ((this.pingCount - successCount) / this.pingCount) * 100;\n\n // Calculate quality score\n const qualityScore = this.calculateQualityScore({\n avgLatency,\n jitter,\n packetLoss,\n });\n\n return {\n candidate,\n latencyMs: avgLatency,\n jitterMs: jitter,\n success: true,\n timestamp: Date.now(),\n qualityScore,\n };\n }\n\n /**\n * Perform a single HTTP GET request to measure latency\n */\n private async httpPing(endpoint: string): Promise<number> {\n const startTime = performance.now();\n const url = `https://${endpoint}/health`;\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n signal: AbortSignal.timeout(this.probeTimeoutMs),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n return performance.now() - startTime;\n } catch (err) {\n throw new Error(`HTTP ping failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n /**\n * Measure exact round-trip latency to an endpoint\n * Sends a ping and measures time to response\n */\n async measureLatency(endpoint: string, type: ConnectionType): Promise<{ latency: number; quality: number }> {\n try {\n const candidate: ConnectionCandidate = { type, endpoint, priority: 99 };\n const result = await this.probeCandidate(candidate);\n\n return {\n latency: result.latencyMs,\n quality: result.qualityScore,\n };\n } catch {\n return { latency: Infinity, quality: 0 };\n }\n }\n\n /**\n * Get current connection status summary\n */\n async getStatus(): Promise<{\n current: ConnectionSelection | null;\n lastProbe: ProbeResult[];\n timestamp: number;\n }> {\n const selection = this.loadSelection();\n const lastProbe = await this.probeAll();\n\n return {\n current: selection,\n lastProbe,\n timestamp: Date.now(),\n };\n }\n}\n\nfunction findLanIPv4(): string | undefined {\n const nets = os.networkInterfaces();\n for (const entries of Object.values(nets)) {\n for (const entry of entries ?? []) {\n if (entry.family === 'IPv4' && !entry.internal && normalizeLanHost(entry.address)) {\n return entry.address;\n }\n }\n }\n return undefined;\n}\n\n/**\n * Split a `host` or `host:port` string into its components.\n *\n * - Plain hostnames / IPv4 (`\"relay.test\"`, `\"192.168.1.10\"`) → `{ host, port: undefined }`\n * - `\"relay.test:8080\"` / `\"localhost:3000\"` → `{ host: \"relay.test\", port: 8080 }`\n * - IPv6 literals with embedded colons but no bracket syntax (`\"::1\"`, `\"fe80::1\"`)\n * are returned as-is with `port: undefined` — we only split when exactly\n * one colon is present and the suffix parses as a port.\n *\n * This exists so `ConnectionProber` can accept hosts produced by\n * `deriveHostFromHttp()` which preserves the port from the cloud base URL.\n */\nfunction splitHostPort(raw: string): { host: string; port?: number } {\n // IPv6 with exactly one colon can't happen; multi-colon hosts are IPv6.\n const colonCount = (raw.match(/:/g) ?? []).length;\n if (colonCount !== 1) {\n return { host: raw };\n }\n const idx = raw.lastIndexOf(':');\n const hostPart = raw.slice(0, idx);\n const portPart = raw.slice(idx + 1);\n if (!hostPart || !portPart) {\n return { host: raw };\n }\n const port = Number(portPart);\n if (!Number.isFinite(port) || !Number.isInteger(port) || port <= 0 || port > 65535) {\n return { host: raw };\n }\n return { host: hostPart, port };\n}\n\nfunction normalizeLanHost(host: string | undefined): string | undefined {\n if (!host) return undefined;\n if (host === 'localhost' || host === '0.0.0.0' || host === '::' || host === '::1') {\n return undefined;\n }\n if (host.startsWith('127.') || host.startsWith('169.254.')) {\n return undefined;\n }\n return host;\n}\n\n// ============================================================\n// Convenience functions\n// ============================================================\n\n/**\n * Probe all connections and auto-select best path\n */\nexport async function probeAndSelect(\n opts: ConnectionProberOptions\n): Promise<ConnectionSelection | null> {\n const prober = new ConnectionProber(opts);\n const results = await prober.probeAll();\n const selected = prober.selectBest(results);\n\n if (selected) {\n prober.persistSelection(selected);\n }\n\n return selected;\n}\n\n/**\n * Get current connection selection\n */\nexport function getCurrentSelection(\n opts: ConnectionProberOptions\n): ConnectionSelection | null {\n const prober = new ConnectionProber(opts);\n return prober.loadSelection();\n}\n","/**\n * Prismer Runtime — WSS Relay Client (v1.9.0)\n *\n * WebSocket client for cloud relay communication. Connects to the main\n * cloud host (derived from `cloudApiBase`) under the `/ws/daemon/*` path\n * prefix — there is no separate relay subdomain.\n *\n * Responsibilities:\n * - Register daemon binding with API key\n * - Receive remote command pushes (control channel)\n * - Route encrypted envelopes (data channel)\n * - Heartbeat keepalive (30s interval)\n * - Auto-reconnect with exponential backoff\n */\n\nimport WebSocket from 'ws';\nimport { EventEmitter } from 'node:events';\nimport { DaemonOutbox, frameFromParts } from './daemon-outbox.js';\n\n// v1.9.0 — §5.6.4 binary frame opcodes (must match cloud relay-handler.ts)\nexport const OPCODE = {\n JSON_CONTROL: 0x00,\n AGENT_OUTPUT: 0x01,\n TERMINAL_IO: 0x02,\n FILE_CHUNK: 0x03,\n AUDIT_TAP: 0x04,\n BACKFILL_REQUEST: 0x05, // incoming from cloud (cloud relays client's request)\n BACKFILL_CHUNK: 0x06, // outgoing to cloud\n} as const;\n\nconst BACKFILL_TRACKED_OPCODES: ReadonlySet<number> = new Set([\n OPCODE.AGENT_OUTPUT,\n OPCODE.TERMINAL_IO,\n OPCODE.FILE_CHUNK,\n]);\n\n// ============================================================\n// Types\n// ============================================================\n\nexport interface RelayClientOptions {\n apiKey: string;\n daemonId: string;\n userId: string;\n /**\n * Base WSS URL for the relay (e.g. `wss://cloud.prismer.dev`). The client\n * appends `/ws/daemon/control` and `/ws/daemon/data` to this base. Callers\n * typically derive it from `cloudApiBase` via `deriveWsFromHttp()`.\n */\n relayUrl: string;\n heartbeatIntervalMs?: number; // default: 30000 (30s)\n reconnectDelayMs?: number; // default: 1000\n maxReconnectDelayMs?: number; // default: 30000 (30s)\n autoReconnect?: boolean; // default: true\n /** v1.9.0 — bindingId enables daemon-side outbox + timeline backfill (§5.6.5). */\n bindingId?: string;\n /** Override outbox location (for tests); defaults to ~/.prismer/daemon/{bindingId}. */\n outboxDataDir?: string;\n}\n\nexport interface RelayState {\n connected: boolean;\n channel: 'control' | 'data' | null;\n lastHeartbeat?: number;\n reconnectAttempts: number;\n lastError?: string;\n}\n\n\nexport interface RemoteCommand {\n id: string;\n type: string;\n payload: Record<string, unknown>;\n createdAt: number;\n}\n\n// ============================================================\n// Constants\n// ============================================================\n\nconst DEFAULT_HEARTBEAT_INTERVAL_MS = 30000; // 30s\nconst DEFAULT_RECONNECT_DELAY_MS = 1000;\nconst MAX_RECONNECT_DELAY_MS = 30000; // 30s\nconst HEARTBEAT_TIMEOUT_MS = 10000; // 10s to receive pong\n\n// ============================================================\n// RelayClient\n// ============================================================\n\nexport class RelayClient extends EventEmitter {\n private apiKey: string;\n private daemonId: string;\n private userId: string;\n private relayUrl: string;\n private heartbeatIntervalMs: number;\n private reconnectDelayMs: number;\n private maxReconnectDelayMs: number;\n private autoReconnect: boolean;\n\n private controlWs: WebSocket | null = null;\n private dataWs: WebSocket | null = null;\n\n private heartbeatInterval?: NodeJS.Timeout;\n private heartbeatTimer?: NodeJS.Timeout;\n private reconnectTimer?: NodeJS.Timeout;\n\n private state: RelayState = {\n connected: false,\n channel: null,\n reconnectAttempts: 0,\n };\n\n private isShuttingDown = false;\n private outbox?: DaemonOutbox;\n\n constructor(opts: RelayClientOptions) {\n super();\n\n this.apiKey = opts.apiKey;\n this.daemonId = opts.daemonId;\n this.userId = opts.userId;\n if (!opts.relayUrl) {\n throw new Error('RelayClient: relayUrl is required (derive from cloudApiBase via deriveWsFromHttp)');\n }\n this.relayUrl = opts.relayUrl;\n this.heartbeatIntervalMs = opts.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;\n this.reconnectDelayMs = opts.reconnectDelayMs ?? DEFAULT_RECONNECT_DELAY_MS;\n this.maxReconnectDelayMs = opts.maxReconnectDelayMs ?? MAX_RECONNECT_DELAY_MS;\n this.autoReconnect = opts.autoReconnect ?? true;\n\n // v1.9.0 — enable disconnect compensation when bindingId provided\n if (opts.bindingId) {\n this.outbox = new DaemonOutbox({\n bindingId: opts.bindingId,\n dataDir: opts.outboxDataDir,\n });\n }\n }\n\n /**\n * Connect to relay server (both control and data channels)\n */\n async connect(): Promise<void> {\n if (this.isShuttingDown) {\n throw new Error('Cannot connect: client is shutting down');\n }\n\n if (this.controlWs?.readyState === 1) {\n console.warn('[RelayClient] Already connected to control channel');\n return;\n }\n\n console.log('[RelayClient] Connecting to relay:', this.relayUrl);\n\n try {\n // Connect control channel\n await this.connectControlChannel();\n\n // Connect data channel\n await this.connectDataChannel();\n\n // Start heartbeat\n this.startHeartbeat();\n\n this.state.connected = true;\n this.state.reconnectAttempts = 0;\n this.emit('connected');\n\n // v1.9.0 — drain queued frames accumulated while offline\n this.replayOutbox();\n } catch (err) {\n console.error('[RelayClient] Connection failed:', err);\n this.state.lastError = err instanceof Error ? err.message : String(err);\n\n if (this.autoReconnect && !this.isShuttingDown) {\n this.scheduleReconnect();\n }\n\n throw err;\n }\n }\n\n /**\n * Disconnect from relay server\n */\n async disconnect(): Promise<void> {\n console.log('[RelayClient] Disconnecting from relay');\n this.isShuttingDown = true;\n this.autoReconnect = false;\n\n // Clear timers\n this.clearHeartbeat();\n this.clearReconnectTimer();\n\n // Close connections\n await this.closeControlChannel();\n await this.closeDataChannel();\n\n this.state.connected = false;\n this.state.channel = null;\n\n // v1.9.0 — flush outbox SQLite cleanly on explicit shutdown\n this.outbox?.close();\n this.outbox = undefined;\n\n this.emit('disconnected');\n }\n\n /**\n * Send command to mobile client via relay (data channel).\n *\n * v1.9.0 — if bindingId was provided, every tracked data-plane frame\n * (AGENT_OUTPUT / TERMINAL_IO / FILE_CHUNK) is recorded in the local\n * timeline before send. If the data channel is down, the frame is queued\n * to the outbox and will be replayed on next successful connect.\n */\n /**\n * Send JSON control message to cloud via the control channel.\n * v1.9.x — used by daemon to ack remote commands (e.g. command.result).\n * Returns false silently if control channel is not connected.\n */\n sendControl(message: unknown): boolean {\n if (!this.controlWs || this.controlWs.readyState !== 1) {\n return false;\n }\n try {\n this.controlWs.send(JSON.stringify(message));\n return true;\n } catch (err) {\n console.error('[RelayClient] Failed to send control message:', err);\n return false;\n }\n }\n\n sendCommand(data: Buffer | string): boolean {\n const frame = typeof data === 'string' ? Buffer.from(data, 'utf-8') : data;\n\n // Record tracked binary frames in timeline BEFORE attempting send\n let seq: number | undefined;\n if (this.outbox && Buffer.isBuffer(frame) && frame.length >= 2) {\n const opcode = frame[0];\n if (BACKFILL_TRACKED_OPCODES.has(opcode)) {\n try {\n seq = this.outbox.appendSent(opcode, frame[1], frame.slice(2));\n } catch (err) {\n console.warn('[RelayClient] Timeline append failed (non-fatal):', err);\n }\n }\n }\n\n if (!this.dataWs || this.dataWs.readyState !== 1) {\n if (this.outbox && seq !== undefined) {\n this.outbox.queue(seq, frame as Buffer);\n console.log(`[RelayClient] Data channel offline — queued frame seq=${seq} to outbox`);\n } else {\n console.warn('[RelayClient] Cannot send command: data channel not connected');\n }\n return false;\n }\n\n try {\n this.dataWs.send(data);\n return true;\n } catch (err) {\n console.error('[RelayClient] Failed to send command:', err);\n if (this.outbox && seq !== undefined) {\n this.outbox.queue(seq, frame as Buffer);\n }\n return false;\n }\n }\n\n /**\n * Get current connection state\n */\n getState(): RelayState {\n return { ...this.state };\n }\n\n /**\n * Get connection status summary\n */\n getStatus(): {\n controlConnected: boolean;\n dataConnected: boolean;\n lastHeartbeat?: number;\n reconnectAttempts: number;\n } {\n return {\n controlConnected: this.controlWs?.readyState === 1,\n dataConnected: this.dataWs?.readyState === 1,\n lastHeartbeat: this.state.lastHeartbeat,\n reconnectAttempts: this.state.reconnectAttempts,\n };\n }\n\n // ============================================================\n // Private methods\n // ============================================================\n\n /**\n * Connect to control channel (/ws/daemon/control)\n */\n private async connectControlChannel(): Promise<void> {\n return new Promise((resolve, reject) => {\n const url = this.relayEndpoint('/ws/daemon/control');\n const ws = new WebSocket(url, {\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'X-Daemon-Id': this.daemonId,\n 'X-User-Id': this.userId,\n },\n });\n\n ws.on('open', () => {\n console.log('[RelayClient] Control channel connected');\n this.controlWs = ws;\n this.state.channel = 'control';\n\n // Send registration message\n this.registerDaemon();\n\n resolve();\n });\n\n ws.on('message', (data: Buffer) => {\n this.handleControlMessage(data);\n });\n\n ws.on('error', (err: Error) => {\n console.error('[RelayClient] Control channel error:', err);\n reject(err);\n });\n\n ws.on('close', (code: number, reason: Buffer) => {\n console.log('[RelayClient] Control channel closed:', code, reason);\n this.controlWs = null;\n\n if (this.state.channel === 'control') {\n this.state.channel = null;\n }\n\n this.handleDisconnect('control');\n\n if (this.autoReconnect && !this.isShuttingDown) {\n this.scheduleReconnect();\n }\n });\n });\n }\n\n /**\n * Connect to data channel (/ws/daemon/data)\n */\n private async connectDataChannel(): Promise<void> {\n return new Promise((resolve, reject) => {\n const url = this.relayEndpoint('/ws/daemon/data');\n const ws = new WebSocket(url, {\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'X-Daemon-Id': this.daemonId,\n 'X-User-Id': this.userId,\n },\n });\n\n ws.on('open', () => {\n console.log('[RelayClient] Data channel connected');\n this.dataWs = ws;\n resolve();\n });\n\n ws.on('message', (data: Buffer) => {\n this.handleDataMessage(data);\n });\n\n ws.on('error', (err: Error) => {\n console.error('[RelayClient] Data channel error:', err);\n reject(err);\n });\n\n ws.on('close', (code: number, reason: Buffer) => {\n console.log('[RelayClient] Data channel closed:', code, reason);\n this.dataWs = null;\n this.handleDisconnect('data');\n\n if (this.autoReconnect && !this.isShuttingDown) {\n this.scheduleReconnect();\n }\n });\n });\n }\n\n private relayEndpoint(path: string): string {\n const url = new URL(path, this.relayUrl.endsWith('/') ? this.relayUrl : `${this.relayUrl}/`);\n url.searchParams.set('token', this.apiKey);\n url.searchParams.set('daemonId', this.daemonId);\n return url.toString();\n }\n\n /**\n * Register daemon with relay server\n */\n private registerDaemon(): void {\n if (!this.controlWs || this.controlWs.readyState !== 1) {\n return;\n }\n\n const registerMessage = {\n type: 'register',\n daemonId: this.daemonId,\n userId: this.userId,\n timestamp: Date.now(),\n };\n\n this.controlWs.send(JSON.stringify(registerMessage));\n }\n\n /**\n * Handle incoming control channel messages\n */\n private handleControlMessage(data: Buffer): void {\n try {\n const message = JSON.parse(data.toString('utf-8'));\n\n switch (message.type) {\n case 'heartbeat':\n // Echo heartbeat back\n this.sendHeartbeatAck();\n break;\n\n case 'command':\n // Remote command from mobile\n this.handleRemoteCommand(message);\n break;\n\n case 'command.new': {\n // v1.9.x cloud → daemon push of a newly-created remote command\n // Cloud payload shape: { type: 'command.new', data: { commandId, commandType, envelope } }\n const d = (message as any).data || {};\n const command: RemoteCommand = {\n id: d.commandId,\n type: d.commandType,\n payload: d.envelope || {},\n createdAt: Date.now(),\n };\n this.emit('command', command);\n break;\n }\n\n case 'commands.pending': {\n // v1.9.x cloud → daemon backlog replay on (re)connect\n // Cloud payload shape: { type: 'commands.pending', data: [{ commandId, commandType, envelope }, ...] }\n const pending = ((message as any).data || []) as Array<{ commandId: string; commandType: string; envelope?: unknown }>;\n for (const c of pending) {\n const command: RemoteCommand = {\n id: c.commandId,\n type: c.commandType,\n payload: (c.envelope as Record<string, unknown>) || {},\n createdAt: Date.now(),\n };\n this.emit('command', command);\n }\n break;\n }\n\n case 'rpc.request':\n // Cloud-initiated RPC (e.g. FS relay from mobile → cloud → daemon).\n // Dispatched via the rpcHandlers map; reply with rpc.response. All\n // paths must reply — timeout on the cloud side is enforced, but we\n // still send an error on any dispatch failure so the caller's promise\n // resolves promptly rather than waiting for the timeout.\n void this.handleRpcRequest(message);\n break;\n\n case 'error':\n console.error('[RelayClient] Relay error:', message.error);\n this.emit('relayError', message.error);\n break;\n\n default:\n console.warn('[RelayClient] Unknown control message type:', message.type);\n }\n } catch (err) {\n console.error('[RelayClient] Failed to parse control message:', err);\n }\n }\n\n /** RPC method handlers registered by the daemon process. Keyed by method\n * name (e.g. 'fs.read'). Result is serialized into the rpc.response\n * envelope. Thrown errors → `error` field. */\n private rpcHandlers = new Map<string, (params: unknown) => Promise<unknown>>();\n\n /** Register an RPC handler. Daemon code calls this at startup for each\n * method it wants to expose to cloud relay (mobile → cloud → daemon). */\n registerRpcHandler(method: string, handler: (params: unknown) => Promise<unknown>): void {\n this.rpcHandlers.set(method, handler);\n }\n\n private async handleRpcRequest(message: {\n rpcId?: string;\n method?: string;\n params?: unknown;\n }): Promise<void> {\n const rpcId = message.rpcId;\n const method = message.method;\n if (!rpcId || !method) return; // malformed; cloud will timeout\n\n const handler = this.rpcHandlers.get(method);\n if (!handler) {\n this.sendRpcResponse(rpcId, undefined, `unknown rpc method: ${method}`);\n return;\n }\n\n try {\n const result = await handler(message.params);\n this.sendRpcResponse(rpcId, result);\n } catch (err: any) {\n this.sendRpcResponse(rpcId, undefined, err?.message ?? String(err));\n }\n }\n\n private sendRpcResponse(rpcId: string, result: unknown, error?: string): void {\n if (!this.controlWs || this.controlWs.readyState !== 1) return;\n this.controlWs.send(JSON.stringify({\n type: 'rpc.response',\n rpcId,\n ...(error !== undefined ? { error } : { result }),\n }));\n }\n\n /**\n * Handle incoming data channel messages.\n *\n * v1.9.0 — intercept backfill-request (opcode 0x05) from the cloud\n * (cloud forwards it on behalf of a reconnecting mobile client) and\n * respond with backfill-chunk frames (opcode 0x06) for every timeline\n * entry with seq > payload.lastSeq.\n */\n private handleDataMessage(data: Buffer): void {\n if (this.outbox && data.length >= 2 && data[0] === OPCODE.BACKFILL_REQUEST) {\n try {\n const payload = JSON.parse(data.slice(2).toString('utf-8')) as { lastSeq?: number };\n const lastSeq = typeof payload.lastSeq === 'number' ? payload.lastSeq : 0;\n const entries = this.outbox.getTimelineSince(lastSeq);\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n const chunkJson = Buffer.from(\n JSON.stringify({\n seq: entry.seq,\n opcode: entry.opcode,\n slot: entry.slot,\n payload: entry.payload.toString('base64'),\n more: i < entries.length - 1,\n }),\n 'utf-8',\n );\n const frame = frameFromParts(OPCODE.BACKFILL_CHUNK, 0, chunkJson);\n if (this.dataWs && this.dataWs.readyState === 1) {\n this.dataWs.send(frame);\n }\n }\n console.log(`[RelayClient] Served ${entries.length} backfill entries since seq=${lastSeq}`);\n } catch (err) {\n console.error('[RelayClient] Backfill handling failed:', err);\n }\n return;\n }\n this.emit('data', data);\n }\n\n /**\n * Drain outbox by replaying queued frames over the data channel.\n * Called after reconnect() succeeds. Stops on the first send failure\n * to preserve ordering.\n */\n private replayOutbox(): void {\n if (!this.outbox || !this.dataWs || this.dataWs.readyState !== 1) return;\n const pending = this.outbox.drain();\n if (pending.length === 0) return;\n console.log(`[RelayClient] Replaying ${pending.length} queued frames from outbox`);\n for (const entry of pending) {\n try {\n this.dataWs.send(entry.frame);\n this.outbox.ack(entry.id);\n } catch (err) {\n console.error('[RelayClient] Replay failed — stopping to preserve order:', err);\n this.outbox.bumpAttempts(entry.id);\n break;\n }\n }\n }\n\n /** Pending count for status reporting. */\n getOutboxPending(): number {\n return this.outbox?.pendingCount() ?? 0;\n }\n\n /**\n * Handle remote command from mobile\n */\n private handleRemoteCommand(message: any): void {\n const command: RemoteCommand = {\n id: message.id,\n type: message.command,\n payload: message.payload || {},\n createdAt: message.timestamp || Date.now(),\n };\n\n this.emit('command', command);\n }\n\n /**\n * Start heartbeat interval\n */\n private startHeartbeat(): void {\n this.clearHeartbeat();\n\n this.heartbeatInterval = setInterval(() => {\n this.sendHeartbeat();\n }, this.heartbeatIntervalMs);\n\n // Send first heartbeat immediately\n this.sendHeartbeat();\n }\n\n /**\n * Clear heartbeat timers\n */\n private clearHeartbeat(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = undefined;\n }\n\n if (this.heartbeatTimer) {\n clearTimeout(this.heartbeatTimer);\n this.heartbeatTimer = undefined;\n }\n }\n\n /**\n * Send heartbeat to relay\n */\n private sendHeartbeat(): void {\n if (!this.controlWs || this.controlWs.readyState !== 1) {\n return;\n }\n\n const heartbeatMessage = {\n type: 'heartbeat',\n daemonId: this.daemonId,\n timestamp: Date.now(),\n };\n\n try {\n this.controlWs.send(JSON.stringify(heartbeatMessage));\n\n // Set timeout to detect if relay is responsive\n this.heartbeatTimer = setTimeout(() => {\n console.warn('[RelayClient] Heartbeat timeout - relay not responsive');\n this.handleDisconnect('heartbeat_timeout');\n }, HEARTBEAT_TIMEOUT_MS);\n } catch (err) {\n console.error('[RelayClient] Failed to send heartbeat:', err);\n }\n }\n\n /**\n * Acknowledge heartbeat from relay\n */\n private sendHeartbeatAck(): void {\n // Clear the timeout since we got a response\n if (this.heartbeatTimer) {\n clearTimeout(this.heartbeatTimer);\n this.heartbeatTimer = undefined;\n }\n\n this.state.lastHeartbeat = Date.now();\n }\n\n /**\n * Handle disconnection from one or both channels\n */\n private handleDisconnect(channel: 'control' | 'data' | 'heartbeat_timeout'): void {\n const wasConnected = this.state.connected;\n\n if (channel === 'control' || channel === 'heartbeat_timeout') {\n this.controlWs = null;\n }\n if (channel === 'data') {\n this.dataWs = null;\n }\n\n const isFullyDisconnected = !this.controlWs && !this.dataWs;\n\n if (isFullyDisconnected && wasConnected) {\n this.state.connected = false;\n this.state.channel = null;\n\n console.log('[RelayClient] Fully disconnected');\n this.emit('disconnected');\n }\n }\n\n /**\n * Schedule reconnection with exponential backoff\n */\n private scheduleReconnect(): void {\n this.clearReconnectTimer();\n\n const delay = Math.min(\n this.reconnectDelayMs * Math.pow(2, this.state.reconnectAttempts),\n this.maxReconnectDelayMs\n );\n\n console.log(\n `[RelayClient] Scheduling reconnect in ${delay}ms (attempt ${this.state.reconnectAttempts + 1})`\n );\n\n this.reconnectTimer = setTimeout(async () => {\n this.state.reconnectAttempts++;\n\n try {\n await this.connect();\n } catch (err) {\n console.error('[RelayClient] Reconnect failed:', err);\n // Will schedule another reconnect via error handler\n }\n }, delay);\n }\n\n /**\n * Clear reconnect timer\n */\n private clearReconnectTimer(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n }\n\n /**\n * Close control channel\n */\n private async closeControlChannel(): Promise<void> {\n return new Promise((resolve) => {\n if (!this.controlWs) {\n resolve();\n return;\n }\n\n this.controlWs.once('close', () => resolve());\n this.controlWs.close();\n });\n }\n\n /**\n * Close data channel\n */\n private async closeDataChannel(): Promise<void> {\n return new Promise((resolve) => {\n if (!this.dataWs) {\n resolve();\n return;\n }\n\n this.dataWs.once('close', () => resolve());\n this.dataWs.close();\n });\n }\n}\n","/**\n * Prismer daemon-side outbox + timeline (v1.9.0)\n *\n * Closes docs/version190/07-remote-control.md §5.6.5. Every outgoing data-plane\n * frame the daemon sends to the cloud relay is appended to an append-only\n * SQLite timeline with a monotonic seq. When the WS disconnects we also\n * buffer undelivered frames in a separate outbox table — reconnect drains\n * the outbox (replay), and incoming backfill-request opcodes from the cloud\n * replay timeline events above lastSeq.\n *\n * Scope bound: timeline <= 10k rows (auto-trimmed), outbox <= 10k rows.\n */\nimport Database from 'better-sqlite3';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\n// Types\n\nexport interface TimelineEntry {\n seq: number;\n opcode: number;\n slot: number;\n payload: Buffer;\n createdAt: number;\n}\n\nexport interface OutboxEntry {\n id: number;\n seq: number;\n frame: Buffer;\n createdAt: number;\n attempts: number;\n}\n\nexport interface DeadLetterEntry {\n id: number;\n originalId: number;\n seq: number;\n createdAt: number;\n failedAt: number;\n attempts: number;\n}\n\nexport interface DroppedFrame {\n id: number;\n seq: number;\n attempts: number;\n}\n\nexport interface DaemonOutboxOptions {\n bindingId: string;\n dataDir?: string;\n timelineCap?: number;\n outboxCap?: number;\n maxAttempts?: number;\n onDrop?: (entries: DroppedFrame[]) => void;\n}\n\nconst DEFAULT_CAP = 10000;\nconst DEFAULT_MAX_ATTEMPTS = 50;\n\nexport class DaemonOutbox {\n private db: Database.Database;\n private bindingId: string;\n private timelineCap: number;\n private outboxCap: number;\n private maxAttempts: number;\n private onDrop?: (entries: DroppedFrame[]) => void;\n private currentSeq: number = 0;\n private droppedCount: number = 0;\n\n constructor(opts: DaemonOutboxOptions) {\n this.bindingId = opts.bindingId;\n this.timelineCap = opts.timelineCap ?? DEFAULT_CAP;\n this.outboxCap = opts.outboxCap ?? DEFAULT_CAP;\n this.maxAttempts = opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n this.onDrop = opts.onDrop;\n\n const baseDir = opts.dataDir ?? path.join(os.homedir(), '.prismer', 'daemon', opts.bindingId);\n fs.mkdirSync(baseDir, { recursive: true });\n\n const dbPath = path.join(baseDir, 'outbox.db');\n this.db = new Database(dbPath);\n this.db.pragma('journal_mode = WAL');\n this.initSchema();\n\n const row = this.db.prepare('SELECT seq FROM timeline ORDER BY seq DESC LIMIT 1').get() as\n | { seq: number }\n | undefined;\n this.currentSeq = row?.seq ?? 0;\n }\n\n private initSchema(): void {\n this.db.exec(\n 'CREATE TABLE IF NOT EXISTS timeline (' +\n 'seq INTEGER PRIMARY KEY AUTOINCREMENT,' +\n 'opcode INTEGER NOT NULL,' +\n 'slot INTEGER NOT NULL,' +\n 'payload BLOB NOT NULL,' +\n 'createdAt INTEGER NOT NULL' +\n '); ' +\n 'CREATE INDEX IF NOT EXISTS idx_timeline_createdAt ON timeline(createdAt); ' +\n 'CREATE TABLE IF NOT EXISTS outbox (' +\n 'id INTEGER PRIMARY KEY AUTOINCREMENT,' +\n 'seq INTEGER NOT NULL,' +\n 'frame BLOB NOT NULL,' +\n 'createdAt INTEGER NOT NULL,' +\n 'attempts INTEGER NOT NULL DEFAULT 0' +\n '); ' +\n 'CREATE INDEX IF NOT EXISTS idx_outbox_seq ON outbox(seq); ' +\n 'CREATE TABLE IF NOT EXISTS outbox_dead_letter (' +\n 'id INTEGER PRIMARY KEY AUTOINCREMENT,' +\n 'originalId INTEGER NOT NULL,' +\n 'seq INTEGER NOT NULL,' +\n 'frame BLOB NOT NULL,' +\n 'createdAt INTEGER NOT NULL,' +\n 'failedAt INTEGER NOT NULL,' +\n 'attempts INTEGER NOT NULL' +\n ');',\n );\n }\n\n appendSent(opcode: number, slot: number, payload: Buffer): number {\n const now = Date.now();\n const result = this.db\n .prepare('INSERT INTO timeline (opcode, slot, payload, createdAt) VALUES (?, ?, ?, ?)')\n .run(opcode, slot, payload, now);\n this.currentSeq = Number(result.lastInsertRowid);\n this.enforceTimelineCap();\n return this.currentSeq;\n }\n\n getTimelineSince(lastSeq: number, limit = 500): TimelineEntry[] {\n return this.db\n .prepare('SELECT seq, opcode, slot, payload, createdAt FROM timeline WHERE seq > ? ORDER BY seq ASC LIMIT ?')\n .all(lastSeq, limit) as TimelineEntry[];\n }\n\n getCurrentSeq(): number {\n return this.currentSeq;\n }\n\n private enforceTimelineCap(): void {\n const count = (this.db.prepare('SELECT COUNT(*) as n FROM timeline').get() as { n: number }).n;\n if (count > this.timelineCap) {\n const excess = count - this.timelineCap;\n this.db\n .prepare('DELETE FROM timeline WHERE seq IN (SELECT seq FROM timeline ORDER BY seq ASC LIMIT ?)')\n .run(excess);\n }\n }\n\n queue(seq: number, frame: Buffer): number {\n const now = Date.now();\n const result = this.db\n .prepare('INSERT INTO outbox (seq, frame, createdAt, attempts) VALUES (?, ?, ?, 0)')\n .run(seq, frame, now);\n this.enforceOutboxCap();\n return Number(result.lastInsertRowid);\n }\n\n drain(limit = 500): OutboxEntry[] {\n return this.db\n .prepare('SELECT id, seq, frame, createdAt, attempts FROM outbox ORDER BY id ASC LIMIT ?')\n .all(limit) as OutboxEntry[];\n }\n\n ack(outboxId: number): void {\n this.db.prepare('DELETE FROM outbox WHERE id = ?').run(outboxId);\n }\n\n bumpAttempts(outboxId: number): { attempts: number; deadLettered: boolean } {\n const row = this.db\n .prepare('UPDATE outbox SET attempts = attempts + 1 WHERE id = ? RETURNING attempts')\n .get(outboxId) as { attempts: number } | undefined;\n if (!row) return { attempts: 0, deadLettered: false };\n if (row.attempts >= this.maxAttempts) {\n this.moveToDeadLetter(outboxId);\n return { attempts: row.attempts, deadLettered: true };\n }\n return { attempts: row.attempts, deadLettered: false };\n }\n\n private moveToDeadLetter(outboxId: number): void {\n const now = Date.now();\n const move = this.db.transaction(() => {\n const row = this.db\n .prepare('SELECT id, seq, frame, createdAt, attempts FROM outbox WHERE id = ?')\n .get(outboxId) as OutboxEntry | undefined;\n if (!row) return;\n this.db\n .prepare(\n 'INSERT INTO outbox_dead_letter (originalId, seq, frame, createdAt, failedAt, attempts) VALUES (?, ?, ?, ?, ?, ?)',\n )\n .run(row.id, row.seq, row.frame, row.createdAt, now, row.attempts);\n this.db.prepare('DELETE FROM outbox WHERE id = ?').run(outboxId);\n });\n move();\n }\n\n getDeadLetterCount(): number {\n return (this.db.prepare('SELECT COUNT(*) as n FROM outbox_dead_letter').get() as { n: number }).n;\n }\n\n getDeadLetterEntries(limit = 100, includeFrame = false): (DeadLetterEntry & { frame?: Buffer })[] {\n const cols = includeFrame\n ? 'id, originalId, seq, frame, createdAt, failedAt, attempts'\n : 'id, originalId, seq, createdAt, failedAt, attempts';\n return this.db\n .prepare(`SELECT ${cols} FROM outbox_dead_letter ORDER BY id ASC LIMIT ?`)\n .all(limit) as (DeadLetterEntry & { frame?: Buffer })[];\n }\n\n pendingCount(): number {\n return (this.db.prepare('SELECT COUNT(*) as n FROM outbox').get() as { n: number }).n;\n }\n\n getDroppedCount(): number {\n return this.droppedCount;\n }\n\n private enforceOutboxCap(): void {\n const count = this.pendingCount();\n if (count > this.outboxCap) {\n const excess = count - this.outboxCap;\n const toDelete = this.db\n .prepare('SELECT id, seq, attempts FROM outbox ORDER BY id ASC LIMIT ?')\n .all(excess) as DroppedFrame[];\n this.db\n .prepare('DELETE FROM outbox WHERE id IN (SELECT id FROM outbox ORDER BY id ASC LIMIT ?)')\n .run(excess);\n this.droppedCount += toDelete.length;\n if (this.onDrop && toDelete.length > 0) {\n this.onDrop(toDelete);\n }\n }\n }\n\n close(): void {\n this.db.close();\n }\n}\n\n/** 2-byte header + payload per §5.6.4 */\nexport function frameFromParts(opcode: number, slot: number, payload: Buffer): Buffer {\n const buf = Buffer.alloc(2 + payload.length);\n buf[0] = opcode;\n buf[1] = slot;\n payload.copy(buf, 2);\n return buf;\n}\n","/**\n * Prismer Runtime — E2EE Crypto Module (v1.9.0)\n *\n * End-to-end encryption for LAN direct connections.\n * Uses X25519 for key exchange and XSalsa20-Poly1305 for encryption.\n *\n * Security model:\n * - Daemon and mobile each generate X25519 keypair\n * - Keys are exchanged via QR code or relay (out-of-band)\n * - Each session derives unique encryption key via HKDF\n * - All LAN traffic is encrypted - relay never sees plaintext\n *\n * This implementation uses Node.js built-in crypto module for\n * compatibility and no external dependencies.\n */\n\nimport * as crypto from 'node:crypto';\n\n// ============================================================\n// Types\n// ============================================================\n\nexport interface KeyPair {\n publicKey: Buffer;\n privateKey: Buffer;\n}\n\nexport interface E2EEContext {\n localKeyPair: KeyPair;\n remotePublicKey: Buffer;\n sharedSecret: Buffer;\n sendKey: Buffer;\n recvKey: Buffer;\n sendNonce: Buffer;\n recvNonce: Buffer;\n}\n\nexport interface EncryptedEnvelope {\n version: number;\n nonce: Buffer;\n ciphertext: Buffer;\n authTag: Buffer;\n}\n\n// ============================================================\n// Constants\n// ============================================================\n\nconst KEY_SIZE = 32; // X25519 key size (bytes)\nconst NONCE_SIZE = 24; // XSalsa20 nonce size (bytes)\nconst AUTH_TAG_SIZE = 16; // Poly1305 auth tag size (bytes)\n// Direction labels for HKDF — peer with smaller public key takes the\n// \"A\" role so both sides agree which side's send key matches which\n// side's recv key. The previous SEND/RECV split gave both peers\n// identical (sendKey, recvKey) and broke decryption end-to-end.\nconst HKDF_INFO_A_TO_B = Buffer.from('prismer-lan-a2b');\nconst HKDF_INFO_B_TO_A = Buffer.from('prismer-lan-b2a');\nconst PROTOCOL_VERSION = 1;\nconst X25519_SPKI_PREFIX = Buffer.from('302a300506032b656e032100', 'hex');\nconst X25519_PKCS8_PREFIX = Buffer.from('302e020100300506032b656e04220420', 'hex');\n\n// ============================================================\n// Key Generation\n// ============================================================\n\n/**\n * Generate X25519 keypair for E2EE\n */\nexport function generateKeyPair(): KeyPair {\n const { publicKey, privateKey } = crypto.generateKeyPairSync('x25519');\n const pubKeyBuffer = publicKey.export({ type: 'spki', format: 'der' });\n const privKeyBuffer = privateKey.export({ type: 'pkcs8', format: 'der' });\n\n const pubKeyRaw = extractX25519PublicFromSPKI(pubKeyBuffer);\n const privKeyRaw = extractX25519PrivateFromPKCS8(privKeyBuffer);\n\n return {\n publicKey: pubKeyRaw,\n privateKey: privKeyRaw,\n };\n}\n\n/**\n * Extract raw X25519 public key from SPKI format\n */\nfunction extractX25519PublicFromSPKI(spki: Buffer): Buffer {\n if (\n spki.length !== X25519_SPKI_PREFIX.length + KEY_SIZE ||\n !spki.subarray(0, X25519_SPKI_PREFIX.length).equals(X25519_SPKI_PREFIX)\n ) {\n throw new Error('Invalid X25519 SPKI format');\n }\n\n const key = spki.subarray(X25519_SPKI_PREFIX.length);\n\n if (key.length !== KEY_SIZE) {\n throw new Error(`Invalid X25519 public key size: ${key.length}`);\n }\n\n return key;\n}\n\n/**\n * Extract raw X25519 private key from PKCS8 format\n */\nfunction extractX25519PrivateFromPKCS8(pkcs8: Buffer): Buffer {\n if (\n pkcs8.length !== X25519_PKCS8_PREFIX.length + KEY_SIZE ||\n !pkcs8.subarray(0, X25519_PKCS8_PREFIX.length).equals(X25519_PKCS8_PREFIX)\n ) {\n throw new Error('Invalid X25519 PKCS8 format');\n }\n\n const key = pkcs8.subarray(X25519_PKCS8_PREFIX.length);\n\n if (key.length !== KEY_SIZE) {\n throw new Error(`Invalid X25519 private key size: ${key.length}`);\n }\n\n return key;\n}\n\n/**\n * Derive shared secret from local private key and remote public key (X25519)\n */\nexport function deriveSharedSecret(\n localPrivateKey: Buffer,\n remotePublicKey: Buffer\n): Buffer {\n if (localPrivateKey.length !== KEY_SIZE) {\n throw new Error(`Invalid local private key size: ${localPrivateKey.length}`);\n }\n if (remotePublicKey.length !== KEY_SIZE) {\n throw new Error(`Invalid remote public key size: ${remotePublicKey.length}`);\n }\n\n const privateKey = crypto.createPrivateKey({\n key: Buffer.concat([X25519_PKCS8_PREFIX, localPrivateKey]),\n format: 'der',\n type: 'pkcs8',\n });\n const publicKey = crypto.createPublicKey({\n key: Buffer.concat([X25519_SPKI_PREFIX, remotePublicKey]),\n format: 'der',\n type: 'spki',\n });\n const sharedSecret = crypto.diffieHellman({ privateKey, publicKey });\n\n if (sharedSecret.length !== KEY_SIZE) {\n throw new Error(`Invalid shared secret size: ${sharedSecret.length}`);\n }\n\n return sharedSecret;\n}\n\n// ============================================================\n// Session Key Derivation\n// ============================================================\n\n/**\n * Derive send/recv keys from shared secret using HKDF-SHA256.\n *\n * Role is determined by lexicographic comparison of the two public keys\n * so both peers agree without an explicit role flag. Without the keys\n * (legacy single-context callers), defaults to the \"A\" role.\n */\nexport function deriveSessionKeys(\n sharedSecret: Buffer,\n localPublicKey?: Buffer,\n remotePublicKey?: Buffer\n): {\n sendKey: Buffer;\n recvKey: Buffer;\n} {\n const isA =\n localPublicKey === undefined ||\n remotePublicKey === undefined ||\n Buffer.compare(localPublicKey, remotePublicKey) < 0;\n\n const sendInfo = isA ? HKDF_INFO_A_TO_B : HKDF_INFO_B_TO_A;\n const recvInfo = isA ? HKDF_INFO_B_TO_A : HKDF_INFO_A_TO_B;\n\n const sendKey = hkdfSha256(sharedSecret, Buffer.alloc(0), sendInfo, KEY_SIZE);\n const recvKey = hkdfSha256(sharedSecret, Buffer.alloc(0), recvInfo, KEY_SIZE);\n\n return { sendKey, recvKey };\n}\n\n/**\n * HKDF-SHA256 key derivation\n */\nfunction hkdfSha256(\n ikm: Buffer,\n salt: Buffer,\n info: Buffer,\n length: number\n): Buffer {\n // Extract\n const prk = crypto\n .createHmac('sha256', salt)\n .update(ikm)\n .digest();\n\n // Expand\n const t: Buffer[] = [];\n let outputLength = 0;\n let i = 1;\n\n while (outputLength < length) {\n const hmac = crypto.createHmac('sha256', prk);\n\n if (t.length > 0) {\n hmac.update(t[t.length - 1]);\n }\n\n hmac.update(info);\n hmac.update(Buffer.from([i]));\n const t_i = hmac.digest();\n\n t.push(t_i);\n outputLength += t_i.length;\n i++;\n }\n\n return Buffer.concat(t).slice(0, length);\n}\n\n// ============================================================\n// Encryption / Decryption\n// ============================================================\n\n/**\n * Encrypt data using ChaCha20-Poly1305 (AEAD)\n * Node.js built-in crypto supports this via crypto.createCipheriv('chacha20-poly1305')\n */\nexport function encrypt(\n key: Buffer,\n plaintext: Buffer,\n nonce?: Buffer\n): EncryptedEnvelope {\n if (key.length !== KEY_SIZE) {\n throw new Error(`Invalid key size: ${key.length}`);\n }\n\n // Generate random nonce if not provided\n const iv = nonce || crypto.randomBytes(NONCE_SIZE);\n\n // ChaCha20-Poly1305: 32-byte key, 12-byte nonce\n // We truncate our 24-byte nonce to 12 bytes for ChaCha20-Poly1305\n const chachaNonce = iv.slice(0, 12);\n\n const cipher = crypto.createCipheriv('chacha20-poly1305', key, chachaNonce);\n\n const ciphertext = Buffer.concat([\n cipher.update(plaintext),\n cipher.final(),\n ]);\n\n const authTag = cipher.getAuthTag();\n\n return {\n version: PROTOCOL_VERSION,\n nonce: iv,\n ciphertext,\n authTag,\n };\n}\n\n/**\n * Decrypt data using ChaCha20-Poly1305\n */\nexport function decrypt(\n key: Buffer,\n envelope: EncryptedEnvelope\n): Buffer {\n if (key.length !== KEY_SIZE) {\n throw new Error(`Invalid key size: ${key}`);\n }\n if (envelope.nonce.length !== NONCE_SIZE) {\n throw new Error(`Invalid nonce size: ${envelope.nonce.length}`);\n }\n if (envelope.authTag.length !== AUTH_TAG_SIZE) {\n throw new Error(`Invalid auth tag size: ${envelope.authTag}`);\n }\n\n // Truncate nonce for ChaCha20-Poly1305\n const chachaNonce = envelope.nonce.slice(0, 12);\n\n const decipher = crypto.createDecipheriv('chacha20-poly1305', key, chachaNonce);\n decipher.setAuthTag(envelope.authTag);\n\n try {\n const plaintext = Buffer.concat([\n decipher.update(envelope.ciphertext),\n decipher.final(),\n ]);\n return plaintext;\n } catch (err) {\n throw new Error(`Decryption failed: ${(err as Error).message}`);\n }\n}\n\n/**\n * Serialize encrypted envelope to buffer\n */\nexport function serializeEnvelope(envelope: EncryptedEnvelope): Buffer {\n const version = Buffer.from([envelope.version]);\n const nonceLen = Buffer.from([NONCE_SIZE]);\n const authTagLen = Buffer.from([AUTH_TAG_SIZE]);\n const ciphertextLen = Buffer.alloc(4);\n ciphertextLen.writeUInt32BE(envelope.ciphertext.length, 0);\n\n return Buffer.concat([\n version,\n nonceLen,\n authTagLen,\n ciphertextLen,\n envelope.nonce,\n envelope.authTag,\n envelope.ciphertext,\n ]);\n}\n\n/**\n * Deserialize encrypted envelope from buffer\n */\nexport function deserializeEnvelope(data: Buffer): EncryptedEnvelope {\n let offset = 0;\n\n const version = data[offset];\n offset += 1;\n\n if (version !== PROTOCOL_VERSION) {\n throw new Error(`Unsupported protocol version: ${version}`);\n }\n\n const nonceLen = data[offset];\n offset += 1;\n\n const authTagLen = data[offset];\n offset += 1;\n\n const ciphertextLen = data.readUInt32BE(offset);\n offset += 4;\n\n if (nonceLen !== NONCE_SIZE) {\n throw new Error(`Invalid nonce length in envelope: ${nonceLen}`);\n }\n if (authTagLen !== AUTH_TAG_SIZE) {\n throw new Error(`Invalid auth tag length in envelope: ${authTagLen}`);\n }\n\n const nonce = data.slice(offset, offset + nonceLen);\n offset += nonceLen;\n\n const authTag = data.slice(offset, offset + authTagLen);\n offset += authTagLen;\n\n const ciphertext = data.slice(offset, offset + ciphertextLen);\n\n return {\n version,\n nonce,\n ciphertext,\n authTag,\n };\n}\n\n// ============================================================\n// E2EE Context Management\n// ============================================================\n\n/**\n * Create E2EE context for a session\n */\nexport function createE2EEContext(\n localKeyPair: KeyPair,\n remotePublicKey: Buffer\n): E2EEContext {\n // Derive shared secret\n const sharedSecret = deriveSharedSecret(\n localKeyPair.privateKey,\n remotePublicKey\n );\n\n // Derive session keys with role-aware HKDF (peer with smaller public\n // key takes the \"A\" role) — see deriveSessionKeys for the rationale.\n const { sendKey, recvKey } = deriveSessionKeys(\n sharedSecret,\n localKeyPair.publicKey,\n remotePublicKey\n );\n\n // Initialize nonces\n const sendNonce = crypto.randomBytes(NONCE_SIZE);\n const recvNonce = crypto.randomBytes(NONCE_SIZE);\n\n return {\n localKeyPair,\n remotePublicKey,\n sharedSecret,\n sendKey,\n recvKey,\n sendNonce,\n recvNonce,\n };\n}\n\n/**\n * Encrypt message using E2EE context\n */\nexport function encryptMessage(context: E2EEContext, plaintext: Buffer): Buffer {\n // Increment send nonce BEFORE encrypting (so each message uses unique nonce)\n incrementNonce(context.sendNonce);\n\n const envelope = encrypt(context.sendKey, plaintext, context.sendNonce);\n\n return serializeEnvelope(envelope);\n}\n\n/**\n * Decrypt message using E2EE context\n */\nexport function decryptMessage(context: E2EEContext, data: Buffer): Buffer {\n const envelope = deserializeEnvelope(data);\n\n // Decrypt using recvKey and the nonce from envelope\n // Note: We don't use context.recvNonce - the nonce in envelope\n // is what the sender used for encryption\n const decrypted = decrypt(context.recvKey, envelope);\n\n return decrypted;\n}\n\n/**\n * Increment nonce (simple big-endian increment)\n */\nfunction incrementNonce(nonce: Buffer): void {\n let carry = 1;\n for (let i = nonce.length - 1; i >= 0 && carry > 0; i--) {\n const sum = nonce[i] + carry;\n nonce[i] = sum & 0xff;\n carry = sum >> 8;\n }\n\n // If carry is still set, nonce wrapped around (should not happen with 24-byte nonce)\n if (carry > 0) {\n throw new Error('Nonce overflow - too many messages in session');\n }\n}\n\n// ============================================================\n// Key Serialization\n// ============================================================\n\n/**\n * Serialize public key to base64\n */\nexport function serializePublicKey(publicKey: Buffer): string {\n return publicKey.toString('base64');\n}\n\n/**\n * Deserialize public key from base64\n */\nexport function deserializePublicKey(data: string): Buffer {\n return Buffer.from(data, 'base64');\n}\n\n/**\n * Serialize keypair to JSON\n */\nexport function serializeKeyPair(keyPair: KeyPair): {\n publicKey: string;\n privateKey: string;\n} {\n return {\n publicKey: serializePublicKey(keyPair.publicKey),\n privateKey: keyPair.privateKey.toString('base64'),\n };\n}\n\n/**\n * Deserialize keypair from JSON\n */\nexport function deserializeKeyPair(data: {\n publicKey: string;\n privateKey: string;\n}): KeyPair {\n return {\n publicKey: deserializePublicKey(data.publicKey),\n privateKey: Buffer.from(data.privateKey, 'base64'),\n };\n}\n","/**\n * Prismer Runtime — Cloud URL derivation\n *\n * Single source for building WSS URLs from the cloud HTTP base.\n * v1.9.0 decision: WSS relay reuses the main cloud host\n * (e.g. `cloud.prismer.dev` / `prismer.cloud`); there is no separate\n * relay subdomain. All relay/WS paths live under `/ws/*` on the same host.\n */\n\n/**\n * Derive the base WSS URL from an HTTP(S) cloud base URL.\n *\n * Examples:\n * https://cloud.prismer.dev → wss://cloud.prismer.dev\n * http://localhost:3000 → ws://localhost:3000\n * https://prismer.cloud/ → wss://prismer.cloud\n *\n * Returns `undefined` when the input is falsy, so callers can gate WS\n * startup on \"do we have a cloud base configured at all\".\n */\nexport function deriveWsFromHttp(httpUrl: string | undefined): string | undefined {\n if (!httpUrl) return undefined;\n return httpUrl.replace(/^http/, 'ws').replace(/\\/+$/, '');\n}\n\n/**\n * Extract the host[:port] portion from a cloud base URL.\n *\n * https://cloud.prismer.dev → cloud.prismer.dev\n * http://localhost:3000 → localhost:3000\n *\n * Used by probes that want a bare host tuple, not a full URL.\n */\nexport function deriveHostFromHttp(httpUrl: string | undefined): string | undefined {\n if (!httpUrl) return undefined;\n try {\n const u = new URL(httpUrl);\n return u.port ? `${u.hostname}:${u.port}` : u.hostname;\n } catch {\n return undefined;\n }\n}\n","import * as crypto from 'node:crypto';\nimport { MemoryDB, type EncryptionConfig, deriveKey, generateSalt } from './memory-db.js';\nimport type { RouteHandler } from './daemon-http.js';\nimport { sendJson } from './http/helpers.js';\n\nconst LOG = '[MemoryGatewayAPI]';\n\nexport interface WriteMemoryRequest {\n ownerId: string;\n ownerType: 'user' | 'agent';\n path: string;\n content: string;\n scope?: string;\n memoryType?: string;\n description?: string;\n encrypt?: boolean;\n}\n\nexport interface RecallRequest {\n keyword: string;\n ownerId?: string;\n scope?: string;\n limit?: number;\n useCloudFallback?: boolean;\n}\n\nexport interface ListMemoryRequest {\n ownerId?: string;\n scope?: string;\n path?: string;\n memoryType?: string;\n stale?: boolean;\n limit?: number;\n offset?: number;\n}\n\nexport interface MemoryResponse {\n success: boolean;\n data?: unknown;\n error?: {\n code: string;\n message: string;\n };\n}\n\nfunction parseJsonBody<T>(buf: Buffer): T {\n if (buf.length === 0) return {} as T;\n return JSON.parse(buf.toString('utf8')) as T;\n}\n\nfunction parseQuery(reqUrl: string | undefined): URLSearchParams {\n return new URL(reqUrl ?? '/', 'http://localhost').searchParams;\n}\n\nfunction extractId(reqUrl: string | undefined): string | null {\n const pathname = new URL(reqUrl ?? '/', 'http://localhost').pathname;\n const match = pathname.match(/\\/memory\\/([^/]+)$/);\n return match ? decodeURIComponent(match[1]) : null;\n}\n\nexport interface MemoryGatewayAPIOptions {\n filePath?: string;\n}\n\nexport class MemoryGatewayAPI {\n private readonly db: MemoryDB;\n\n constructor(\n encryptionConfig: EncryptionConfig = { enabled: false },\n opts: MemoryGatewayAPIOptions = {},\n ) {\n this.db = new MemoryDB(encryptionConfig, { filePath: opts.filePath });\n }\n\n handleWrite: RouteHandler = async (_req, res, ctx) => {\n try {\n const body = parseJsonBody<WriteMemoryRequest>(ctx.body);\n if (!body.ownerId || !body.ownerType || !body.path || body.content === undefined) {\n return sendJson(res, 400, {\n success: false,\n error: {\n code: 'INVALID_REQUEST',\n message: 'Missing required fields: ownerId, ownerType, path, content',\n },\n });\n }\n\n const file = this.db.writeMemoryFile({\n ownerId: body.ownerId,\n ownerType: body.ownerType,\n scope: body.scope,\n path: body.path,\n content: body.content,\n memoryType: body.memoryType,\n description: body.description,\n });\n\n console.log(`${LOG} Write: ${file.scope}/${file.path} (${file.id})`);\n sendJson(res, 200, {\n success: true,\n ok: true,\n data: file,\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`${LOG} Write error:`, msg);\n sendJson(res, 500, {\n success: false,\n error: {\n code: 'WRITE_ERROR',\n message: msg,\n },\n });\n }\n };\n\n handleRecall: RouteHandler = async (_req, res, ctx) => {\n try {\n const body = parseJsonBody<RecallRequest>(ctx.body);\n if (!body.keyword) {\n return sendJson(res, 400, {\n success: false,\n error: {\n code: 'INVALID_REQUEST',\n message: 'Missing required field: keyword',\n },\n });\n }\n\n const startTime = Date.now();\n const results = this.db.searchMemoryFiles(body.keyword, {\n ownerId: body.ownerId,\n scope: body.scope,\n limit: body.limit ?? 10,\n });\n const durationMs = Date.now() - startTime;\n\n sendJson(res, 200, {\n success: true,\n ok: true,\n data: {\n results,\n query: body.keyword,\n count: results.length,\n durationMs,\n },\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`${LOG} Recall error:`, msg);\n sendJson(res, 500, {\n success: false,\n error: {\n code: 'RECALL_ERROR',\n message: msg,\n },\n });\n }\n };\n\n handleDelete: RouteHandler = async (req, res) => {\n try {\n const id = extractId(req.url);\n if (!id) {\n return sendJson(res, 400, {\n success: false,\n error: {\n code: 'INVALID_REQUEST',\n message: 'Missing required parameter: id',\n },\n });\n }\n\n const deleted = this.db.deleteMemoryFile(id);\n if (!deleted) {\n return sendJson(res, 404, {\n success: false,\n error: {\n code: 'NOT_FOUND',\n message: `Memory file not found: ${id}`,\n },\n });\n }\n\n console.log(`${LOG} Delete: ${id}`);\n sendJson(res, 200, {\n success: true,\n ok: true,\n data: { id },\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`${LOG} Delete error:`, msg);\n sendJson(res, 500, {\n success: false,\n error: {\n code: 'DELETE_ERROR',\n message: msg,\n },\n });\n }\n };\n\n handleList: RouteHandler = async (req, res) => {\n try {\n const query = parseQuery(req.url);\n const staleRaw = query.get('stale');\n const files = this.db.listMemoryFiles({\n ownerId: query.get('ownerId') ?? undefined,\n scope: query.get('scope') ?? undefined,\n path: query.get('path') ?? undefined,\n memoryType: query.get('memoryType') ?? undefined,\n stale: staleRaw === null ? undefined : staleRaw === 'true',\n limit: query.get('limit') ? parseInt(query.get('limit') ?? '50', 10) : undefined,\n offset: query.get('offset') ? parseInt(query.get('offset') ?? '0', 10) : undefined,\n });\n\n sendJson(res, 200, {\n success: true,\n ok: true,\n data: {\n files,\n count: files.length,\n },\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`${LOG} List error:`, msg);\n sendJson(res, 500, {\n success: false,\n error: {\n code: 'LIST_ERROR',\n message: msg,\n },\n });\n }\n };\n\n handleStats: RouteHandler = async (req, res) => {\n try {\n const query = parseQuery(req.url);\n const stats = this.db.getStats(query.get('ownerId') ?? undefined);\n sendJson(res, 200, {\n success: true,\n ok: true,\n data: stats,\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`${LOG} Stats error:`, msg);\n sendJson(res, 500, {\n success: false,\n error: {\n code: 'STATS_ERROR',\n message: msg,\n },\n });\n }\n };\n\n registerRoutes(daemon: {\n registerRoute: (\n method: 'GET' | 'POST' | 'PATCH' | 'DELETE',\n path: string,\n handler: RouteHandler,\n ) => void;\n }): void {\n daemon.registerRoute('POST', '/memory/write', this.handleWrite);\n daemon.registerRoute('POST', '/memory/recall', this.handleRecall);\n daemon.registerRoute('DELETE', '/memory/:id', this.handleDelete);\n daemon.registerRoute('GET', '/memory', this.handleList);\n daemon.registerRoute('GET', '/memory/stats', this.handleStats);\n\n console.log(`${LOG} Registered memory routes`);\n }\n\n shutdown(): void {\n this.db.close();\n console.log(`${LOG} Shutdown complete`);\n }\n}\n\nexport function buildEncryptionConfig(password?: string): EncryptionConfig {\n if (!password) {\n return { enabled: false };\n }\n\n const salt = generateSalt();\n const key = deriveKey(password, salt);\n\n return {\n enabled: true,\n key,\n };\n}\n\nlet gatewayAPIInstance: MemoryGatewayAPI | null = null;\n\nexport function getMemoryGatewayAPI(\n encryptionConfig?: EncryptionConfig,\n opts?: MemoryGatewayAPIOptions,\n): MemoryGatewayAPI {\n if (!gatewayAPIInstance) {\n gatewayAPIInstance = new MemoryGatewayAPI(encryptionConfig, opts);\n }\n return gatewayAPIInstance;\n}\n\nexport function closeMemoryGatewayAPI(): void {\n if (gatewayAPIInstance) {\n gatewayAPIInstance.shutdown();\n gatewayAPIInstance = null;\n }\n}\n\nexport function createMemoryId(): string {\n return crypto.randomUUID();\n}\n","import * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport Database from 'better-sqlite3';\nimport type BetterSqlite3 from 'better-sqlite3';\nimport { createContentCrypto, type ContentCrypto } from './memory-db-crypto.js';\n\nexport interface EncryptionConfig {\n enabled: boolean;\n key?: Buffer;\n}\n\nexport interface MemoryFile {\n id: string;\n ownerId: string;\n ownerType: 'user' | 'agent';\n scope: string;\n path: string;\n content: string;\n version: number;\n memoryType?: string;\n description?: string;\n contentHash: string;\n createdAt: string;\n updatedAt: string;\n stale: boolean;\n}\n\nexport interface MemoryFileVersion {\n id: string;\n fileId: string;\n version: number;\n content: string;\n createdAt: string;\n}\n\nexport interface DreamCompaction {\n id: string;\n ownerId: string;\n scope: string;\n summary: string;\n createdAt: string;\n}\n\nexport interface WriteMemoryFileInput {\n ownerId: string;\n ownerType: 'user' | 'agent';\n scope?: string;\n path: string;\n content: string;\n memoryType?: string;\n description?: string;\n}\n\nexport interface MemoryFileFilters {\n ownerId?: string;\n scope?: string;\n path?: string;\n memoryType?: string;\n stale?: boolean;\n limit?: number;\n offset?: number;\n}\n\nexport interface MemorySearchResult extends MemoryFile {\n relevance: number;\n snippet?: string;\n}\n\nexport interface MemoryStats {\n fileCount: number;\n totalSize: number;\n totalBytes: number;\n staleFiles: number;\n ftsIndexed: number;\n recallP95: number;\n}\n\nfunction defaultStorePath(): string {\n return path.join(os.homedir(), '.prismer', 'memory.db');\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nfunction hashContent(content: string): string {\n return crypto.createHash('sha256').update(content).digest('hex');\n}\n\n/** Map a raw SQLite row (stale as 0|1) to a MemoryFile interface object.\n * `decryptContent` is applied to the raw content column so that plaintext\n * rows pass through and ciphertext envelopes are unwrapped transparently. */\nfunction rowToMemoryFile(\n row: Record<string, unknown>,\n decryptContent: (v: string) => string = (v) => v,\n): MemoryFile {\n return {\n id: row.id as string,\n ownerId: row.ownerId as string,\n ownerType: row.ownerType as 'user' | 'agent',\n scope: row.scope as string,\n path: row.path as string,\n content: decryptContent(row.content as string),\n version: row.version as number,\n memoryType: (row.memoryType as string) || undefined,\n description: (row.description as string) || undefined,\n contentHash: row.contentHash as string,\n createdAt: row.createdAt as string,\n updatedAt: row.updatedAt as string,\n stale: (row.stale as number) === 1,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Schema DDL\n// ---------------------------------------------------------------------------\n\nconst SCHEMA_DDL = `\nCREATE TABLE IF NOT EXISTS memory_files (\n id TEXT PRIMARY KEY,\n ownerId TEXT NOT NULL,\n ownerType TEXT NOT NULL DEFAULT 'user',\n scope TEXT NOT NULL DEFAULT 'global',\n path TEXT NOT NULL,\n content TEXT NOT NULL,\n version INTEGER NOT NULL DEFAULT 1,\n memoryType TEXT,\n description TEXT,\n contentHash TEXT NOT NULL,\n createdAt TEXT NOT NULL,\n updatedAt TEXT NOT NULL,\n stale INTEGER NOT NULL DEFAULT 0,\n UNIQUE(ownerId, scope, path)\n);\n\nCREATE TABLE IF NOT EXISTS memory_file_versions (\n id TEXT PRIMARY KEY,\n fileId TEXT NOT NULL,\n version INTEGER NOT NULL,\n content TEXT NOT NULL,\n createdAt TEXT NOT NULL,\n FOREIGN KEY (fileId) REFERENCES memory_files(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS memory_dreams (\n id TEXT PRIMARY KEY,\n ownerId TEXT NOT NULL,\n scope TEXT NOT NULL DEFAULT 'global',\n summary TEXT NOT NULL,\n createdAt TEXT NOT NULL\n);\n\nCREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(\n path,\n description,\n content,\n content=memory_files,\n content_rowid=rowid\n);\n\nCREATE TRIGGER IF NOT EXISTS memory_fts_ai AFTER INSERT ON memory_files BEGIN\n INSERT INTO memory_fts(rowid, path, description, content)\n VALUES (new.rowid, new.path, COALESCE(new.description, ''), new.content);\nEND;\n\nCREATE TRIGGER IF NOT EXISTS memory_fts_ad AFTER DELETE ON memory_files BEGIN\n INSERT INTO memory_fts(memory_fts, rowid, path, description, content)\n VALUES ('delete', old.rowid, old.path, COALESCE(old.description, ''), old.content);\nEND;\n\nCREATE TRIGGER IF NOT EXISTS memory_fts_au AFTER UPDATE ON memory_files BEGIN\n INSERT INTO memory_fts(memory_fts, rowid, path, description, content)\n VALUES ('delete', old.rowid, old.path, COALESCE(old.description, ''), old.content);\n INSERT INTO memory_fts(rowid, path, description, content)\n VALUES (new.rowid, new.path, COALESCE(new.description, ''), new.content);\nEND;\n`;\n\n// ---------------------------------------------------------------------------\n// JSON migration helper\n// ---------------------------------------------------------------------------\n\ninterface LegacyStoreShape {\n files: MemoryFile[];\n versions: MemoryFileVersion[];\n dreams: DreamCompaction[];\n}\n\nfunction migrateFromJson(jsonPath: string, db: BetterSqlite3.Database): void {\n let raw: string;\n try {\n raw = fs.readFileSync(jsonPath, 'utf-8');\n } catch {\n return; // JSON file unreadable -- skip\n }\n\n let parsed: Partial<LegacyStoreShape>;\n try {\n parsed = JSON.parse(raw) as Partial<LegacyStoreShape>;\n } catch {\n return; // malformed JSON -- skip\n }\n\n const files = Array.isArray(parsed.files) ? parsed.files : [];\n const versions = Array.isArray(parsed.versions) ? parsed.versions : [];\n const dreams = Array.isArray(parsed.dreams) ? parsed.dreams : [];\n\n if (files.length === 0 && versions.length === 0 && dreams.length === 0) {\n return;\n }\n\n const insertFile = db.prepare(`\n INSERT OR IGNORE INTO memory_files\n (id, ownerId, ownerType, scope, path, content, version, memoryType, description, contentHash, createdAt, updatedAt, stale)\n VALUES\n (@id, @ownerId, @ownerType, @scope, @path, @content, @version, @memoryType, @description, @contentHash, @createdAt, @updatedAt, @stale)\n `);\n\n const insertVersion = db.prepare(`\n INSERT OR IGNORE INTO memory_file_versions\n (id, fileId, version, content, createdAt)\n VALUES\n (@id, @fileId, @version, @content, @createdAt)\n `);\n\n const insertDream = db.prepare(`\n INSERT OR IGNORE INTO memory_dreams\n (id, ownerId, scope, summary, createdAt)\n VALUES\n (@id, @ownerId, @scope, @summary, @createdAt)\n `);\n\n const importAll = db.transaction(() => {\n for (const f of files) {\n insertFile.run({\n id: f.id,\n ownerId: f.ownerId,\n ownerType: f.ownerType,\n scope: f.scope,\n path: f.path,\n content: f.content,\n version: f.version,\n memoryType: f.memoryType ?? null,\n description: f.description ?? null,\n contentHash: f.contentHash,\n createdAt: f.createdAt,\n updatedAt: f.updatedAt,\n stale: f.stale ? 1 : 0,\n });\n }\n for (const v of versions) {\n insertVersion.run({\n id: v.id,\n fileId: v.fileId,\n version: v.version,\n content: v.content,\n createdAt: v.createdAt,\n });\n }\n for (const d of dreams) {\n insertDream.run({\n id: d.id,\n ownerId: d.ownerId,\n scope: d.scope,\n summary: d.summary,\n createdAt: d.createdAt,\n });\n }\n });\n\n importAll();\n\n // Rename JSON file to .migrated so it is not re-imported\n try {\n fs.renameSync(jsonPath, jsonPath + '.migrated');\n } catch {\n // best effort\n }\n}\n\n// ---------------------------------------------------------------------------\n// MemoryDB class -- SQLite + FTS5\n// ---------------------------------------------------------------------------\n\nexport class MemoryDB {\n private readonly filePath: string;\n private readonly db: BetterSqlite3.Database;\n private readonly crypto: ContentCrypto;\n\n constructor(_encryptionConfig: EncryptionConfig = { enabled: false }, opts?: { filePath?: string }) {\n this.filePath = opts?.filePath ?? defaultStorePath();\n // v1.9.0 opt-in: content encryption via env var PRISMER_DB_ENCRYPTION=1.\n // The legacy `_encryptionConfig` parameter is retained for API stability but\n // the actual switch is the env var — this matches how @prismer/runtime\n // reads secrets everywhere else (keychain + env indirection).\n this.crypto = createContentCrypto();\n\n // Ensure parent directory exists\n fs.mkdirSync(path.dirname(this.filePath), { recursive: true });\n\n this.db = new Database(this.filePath);\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('foreign_keys = ON');\n\n // Create schema\n this.db.exec(SCHEMA_DDL);\n\n // Migrate from legacy JSON file if it exists and DB is fresh\n const jsonPath = this.filePath.replace(/\\.db$/, '.json');\n if (jsonPath !== this.filePath && fs.existsSync(jsonPath)) {\n const count = (this.db.prepare('SELECT COUNT(*) AS cnt FROM memory_files').get() as { cnt: number }).cnt;\n if (count === 0) {\n migrateFromJson(jsonPath, this.db);\n }\n }\n }\n\n writeMemoryFile(input: WriteMemoryFileInput): MemoryFile {\n const scope = input.scope ?? 'global';\n const timestamp = nowIso();\n\n const existing = this.db.prepare(\n 'SELECT * FROM memory_files WHERE ownerId = ? AND scope = ? AND path = ?',\n ).get(input.ownerId, scope, input.path) as Record<string, unknown> | undefined;\n\n if (existing) {\n const newVersion = (existing.version as number) + 1;\n const newHash = hashContent(input.content);\n const encryptedContent = this.crypto.encrypt(input.content);\n\n // Wrap version insert + file update in a transaction to prevent\n // phantom version records on crash (C3 review fix).\n const updateTx = this.db.transaction(() => {\n // Save old version — keep whatever envelope it was stored as\n // (plaintext or ciphertext). Lazy migration means we don't force\n // re-encrypt of history; old rows stay in their original form.\n this.db.prepare(`\n INSERT INTO memory_file_versions (id, fileId, version, content, createdAt)\n VALUES (?, ?, ?, ?, ?)\n `).run(\n crypto.randomUUID(),\n existing.id as string,\n existing.version as number,\n existing.content as string,\n timestamp,\n );\n\n // Update existing file with (possibly encrypted) new content\n this.db.prepare(`\n UPDATE memory_files\n SET content = ?, version = ?, memoryType = ?, description = ?,\n contentHash = ?, updatedAt = ?, stale = 0\n WHERE id = ?\n `).run(\n encryptedContent,\n newVersion,\n input.memoryType ?? null,\n input.description ?? null,\n newHash,\n timestamp,\n existing.id as string,\n );\n });\n updateTx();\n\n return {\n id: existing.id as string,\n ownerId: existing.ownerId as string,\n ownerType: existing.ownerType as 'user' | 'agent',\n scope: existing.scope as string,\n path: existing.path as string,\n content: input.content,\n version: newVersion,\n memoryType: input.memoryType,\n description: input.description,\n contentHash: newHash,\n createdAt: existing.createdAt as string,\n updatedAt: timestamp,\n stale: false,\n };\n }\n\n // Insert new file\n const id = crypto.randomUUID();\n const contentHash = hashContent(input.content);\n this.db.prepare(`\n INSERT INTO memory_files\n (id, ownerId, ownerType, scope, path, content, version, memoryType, description, contentHash, createdAt, updatedAt, stale)\n VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, 0)\n `).run(\n id,\n input.ownerId,\n input.ownerType,\n scope,\n input.path,\n this.crypto.encrypt(input.content),\n input.memoryType ?? null,\n input.description ?? null,\n contentHash,\n timestamp,\n timestamp,\n );\n\n return {\n id,\n ownerId: input.ownerId,\n ownerType: input.ownerType,\n scope,\n path: input.path,\n content: input.content,\n version: 1,\n memoryType: input.memoryType,\n description: input.description,\n contentHash,\n createdAt: timestamp,\n updatedAt: timestamp,\n stale: false,\n };\n }\n\n getMemoryFileById(id: string): MemoryFile | null {\n const row = this.db.prepare('SELECT * FROM memory_files WHERE id = ?').get(id) as Record<string, unknown> | undefined;\n return row ? rowToMemoryFile(row, this.crypto.decrypt) : null;\n }\n\n deleteMemoryFile(id: string): boolean {\n // Versions are deleted via ON DELETE CASCADE\n const result = this.db.prepare('DELETE FROM memory_files WHERE id = ?').run(id);\n return result.changes > 0;\n }\n\n listMemoryFiles(filters: MemoryFileFilters = {}): MemoryFile[] {\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n if (filters.ownerId) {\n conditions.push('ownerId = ?');\n params.push(filters.ownerId);\n }\n if (filters.scope) {\n conditions.push('scope = ?');\n params.push(filters.scope);\n }\n if (filters.path) {\n conditions.push('path = ?');\n params.push(filters.path);\n }\n if (filters.memoryType) {\n conditions.push('memoryType = ?');\n params.push(filters.memoryType);\n }\n if (filters.stale !== undefined) {\n conditions.push('stale = ?');\n params.push(filters.stale ? 1 : 0);\n }\n\n const where = conditions.length > 0 ? 'WHERE ' + conditions.join(' AND ') : '';\n const limit = filters.limit ?? 50;\n const offset = filters.offset ?? 0;\n\n const sql = `SELECT * FROM memory_files ${where} ORDER BY updatedAt DESC LIMIT ? OFFSET ?`;\n params.push(limit, offset);\n\n const rows = this.db.prepare(sql).all(...params) as Array<Record<string, unknown>>;\n return rows.map((r) => rowToMemoryFile(r, this.crypto.decrypt));\n }\n\n searchMemoryFiles(keyword: string, filters: MemoryFileFilters = {}): MemorySearchResult[] {\n const terms = keyword\n .toLowerCase()\n .split(/\\s+/)\n .map((term) => term.trim())\n .filter(Boolean);\n\n if (terms.length === 0) return [];\n\n // Build FTS5 match expression: each term quoted for safety\n const ftsQuery = terms.map((t) => '\"' + t.replace(/\"/g, '\"\"') + '\"').join(' ');\n\n const conditions: string[] = [];\n const params: unknown[] = [ftsQuery];\n\n if (filters.ownerId) {\n conditions.push('m.ownerId = ?');\n params.push(filters.ownerId);\n }\n if (filters.scope) {\n conditions.push('m.scope = ?');\n params.push(filters.scope);\n }\n if (filters.path) {\n conditions.push('m.path = ?');\n params.push(filters.path);\n }\n if (filters.memoryType) {\n conditions.push('m.memoryType = ?');\n params.push(filters.memoryType);\n }\n if (filters.stale !== undefined) {\n conditions.push('m.stale = ?');\n params.push(filters.stale ? 1 : 0);\n }\n\n const extraWhere = conditions.length > 0 ? 'AND ' + conditions.join(' AND ') : '';\n const limit = filters.limit ?? 10;\n params.push(limit);\n\n const sql = `\n SELECT m.*, bm25(memory_fts, 5.0, 3.0, 1.0) AS rank,\n snippet(memory_fts, 2, '', '', '...', 30) AS fts_snippet\n FROM memory_fts f\n JOIN memory_files m ON f.rowid = m.rowid\n WHERE memory_fts MATCH ?\n ${extraWhere}\n ORDER BY rank\n LIMIT ?\n `;\n\n const rows = this.db.prepare(sql).all(...params) as Array<Record<string, unknown>>;\n\n return rows.map((row) => {\n const file = rowToMemoryFile(row, this.crypto.decrypt);\n // bm25 returns negative values; more negative = more relevant.\n // Normalize to 0-1 range where 1 = most relevant.\n const rawRank = row.rank as number;\n const relevance = Math.min(1, Math.max(0, -rawRank / 10));\n return {\n ...file,\n relevance: relevance || 0.1, // floor at 0.1 so matched results always have > 0\n snippet: (row.fts_snippet as string) || undefined,\n };\n });\n }\n\n getStats(ownerId?: string): MemoryStats {\n if (ownerId) {\n const row = this.db.prepare(`\n SELECT COUNT(*) AS cnt,\n COALESCE(SUM(LENGTH(content)), 0) AS totalBytes,\n COALESCE(SUM(CASE WHEN stale = 1 THEN 1 ELSE 0 END), 0) AS staleCount\n FROM memory_files\n WHERE ownerId = ?\n `).get(ownerId) as { cnt: number; totalBytes: number; staleCount: number };\n\n const ftsCount = (this.db.prepare(\n 'SELECT COUNT(*) AS cnt FROM memory_fts f JOIN memory_files m ON f.rowid = m.rowid WHERE m.ownerId = ?',\n ).get(ownerId) as { cnt: number }).cnt;\n\n return {\n fileCount: row.cnt,\n totalSize: row.totalBytes,\n totalBytes: row.totalBytes,\n staleFiles: row.staleCount,\n ftsIndexed: ftsCount,\n recallP95: 0,\n };\n }\n\n const row = this.db.prepare(`\n SELECT COUNT(*) AS cnt,\n COALESCE(SUM(LENGTH(content)), 0) AS totalBytes,\n COALESCE(SUM(CASE WHEN stale = 1 THEN 1 ELSE 0 END), 0) AS staleCount\n FROM memory_files\n `).get() as { cnt: number; totalBytes: number; staleCount: number };\n\n const ftsCount = (this.db.prepare('SELECT COUNT(*) AS cnt FROM memory_fts').get() as { cnt: number }).cnt;\n\n return {\n fileCount: row.cnt,\n totalSize: row.totalBytes,\n totalBytes: row.totalBytes,\n staleFiles: row.staleCount,\n ftsIndexed: ftsCount,\n recallP95: 0,\n };\n }\n\n close(): void {\n this.db.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Singleton management\n// ---------------------------------------------------------------------------\n\nlet memoryDbInstance: MemoryDB | null = null;\n\nexport function getMemoryDB(): MemoryDB {\n if (memoryDbInstance === null) {\n memoryDbInstance = new MemoryDB();\n }\n return memoryDbInstance;\n}\n\nexport function closeMemoryDB(): void {\n if (memoryDbInstance !== null) {\n memoryDbInstance.close();\n memoryDbInstance = null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Encryption helpers (unchanged)\n// ---------------------------------------------------------------------------\n\nexport function generateSalt(): Buffer {\n return crypto.randomBytes(16);\n}\n\nexport function deriveKey(password: string, salt: Buffer): Buffer {\n return crypto.pbkdf2Sync(password, salt, 100_000, 32, 'sha256');\n}\n\nexport function encrypt(plaintext: string, key: Buffer): string {\n const iv = crypto.randomBytes(12);\n const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);\n const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const tag = cipher.getAuthTag();\n return Buffer.concat([iv, tag, ciphertext]).toString('base64');\n}\n\nexport function decrypt(encoded: string, key: Buffer): string {\n const packed = Buffer.from(encoded, 'base64');\n const iv = packed.subarray(0, 12);\n const tag = packed.subarray(12, 28);\n const ciphertext = packed.subarray(28);\n const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(tag);\n return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString('utf8');\n}\n","// Memory DB content encryption (opt-in, v1.9.0 soft goal → v2.0 mandatory)\n//\n// Enables AES-256-GCM encryption of the `content` column in memory_files.\n// Rest of the schema (path, description, hashes) stays plaintext so that\n// FTS indexing on path+description still works.\n//\n// Activation (opt-in):\n// PRISMER_DB_ENCRYPTION=1 — turn on encryption for new writes\n// PRISMER_DB_KEY=<base64:32B> — 32-byte raw key, or\n// PRISMER_DB_KEY_FILE=<path> — read key from file (must be 32 bytes after base64-decode)\n//\n// Ciphertext envelope (base64 fields, colon-delimited):\n// ENC:v1:<nonce_b64>:<authTag_b64>:<ciphertext_b64>\n//\n// Decryption is keyed by the envelope version prefix. Plaintext rows are\n// returned as-is so that a DB with mixed plaintext+ciphertext (during lazy\n// migration) stays readable. New writes always encrypt when enabled.\n\nimport * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\n\nconst ENVELOPE_PREFIX = 'ENC:v1:';\nconst NONCE_LEN = 12; // GCM recommended\nconst AUTHTAG_LEN = 16;\n\nexport interface ContentCrypto {\n enabled: boolean;\n encrypt: (plaintext: string) => string;\n decrypt: (value: string) => string;\n}\n\nfunction isEncrypted(value: string): boolean {\n return typeof value === 'string' && value.startsWith(ENVELOPE_PREFIX);\n}\n\nfunction loadKey(): Buffer | null {\n const raw = process.env['PRISMER_DB_KEY'];\n if (raw) {\n const buf = Buffer.from(raw, 'base64');\n if (buf.length !== 32) {\n throw new Error(`PRISMER_DB_KEY must decode to 32 bytes, got ${buf.length}`);\n }\n return buf;\n }\n const keyFile = process.env['PRISMER_DB_KEY_FILE'];\n if (keyFile) {\n const contents = fs.readFileSync(keyFile, 'utf-8').trim();\n const buf = Buffer.from(contents, 'base64');\n if (buf.length !== 32) {\n throw new Error(`PRISMER_DB_KEY_FILE must decode to 32 bytes, got ${buf.length}`);\n }\n return buf;\n }\n return null;\n}\n\nexport function createContentCrypto(): ContentCrypto {\n const flag = process.env['PRISMER_DB_ENCRYPTION'] === '1';\n if (!flag) {\n return {\n enabled: false,\n encrypt: (s) => s,\n decrypt: (s) => s,\n };\n }\n\n const key = loadKey();\n if (!key) {\n // Opt-in set but no key — fail loud rather than silently write plaintext.\n throw new Error(\n 'PRISMER_DB_ENCRYPTION=1 requires PRISMER_DB_KEY or PRISMER_DB_KEY_FILE ' +\n '(32-byte key, base64-encoded). See sdk/prismer-cloud/runtime/src/memory-db-crypto.ts',\n );\n }\n\n const encrypt = (plaintext: string): string => {\n if (typeof plaintext !== 'string') return plaintext;\n if (isEncrypted(plaintext)) return plaintext; // idempotent\n const nonce = crypto.randomBytes(NONCE_LEN);\n const cipher = crypto.createCipheriv('aes-256-gcm', key, nonce);\n const ct = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const authTag = cipher.getAuthTag();\n return [\n ENVELOPE_PREFIX.slice(0, -1), // \"ENC:v1\"\n nonce.toString('base64'),\n authTag.toString('base64'),\n ct.toString('base64'),\n ].join(':');\n };\n\n const decrypt = (value: string): string => {\n if (typeof value !== 'string') return value;\n if (!isEncrypted(value)) return value; // plaintext pass-through\n const parts = value.split(':');\n if (parts.length !== 5) {\n throw new Error('Malformed encrypted envelope (expected 5 fields)');\n }\n const [, , nonceB64, authTagB64, ctB64] = parts;\n const nonce = Buffer.from(nonceB64, 'base64');\n const authTag = Buffer.from(authTagB64, 'base64');\n const ct = Buffer.from(ctB64, 'base64');\n if (nonce.length !== NONCE_LEN || authTag.length !== AUTHTAG_LEN) {\n throw new Error('Malformed encrypted envelope (bad nonce/tag length)');\n }\n const decipher = crypto.createDecipheriv('aes-256-gcm', key, nonce);\n decipher.setAuthTag(authTag);\n const pt = Buffer.concat([decipher.update(ct), decipher.final()]);\n return pt.toString('utf8');\n };\n\n return { enabled: true, encrypt, decrypt };\n}\n\n/** Generate a fresh 32-byte key, base64-encoded, for documentation / key-rotation flows. */\nexport function generateKey(): string {\n return crypto.randomBytes(32).toString('base64');\n}\n","/**\n * Prismer Runtime — PARA Events Tailer\n *\n * Polls ~/.prismer/para/events.jsonl and uploads new lines to the cloud\n * ingest endpoint POST /api/im/para/events.\n *\n * Features:\n * - Atomic offset persistence (tmp + rename) — survives daemon crashes\n * - Rotation handling: if file shrinks below offset, reads events.jsonl.1\n * from old offset, then resets to 0 on the current file\n * - Exponential back-off on 5xx / network errors (5s→10s→20s→60s max)\n * - 4xx responses advance offset (bad data is skipped to avoid infinite loop)\n * - Batch size cap (maxBatchSize, default 100)\n *\n * @see docs/version190/v190-docker-closure-design.md §T3 daemon side\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\n// ─── Types ─────────────────────────────────────────────────────────────────\n\nexport interface EventsTailerOptions {\n /** Path to the JSONL events file (default ~/.prismer/para/events.jsonl) */\n eventsFilePath?: string;\n /** Path to the offset sidecar file (default ~/.prismer/para/tailer-offset.json) */\n offsetFilePath?: string;\n /** Cloud API base URL (required, e.g. https://prismer.cloud) */\n cloudApiBase: string;\n /** Prismer API key (required, passed as Bearer token) */\n apiKey: string;\n /** Poll interval in ms (default 5000) */\n pollIntervalMs?: number;\n /** Maximum events per POST batch (default 100) */\n maxBatchSize?: number;\n /**\n * Injectable fetch implementation — defaults to global fetch.\n * Useful for testing without network.\n */\n fetchImpl?: typeof fetch;\n}\n\ninterface Offset {\n position: number;\n}\n\n// ─── EventsTailer ──────────────────────────────────────────────────────────\n\nexport class EventsTailer {\n private readonly eventsFilePath: string;\n private readonly offsetFilePath: string;\n private readonly cloudApiBase: string;\n private readonly apiKey: string;\n private readonly pollIntervalMs: number;\n private readonly maxBatchSize: number;\n private readonly fetchImpl: typeof fetch;\n\n private timer: ReturnType<typeof setTimeout> | null = null;\n private running = false;\n private currentBackoffMs = 0;\n private readonly backoffSteps = [5000, 10000, 20000, 60000];\n\n constructor(opts: EventsTailerOptions) {\n const paraDir = path.join(os.homedir(), '.prismer', 'para');\n this.eventsFilePath = opts.eventsFilePath ?? path.join(paraDir, 'events.jsonl');\n this.offsetFilePath = opts.offsetFilePath ?? path.join(paraDir, 'tailer-offset.json');\n this.cloudApiBase = opts.cloudApiBase.replace(/\\/$/, '');\n this.apiKey = opts.apiKey;\n this.pollIntervalMs = opts.pollIntervalMs ?? 5000;\n this.maxBatchSize = opts.maxBatchSize ?? 100;\n this.fetchImpl = opts.fetchImpl ?? fetch;\n }\n\n // ─── Public API ──────────────────────────────────────────────────────────\n\n start(): void {\n if (this.running) return;\n this.running = true;\n console.log('[EventsTailer] Starting — polling', this.eventsFilePath);\n this._scheduleNext(0);\n }\n\n stop(): void {\n this.running = false;\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n console.log('[EventsTailer] Stopped');\n }\n\n /** Force a single poll tick immediately (useful for tests). */\n async flush(): Promise<void> {\n if (this.timer !== null) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n await this._tick();\n }\n\n // ─── Internals ───────────────────────────────────────────────────────────\n\n private _scheduleNext(delayMs: number): void {\n if (!this.running) return;\n this.timer = setTimeout(async () => {\n await this._tick();\n const nextDelay = this.currentBackoffMs > 0 ? this.currentBackoffMs : this.pollIntervalMs;\n this._scheduleNext(nextDelay);\n }, delayMs);\n }\n\n private async _tick(): Promise<void> {\n try {\n let offset = this._loadOffset();\n\n // Rotation detection: if file is smaller than our offset, the file was rotated.\n // Read unread lines from events.jsonl.1 first, then reset to 0.\n const fileSize = this._fileSize(this.eventsFilePath);\n if (fileSize !== null && fileSize < offset) {\n console.log(`[EventsTailer] Rotation detected (size=${fileSize} < offset=${offset}), reading .1`);\n const rotated = this.eventsFilePath + '.1';\n const rotatedLines = this._readLinesFrom(rotated, offset);\n if (rotatedLines.lines.length > 0) {\n const rotatedOk = await this._uploadBatches(rotatedLines.lines);\n if (!rotatedOk) {\n // 5xx/network on rotated-batch upload — hold offset where it is so\n // we retry the .1 drain on the next tick. Do NOT reset to 0 here,\n // otherwise the .1 lines would be silently dropped.\n return;\n }\n }\n // Rotated drain succeeded (or was empty). Now safe to reset offset.\n offset = 0;\n this._persistOffset(0);\n }\n\n // Read new lines from current position\n const read = this._readLinesFrom(this.eventsFilePath, offset);\n if (read.lines.length === 0) return; // nothing new\n\n const success = await this._uploadBatches(read.lines);\n if (success) {\n this._persistOffset(read.newPosition);\n this.currentBackoffMs = 0; // reset back-off on success\n }\n // On failure (5xx/network): _uploadBatches returned false and already\n // set the backoff. Offset is NOT persisted, so we retry these same\n // bytes on the next tick. On 4xx: _postBatch returned true (skip-bad),\n // so success=true and offset advances normally.\n } catch (err) {\n console.error('[EventsTailer] Tick error:', (err as Error).message);\n }\n }\n\n /**\n * Upload lines in batches.\n * Returns true if all batches succeeded (2xx or 4xx).\n * Returns false if a 5xx or network error occurred (offset should not advance).\n */\n private async _uploadBatches(lines: string[]): Promise<boolean> {\n for (let i = 0; i < lines.length; i += this.maxBatchSize) {\n const batch = lines.slice(i, i + this.maxBatchSize);\n const events = this._parseLines(batch);\n\n const ok = await this._postBatch(events);\n if (!ok) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * POST a batch to the cloud. Returns true on 2xx or 4xx (advance offset).\n * Returns false on 5xx or network error (hold offset, back off).\n */\n private async _postBatch(events: unknown[]): Promise<boolean> {\n const url = `${this.cloudApiBase}/api/im/para/events`;\n try {\n const res = await this.fetchImpl(url, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ events }),\n });\n\n if (res.status >= 200 && res.status < 300) {\n return true; // success\n }\n\n if (res.status >= 400 && res.status < 500) {\n // Client error — log and advance offset to avoid infinite loop\n const body = await res.text().catch(() => '');\n console.error(`[EventsTailer] 4xx from cloud (${res.status}), skipping batch: ${body.slice(0, 200)}`);\n return true; // treat as \"advance offset\"\n }\n\n // 5xx or unexpected — back off\n console.error(`[EventsTailer] Server error ${res.status}, backing off`);\n this._increaseBackoff();\n return false;\n } catch (err) {\n console.error(`[EventsTailer] Network error: ${(err as Error).message}, backing off`);\n this._increaseBackoff();\n return false;\n }\n }\n\n // ─── File helpers ─────────────────────────────────────────────────────────\n\n private _fileSize(filePath: string): number | null {\n try {\n return fs.statSync(filePath).size;\n } catch {\n return null;\n }\n }\n\n private _readLinesFrom(\n filePath: string,\n offset: number,\n ): { lines: string[]; newPosition: number } {\n try {\n const size = this._fileSize(filePath);\n if (size === null || size <= offset) return { lines: [], newPosition: offset };\n\n // Read only the new bytes\n const bytesToRead = size - offset;\n const buf = Buffer.alloc(bytesToRead);\n const fd = fs.openSync(filePath, 'r');\n try {\n fs.readSync(fd, buf, 0, bytesToRead, offset);\n } finally {\n fs.closeSync(fd);\n }\n\n const chunk = buf.toString('utf-8');\n // Drop the last element of the split — it's either empty (chunk ended\n // with '\\n') or a partial line (not yet terminated). Either way we\n // only commit bytes up to the last newline via lastNewlineIdx below.\n const parts = chunk.split('\\n');\n const completeLines = parts.slice(0, -1);\n const lastNewlineIdx = chunk.lastIndexOf('\\n');\n const bytesConsumed = lastNewlineIdx >= 0 ? lastNewlineIdx + 1 : 0;\n const newPosition = offset + bytesConsumed;\n\n const nonEmpty = completeLines.filter((l) => l.trim().length > 0);\n return { lines: nonEmpty, newPosition };\n } catch (err) {\n console.warn(`[EventsTailer] Cannot read ${filePath}: ${(err as Error).message}`);\n return { lines: [], newPosition: offset };\n }\n }\n\n private _parseLines(lines: string[]): unknown[] {\n const events: unknown[] = [];\n for (const line of lines) {\n try {\n events.push(JSON.parse(line));\n } catch {\n console.warn(`[EventsTailer] Skipping malformed JSON line: ${line.slice(0, 80)}`);\n // Skip malformed lines but do NOT stop processing\n }\n }\n return events;\n }\n\n // ─── Offset persistence ──────────────────────────────────────────────────\n\n private _loadOffset(): number {\n try {\n const raw = fs.readFileSync(this.offsetFilePath, 'utf-8');\n const parsed = JSON.parse(raw) as Offset;\n return typeof parsed.position === 'number' ? parsed.position : 0;\n } catch {\n return 0;\n }\n }\n\n private _persistOffset(position: number): void {\n try {\n const dir = path.dirname(this.offsetFilePath);\n fs.mkdirSync(dir, { recursive: true });\n const tmp = this.offsetFilePath + '.tmp';\n fs.writeFileSync(tmp, JSON.stringify({ position }), { encoding: 'utf-8', mode: 0o600 });\n fs.renameSync(tmp, this.offsetFilePath);\n } catch (err) {\n console.error('[EventsTailer] Failed to persist offset:', (err as Error).message);\n }\n }\n\n // ─── Back-off ────────────────────────────────────────────────────────────\n\n private _increaseBackoff(): void {\n const idx = this.backoffSteps.indexOf(this.currentBackoffMs);\n if (idx < 0 || idx >= this.backoffSteps.length - 1) {\n this.currentBackoffMs = this.backoffSteps[this.backoffSteps.length - 1];\n } else {\n this.currentBackoffMs = this.backoffSteps[idx + 1];\n }\n }\n}\n","// T12 — CLI UI primitives per §15 cli-design spec\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n// picocolors is used in bin/prismer.ts; imported here for consistency\n// but we apply ANSI codes directly to honour the per-instance colorEnabled\n// flag rather than relying on picocolors' global TTY/NO_COLOR detection.\n// (The import keeps the dependency resolved for downstream bundlers.)\nimport _pc from 'picocolors';\nvoid _pc; // intentionally unused — we manage ANSI inline via this.ansi()\n\n// ============================================================\n// Types\n// ============================================================\n\nexport type OutputMode = 'pretty' | 'json' | 'quiet';\n\nexport interface UIOptions {\n mode?: OutputMode;\n color?: boolean;\n stream?: NodeJS.WritableStream;\n errStream?: NodeJS.WritableStream;\n}\n\nexport interface TableRow {\n [column: string]: string;\n}\n\nexport interface TableOptions {\n columns: string[];\n maxWidth?: number;\n}\n\nexport interface LegacyTableOptions {\n columns: string[];\n rows: TableRow[];\n maxWidth?: number;\n}\n\n// ============================================================\n// Brand voice guard — re-export from shared module so SDK-side callers\n// can import it without dragging in the full UI class.\n// ============================================================\n\nexport { assertBrandVoice } from '../shared/brand-voice.js';\n\n// ============================================================\n// Spinner frames\n// ============================================================\n\nconst BRAILLE_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\nconst COMPACT_BANNER = [\n '◇ PRISMER',\n ' Runtime CLI',\n];\n\nfunction findIconPath(size: 'big' | 'small' = 'big'): string | null {\n const name = size === 'big' ? 'icon' : 'smallicon';\n const candidates = [\n path.resolve(__dirname, `../${name}`), // dist/bin/prismer.js -> dist/<name>\n path.resolve(__dirname, `../../${name}`), // dist/index.js -> dist/<name>\n path.resolve(__dirname, `../../../${name}`), // src/cli/ui.ts -> sdk/prismer-cloud/<name>\n path.resolve(process.cwd(), `../${name}`),\n ];\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) return candidate;\n }\n return null;\n}\n\n// Back-compat alias — kept so existing callers / tests don't break.\nfunction findBrandIconPath(): string | null {\n return findIconPath('big');\n}\n\n// ============================================================\n// UI class\n// ============================================================\n\nexport class UI {\n readonly mode: OutputMode;\n readonly colorEnabled: boolean;\n private readonly stream: NodeJS.WritableStream;\n private readonly errStream: NodeJS.WritableStream;\n\n constructor(opts?: UIOptions) {\n this.mode = opts?.mode ?? 'pretty';\n this.stream = opts?.stream ?? process.stdout;\n this.errStream = opts?.errStream ?? process.stderr;\n\n if (opts?.color !== undefined) {\n this.colorEnabled = opts.color;\n } else {\n const isTTY = (this.stream as NodeJS.WriteStream).isTTY === true;\n const noColor = Boolean(process.env['NO_COLOR']);\n this.colorEnabled = isTTY && !noColor;\n }\n }\n\n // ---- Internal color helpers ----\n // We apply ANSI codes directly rather than through picocolors' global\n // TTY/NO_COLOR detection, so that injected streams (e.g. test collectors)\n // are honoured correctly.\n\n private ansi(open: number, close: number, text: string): string {\n if (!this.colorEnabled) return text;\n return `\\u001b[${open}m${text}\\u001b[${close}m`;\n }\n\n private green(t: string): string { return this.ansi(32, 39, t); }\n private red(t: string): string { return this.ansi(31, 39, t); }\n private yellow(t: string): string { return this.ansi(33, 39, t); }\n private cyan(t: string): string { return this.ansi(36, 39, t); }\n private dim(t: string): string { return this.ansi(2, 22, t); }\n private bold(t: string): string { return this.ansi(1, 22, t); }\n private gray(t: string): string { return this.ansi(90, 39, t); }\n private brandMark(): string { return this.cyan('◇'); }\n\n private colorBrandLine(line: string): string {\n let out = '';\n for (const ch of line) {\n if (ch === '▒') {\n out += this.cyan(ch);\n } else if (ch === '▓') {\n out += this.dim(ch);\n } else {\n out += ch;\n }\n }\n return out;\n }\n\n // ---- Core write helpers ----\n\n write(text: string): void {\n this.stream.write(text);\n }\n\n writeErr(text: string): void {\n this.errStream.write(text);\n }\n\n // ---- Level 1: Header ----\n\n header(text: string): void {\n if (this.mode === 'json') return;\n const prefix = text.startsWith('Prismer') ? this.brandMark() + ' ' : '';\n this.write(prefix + this.bold(text) + '\\n');\n }\n\n // Small-icon header — used by day-to-day commands (`prismer agent list`,\n // `prismer status`, etc). Renders the 5-line product icon in dim cyan then a\n // subtitle line. Falls back silently to a single `◇ Prismer | <subtitle>`\n // line when the asset cannot be resolved so non-dev installs still read.\n smallHeader(subtitle?: string): void {\n // `--quiet` and `--json` both suppress decorative preamble. Per-command\n // result output still prints in quiet mode; only banners/headers go away.\n if (this.mode === 'json' || this.mode === 'quiet') return;\n const iconPath = findIconPath('small');\n if (iconPath !== null) {\n try {\n const raw = fs.readFileSync(iconPath, 'utf-8').replace(/\\n+$/, '');\n for (const line of raw.split('\\n')) {\n this.write(this.cyan(line) + '\\n');\n }\n } catch {\n this.write(this.brandMark() + ' ' + this.bold('Prismer') + '\\n');\n }\n } else {\n this.write(this.brandMark() + ' ' + this.bold('Prismer') + '\\n');\n }\n if (subtitle !== undefined && subtitle.length > 0) {\n this.write(this.dim(' ' + subtitle) + '\\n');\n }\n this.blank();\n }\n\n banner(subtitle?: string, opts?: { full?: boolean }): void {\n // Decorative intro banner — suppress in both json and quiet modes so\n // `prismer --quiet status` doesn't print \"◇ PRISMER / Runtime CLI\" before\n // the actual output.\n if (this.mode === 'json' || this.mode === 'quiet') return;\n\n const envColumns = process.env['COLUMNS'] !== undefined\n ? parseInt(process.env['COLUMNS'], 10)\n : NaN;\n const width = (this.stream as NodeJS.WriteStream).columns ??\n process.stdout.columns ??\n (Number.isFinite(envColumns) ? envColumns : 80);\n const iconPath = findIconPath('big');\n const shouldUseFull = opts?.full === true || width >= 120;\n\n if (shouldUseFull && iconPath !== null) {\n const raw = fs.readFileSync(iconPath, 'utf-8');\n const lines = raw.split('\\n');\n for (const line of lines) {\n const brandedLine = line.replace('Prismer Cloud SDK', 'Prismer Runtime CLI');\n const stripped = brandedLine.trimEnd();\n if (stripped.length === 0) {\n this.write('\\n');\n continue;\n }\n const clipped = stripped.length >= width ? stripped.slice(0, Math.max(width - 1, 1)) : stripped;\n this.write(this.colorBrandLine(clipped) + '\\n');\n }\n } else {\n this.write(this.cyan(COMPACT_BANNER[0]) + '\\n');\n this.write(this.dim(COMPACT_BANNER[1]) + '\\n');\n }\n\n if (subtitle !== undefined && subtitle.length > 0) {\n this.write(this.dim(' ' + subtitle) + '\\n');\n }\n this.blank();\n }\n\n // ---- Level 2: Primary data ----\n\n blank(): void {\n if (this.mode === 'json') return;\n this.write('\\n');\n }\n\n line(text: string): void {\n if (this.mode === 'json') return;\n this.write(text + '\\n');\n }\n\n info(text: string): void {\n this.line(text);\n }\n\n // ---- Level 3: Secondary ----\n\n secondary(text: string, indent = 2): void {\n if (this.mode === 'json') return;\n this.write(' '.repeat(indent) + this.dim(text) + '\\n');\n }\n\n // ---- Level 4: Action tips ----\n\n tip(text: string): void {\n if (this.mode === 'json') return;\n this.write(this.cyan('Tip:') + ' ' + text + '\\n');\n }\n\n next(text: string): void {\n if (this.mode === 'json') return;\n this.write(this.cyan('Next:') + ' ' + text + '\\n');\n }\n\n // ---- Level 5: Status indicators ----\n\n ok(text: string, detail?: string): void {\n if (this.mode === 'json') return;\n const suffix = detail ? ' ' + this.dim(detail) : '';\n this.write(' ' + this.green('✓') + ' ' + text + suffix + '\\n');\n }\n\n success(text: string, detail?: string): void {\n this.ok(text, detail);\n }\n\n fail(text: string, detail?: string): void {\n if (this.mode === 'json') return;\n const suffix = detail ? ' ' + this.dim(detail) : '';\n this.write(' ' + this.red('✗') + ' ' + text + suffix + '\\n');\n }\n\n online(text: string): void {\n if (this.mode === 'json') return;\n this.write(' ' + this.green('●') + ' ' + text + '\\n');\n }\n\n offline(text: string): void {\n if (this.mode === 'json') return;\n this.write(' ' + this.gray('○') + ' ' + text + '\\n');\n }\n\n notInstalled(text: string): void {\n if (this.mode === 'json') return;\n this.write(' ' + this.dim('·') + ' ' + this.dim(text) + '\\n');\n }\n\n pending(text: string): void {\n if (this.mode === 'json') return;\n this.write(' ' + this.yellow('⟳') + ' ' + text + '\\n');\n }\n\n warn(text: string, detail?: string): void {\n if (this.mode === 'json') return;\n const suffix = detail ? ' ' + this.dim(detail) : '';\n this.write(' ' + this.yellow('!') + ' ' + text + suffix + '\\n');\n }\n\n // ---- Level 6: Error block ----\n\n // JSON mode callers MUST emit error output via ui.json({ ok: false, ... });\n // this method is pretty-mode only. Keeping it silent in JSON mode prevents\n // stderr pollution for machine callers who chose --json for parseable stdout.\n error(what: string, cause?: string, fix?: string): void {\n if (this.mode === 'json') return;\n this.writeErr(this.red('✗') + ' ' + what + '\\n');\n if (cause !== undefined) {\n this.writeErr(' ' + this.dim('Cause:') + ' ' + this.dim(cause) + '\\n');\n }\n if (fix !== undefined) {\n this.writeErr(' ' + this.cyan('Fix:') + ' ' + fix + '\\n');\n }\n }\n\n // ---- Tables ----\n\n table(rows: TableRow[], opts: TableOptions): void;\n table(opts: LegacyTableOptions): void;\n table(rowsOrOpts: TableRow[] | LegacyTableOptions, maybeOpts?: TableOptions): void {\n if (this.mode === 'json') return;\n const rows = Array.isArray(rowsOrOpts) ? rowsOrOpts : rowsOrOpts.rows;\n const opts = Array.isArray(rowsOrOpts)\n ? maybeOpts\n : {\n columns: rowsOrOpts.columns,\n maxWidth: rowsOrOpts.maxWidth,\n };\n\n if (!opts) {\n throw new Error('table() requires columns');\n }\n\n const maxWidth = opts.maxWidth ?? (process.stdout.columns || 80);\n const cols = opts.columns;\n\n // Compute column widths\n const widths: number[] = cols.map((col) => col.length);\n for (const row of rows) {\n cols.forEach((col, i) => {\n const val = row[col] ?? '';\n if (val.length > widths[i]) widths[i] = val.length;\n });\n }\n\n const totalWidth = widths.reduce((a, b) => a + b, 0) + (cols.length - 1) * 2 + 2;\n\n if (totalWidth > maxWidth) {\n // List mode\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n for (const col of cols) {\n const val = row[col] ?? '';\n this.write(' ' + this.bold(col + ':') + ' ' + val + '\\n');\n }\n if (i < rows.length - 1) this.write('\\n');\n }\n return;\n }\n\n // Table mode — header row\n const header = cols.map((col, i) => col.toUpperCase().padEnd(widths[i])).join(' ');\n this.write(' ' + this.dim(header) + '\\n');\n\n // Data rows\n for (const row of rows) {\n const line = cols.map((col, i) => (row[col] ?? '').padEnd(widths[i])).join(' ');\n this.write(' ' + line + '\\n');\n }\n }\n\n // ---- Spinner ----\n\n spinner(text: string): { update(t: string): void; stop(final?: string): void } {\n if (this.mode === 'quiet' || this.mode === 'json') {\n return {\n update(): void { /* no-op */ },\n stop(): void { /* no-op */ },\n };\n }\n\n const isTTY = (this.stream as NodeJS.WriteStream).isTTY === true;\n\n if (!isTTY || !this.colorEnabled) {\n // Non-TTY: single start line, single stop line\n this.write(' ' + this.yellow('⟳') + ' ' + text + '\\n');\n return {\n update: (t: string) => {\n this.write(' ' + this.yellow('⟳') + ' ' + t + '\\n');\n },\n stop: (final?: string) => {\n if (final) this.write(' ' + this.green('✓') + ' ' + final + '\\n');\n },\n };\n }\n\n // Animated braille spinner\n let current = text;\n let frameIdx = 0;\n let stopped = false;\n\n const write = this.write.bind(this);\n const colorFn = this.yellow.bind(this);\n const greenFn = this.green.bind(this);\n\n function renderFrame(): void {\n const frame = BRAILLE_FRAMES[frameIdx % BRAILLE_FRAMES.length];\n const line = ' ' + colorFn(frame) + ' ' + current;\n // Move cursor to start of line and overwrite\n write('\\r' + line);\n frameIdx++;\n }\n\n renderFrame();\n const timer = setInterval(renderFrame, 80);\n\n return {\n update(t: string): void {\n if (stopped) return;\n current = t;\n },\n stop(final?: string): void {\n if (stopped) return;\n stopped = true;\n clearInterval(timer);\n // Clear current line\n write('\\r\\x1b[2K');\n if (final) write(' ' + greenFn('✓') + ' ' + final + '\\n');\n },\n };\n }\n\n // ---- Progress bar (§15.4 long-running ops) ----\n //\n // Usage:\n // const bar = ui.progress('Downloading pack', total);\n // bar.update(1.3 * 1024 * 1024, '1.3MB/2.1MB');\n // bar.stop('Downloaded and verified');\n //\n // Non-TTY / quiet / json / no-color → degrades to a single-line summary and\n // a final line on stop(). Uses `▓`/`░` (aligns with banner characters).\n progress(\n text: string,\n total: number,\n ): { update(current: number, detail?: string): void; stop(final?: string): void } {\n if (this.mode === 'quiet' || this.mode === 'json') {\n return {\n update(): void {\n /* no-op */\n },\n stop(): void {\n /* no-op */\n },\n };\n }\n\n const isTTY = (this.stream as NodeJS.WriteStream).isTTY === true;\n const start = Date.now();\n const write = this.write.bind(this);\n const colorFn = this.cyan.bind(this);\n const dimFn = this.dim.bind(this);\n const greenFn = this.green.bind(this);\n\n let last = 0;\n let lastDetail = '';\n let stopped = false;\n\n const render = (): void => {\n if (stopped) return;\n const frac = total > 0 ? Math.min(1, Math.max(0, last / total)) : 0;\n const pct = Math.floor(frac * 100);\n const width = 20;\n const filled = Math.floor(frac * width);\n const bar = '█'.repeat(filled) + '░'.repeat(width - filled);\n const elapsed = (Date.now() - start) / 1000;\n const eta = frac > 0.01 ? Math.max(0, elapsed / frac - elapsed) : 0;\n const etaStr = frac >= 1 ? '' : ` · ${eta < 1 ? '<1s' : Math.round(eta) + 's'} left`;\n const detailStr = lastDetail ? ` · ${lastDetail}` : '';\n const line = ` ${text} [${colorFn(bar)}] ${String(pct).padStart(3)}%${detailStr}${dimFn(etaStr)}`;\n if (isTTY && this.colorEnabled) {\n write('\\r\\x1b[2K' + line);\n } else {\n write(line + '\\n');\n }\n };\n\n render();\n\n return {\n update: (current: number, detail?: string): void => {\n if (stopped) return;\n last = current;\n if (detail !== undefined) lastDetail = detail;\n render();\n },\n stop: (final?: string): void => {\n if (stopped) return;\n stopped = true;\n if (isTTY && this.colorEnabled) write('\\r\\x1b[2K');\n if (final) write(' ' + greenFn('✓') + ' ' + final + '\\n');\n },\n };\n }\n\n // ---- JSON output ----\n\n json(payload: unknown, opts?: { pretty?: boolean }): void {\n const indent = opts?.pretty ? 2 : undefined;\n this.write(JSON.stringify(payload, null, indent) + '\\n');\n }\n\n // ---- Result convenience ----\n\n result<T>(pretty: () => void, jsonPayload: T): void {\n if (this.mode === 'pretty') {\n pretty();\n } else {\n this.json(jsonPayload);\n }\n }\n}\n\n// ============================================================\n// Singleton\n// ============================================================\n\nlet _ui: UI | null = null;\n\nexport function getUI(): UI {\n if (!_ui) {\n _ui = new UI();\n }\n return _ui;\n}\n\nexport function setUI(ui: UI): void {\n _ui = ui;\n}\n\nexport function __resetUIForTests(): void {\n _ui = null;\n}\n\n// ============================================================\n// applyCommonFlags\n// ============================================================\n\nexport function applyCommonFlags(argv: string[]): {\n mode: OutputMode;\n color: boolean;\n restArgv: string[];\n} {\n let mode: OutputMode = 'pretty';\n // Default color based on TTY + NO_COLOR — but flags can override\n const isTTY = process.stdout.isTTY === true;\n const noColorEnv = Boolean(process.env['NO_COLOR']);\n let color = isTTY && !noColorEnv;\n\n const rest: string[] = [];\n\n for (const arg of argv) {\n switch (arg) {\n case '--no-color':\n color = false;\n break;\n case '--color':\n color = true;\n break;\n case '--json':\n mode = 'json';\n break;\n case '--pretty-json':\n // Kept as a flag — callers use it to set pretty:true on json() calls\n // We keep mode as 'json' but signal via the returned mode only; callers\n // can detect by checking whether 'pretty-json' was stripped.\n // For simplicity, treat it as json mode (caller sets pretty on construction).\n mode = 'json';\n break;\n case '--quiet':\n mode = 'quiet';\n break;\n default:\n rest.push(arg);\n }\n }\n\n return { mode, color, restArgv: rest };\n}\n","// Brand voice guard — extracted from cli/ui.ts so that installer (shell),\n// SDK library, and runtime CLI can all run the same check.\n//\n// Activated only when PRISMER_BRAND_VOICE_STRICT is set (test/CI contexts);\n// default production paths do not pay the regex cost.\n\nconst FORBIDDEN_SUBSTRINGS = ['Sorry', 'Unfortunately', 'Oops'];\nconst FORBIDDEN_WORDS = ['Please'];\n\nexport function assertBrandVoice(text: string, label = 'text'): void {\n if (!process.env['PRISMER_BRAND_VOICE_STRICT']) return;\n for (const sub of FORBIDDEN_SUBSTRINGS) {\n if (text.includes(sub)) {\n throw new Error(`[Brand Voice] Forbidden substring \"${sub}\" in CLI ${label}: ${text}`);\n }\n }\n for (const word of FORBIDDEN_WORDS) {\n const re = new RegExp(`\\\\b${word}\\\\b`);\n if (re.test(text)) {\n throw new Error(`[Brand Voice] Forbidden word \"${word}\" in CLI ${label}: ${text}`);\n }\n }\n const lines = text.split('\\n');\n for (const line of lines) {\n const stripped = line.replace(/\"[^\"]*\"/g, '').replace(/'[^']*'/g, '');\n if (stripped.trimEnd().endsWith('!')) {\n throw new Error(`[Brand Voice] Trailing \"!\" in CLI ${label}: ${line}`);\n }\n }\n}\n","// T12 — Shared CLI context: wires UI + Keychain for command handlers\n\nimport { UI, applyCommonFlags } from './ui.js';\nimport { Keychain } from '../keychain.js';\nimport { loadConfig, type PrismerConfig } from '../config.js';\n\nexport interface CliResolvedConfig extends PrismerConfig {\n apiToken?: string;\n cloudBaseUrl: string;\n agentId?: string;\n}\n\nexport interface CliContext {\n ui: UI;\n keychain: Keychain;\n cwd: string;\n argv: string[];\n}\n\nexport async function createCliContext(opts?: {\n argv?: string[];\n ui?: UI;\n}): Promise<CliContext> {\n const argv = opts?.argv ?? process.argv;\n\n let ui: UI;\n if (opts?.ui) {\n ui = opts.ui;\n } else {\n const { mode, color } = applyCommonFlags(argv);\n ui = new UI({ mode, color });\n }\n\n const keychain = new Keychain();\n\n return {\n ui,\n keychain,\n cwd: process.cwd(),\n argv,\n };\n}\n\nexport async function loadCliConfig(ctx: CliContext): Promise<CliResolvedConfig> {\n const config = await loadConfig({\n keychain: ctx.keychain,\n });\n\n return {\n ...config,\n apiToken: typeof config.apiKey === 'string' ? config.apiKey : undefined,\n cloudBaseUrl:\n typeof config.apiBase === 'string' && config.apiBase.length > 0\n ? config.apiBase\n : 'https://prismer.cloud/api',\n agentId:\n typeof config['agentId'] === 'string'\n ? (config['agentId'] as string)\n : typeof process.env['PRISMER_AGENT_ID'] === 'string'\n ? process.env['PRISMER_AGENT_ID']\n : undefined,\n };\n}\n","// T13 — Hook config management: merge, upgrade, rollback, idempotency.\n// Ported from scripts/PARA/exp-13-hooks-migration.ts (6 scenarios all pass).\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n// ============================================================\n// Types\n// ============================================================\n\nexport type HookFormat = 'v1.8' | 'v1.9';\n\nexport interface HookEntry {\n command?: string;\n webhook?: string;\n enabled?: boolean;\n [key: string]: unknown;\n}\n\nexport interface HookConfig {\n hooks: Record<string, HookEntry | HookEntry[]>;\n [key: string]: unknown;\n}\n\nexport interface MergeResult {\n merged: HookConfig;\n added: string[];\n preserved: string[];\n replaced: string[];\n backupPath?: string;\n}\n\nexport interface MergeOptions {\n daemonUrl: string;\n dryRun?: boolean;\n /** Absolute path to the installed claude-code-plugin root (contains hooks/para-emit.mjs). */\n pluginRoot?: string;\n}\n\n// ============================================================\n// EXP-13 constants (updated from exp-13 → PARA hooks.para.json)\n// ============================================================\n\n/** Marker present in all v1.8 Prismer-owned hook commands. */\nconst LEGACY_HOOK_MARKER = 'evolution-hook.js';\n\n/** Known legacy session-start script path (also Prismer-owned in v1.8). */\nconst LEGACY_SESSION_START_MARKER = 'session-start.mjs';\n\n/** Marker present in v1.9 PARA hooks (para-emit.mjs or para-adapter.js). */\nconst PARA_EMIT_MARKER = 'para-emit';\n\n/** Legacy marker — kept for backward compat detection of early v1.9 installs. */\nconst PARA_ADAPTER_MARKER = '/opt/prismer/runtime/para-adapter.js';\n\n/**\n * Full set of v1.9 PARA hook events to inject into Claude Code hooks.json.\n *\n * Uses the Claude Code nested format:\n * { matcher: \".*\", hooks: [{ type: \"command\", command: \"...\" }] }\n *\n * The command uses a template variable `{{PLUGIN_ROOT}}` which is replaced\n * by `installHooks()` with the resolved plugin root path.\n *\n * Event list sourced from hooks.para.json (25 events).\n */\nconst PARA_HOOK_EVENTS = [\n 'SessionStart',\n 'SessionEnd',\n 'UserPromptSubmit',\n 'PreToolUse',\n 'PostToolUse',\n 'PostToolUseFailure',\n 'PermissionRequest',\n 'PermissionDenied',\n 'SubagentStart',\n 'SubagentStop',\n 'TaskCreated',\n 'TaskCompleted',\n 'TeammateIdle',\n 'Stop',\n 'StopFailure',\n 'Notification',\n 'InstructionsLoaded',\n 'ConfigChange',\n 'CwdChanged',\n 'FileChanged',\n 'WorktreeCreate',\n 'WorktreeRemove',\n 'PreCompact',\n 'PostCompact',\n 'Elicitation',\n 'ElicitationResult',\n] as const;\n\n/**\n * Build the PARA_HOOKS record with a resolved plugin root path.\n *\n * Each event maps to a single HookEntry in Claude Code nested format:\n * { matcher: \".*\", hooks: [{ type: \"command\", command: \"node \\\"<root>/hooks/para-emit.mjs\\\" <Event>\" }] }\n */\nfunction buildParaHooks(pluginRoot: string): Record<string, HookEntry[]> {\n const hooks: Record<string, HookEntry[]> = {};\n for (const event of PARA_HOOK_EVENTS) {\n hooks[event] = [\n {\n matcher: '.*',\n hooks: [\n {\n type: 'command',\n command: `node \"${pluginRoot}/hooks/para-emit.mjs\" ${event}`,\n },\n ],\n } as unknown as HookEntry,\n ];\n }\n return hooks;\n}\n\n/**\n * Resolve the plugin root for @prismer/claude-code-plugin.\n *\n * Resolution order:\n * 1. PRISMER_PLUGIN_ROOT env var (explicit override)\n * 2. Sibling directory (runtime ships alongside claude-code-plugin under sdk/)\n * 3. Global npm prefix: $(npm prefix -g)/lib/node_modules/@prismer/claude-code-plugin\n * 4. Fallback: /opt/prismer/runtime (daemon install path)\n *\n * Callers can override with opts.pluginRoot in MergeOptions.\n */\nexport function resolvePluginRoot(): string {\n // 1. Env override\n if (process.env['PRISMER_PLUGIN_ROOT']) {\n return process.env['PRISMER_PLUGIN_ROOT'];\n }\n\n // 2. Relative to this package (runtime ships alongside claude-code-plugin under sdk/)\n // Compiled output: .../runtime/dist/agents/hooks.js → walk up to sdk/prismer-cloud/claude-code-plugin\n // Source: .../runtime/src/agents/hooks.ts → same relative walk\n const siblingPath = path.resolve(__dirname, '..', '..', '..', 'claude-code-plugin');\n if (fs.existsSync(path.join(siblingPath, 'hooks', 'para-emit.mjs'))) {\n return siblingPath;\n }\n\n // 3. Global npm install\n try {\n const { execFileSync } = require('node:child_process') as typeof import('node:child_process');\n const prefix = execFileSync('npm', ['prefix', '-g'], { encoding: 'utf-8' }).trim();\n const globalPath = path.join(prefix, 'lib', 'node_modules', '@prismer', 'claude-code-plugin');\n if (fs.existsSync(path.join(globalPath, 'hooks', 'para-emit.mjs'))) {\n return globalPath;\n }\n } catch {\n // npm not available or failed — continue\n }\n\n // 4. Fallback\n return '/opt/prismer/runtime';\n}\n\n// ============================================================\n// Classification helpers\n// ============================================================\n\n/**\n * Extract all command strings from an entry, handling both flat and nested CC formats.\n * Flat: { command: '...' }\n * Nested: { matcher: '...', hooks: [{ type: 'command', command: '...' }] }\n */\nfunction extractCommands(entry: HookEntry): string[] {\n const cmds: string[] = [];\n if (typeof entry.command === 'string') {\n cmds.push(entry.command);\n }\n if (typeof entry.webhook === 'string') {\n cmds.push(entry.webhook);\n }\n // CC nested format: entry.hooks is an array of sub-entries with their own command fields\n const nested = entry['hooks'];\n if (Array.isArray(nested)) {\n for (const sub of nested) {\n if (sub !== null && typeof sub === 'object') {\n const subCmd = (sub as { command?: unknown })['command'];\n if (typeof subCmd === 'string') {\n cmds.push(subCmd);\n }\n }\n }\n }\n return cmds;\n}\n\n/** Returns true if the HookEntry is a v1.8 Prismer-owned hook. */\nfunction isLegacyPrismerEntry(entry: HookEntry): boolean {\n const cmds = extractCommands(entry);\n return cmds.some(\n (c) => c.includes(LEGACY_HOOK_MARKER) || c.includes(LEGACY_SESSION_START_MARKER),\n );\n}\n\n/** Returns true if the HookEntry is a v1.9 PARA hook (para-emit.mjs or legacy para-adapter.js). */\nfunction isParaEntry(entry: HookEntry): boolean {\n const cmds = extractCommands(entry);\n return cmds.some((c) => c.includes(PARA_EMIT_MARKER) || c.includes(PARA_ADAPTER_MARKER));\n}\n\n// ============================================================\n// Normalisation helpers\n// ============================================================\n\n/**\n * Normalise a hook event value to an array of HookEntry.\n * The stored format is `HookEntry | HookEntry[]` — callers get the array form.\n */\nfunction toEntries(value: HookEntry | HookEntry[]): HookEntry[] {\n return Array.isArray(value) ? value : [value];\n}\n\n// ============================================================\n// mergeHooks — core idempotent merge function\n// ============================================================\n\nexport function mergeHooks(existing: HookConfig | null, opts: MergeOptions): MergeResult {\n // Resolve the plugin root for building PARA hook commands\n const pluginRoot = opts.pluginRoot ?? resolvePluginRoot();\n const paraHooks = buildParaHooks(pluginRoot);\n\n // We work in the flat HookEntry[] format internally.\n const existingHooks: Record<string, HookEntry[]> = {};\n\n if (existing?.hooks) {\n for (const [event, val] of Object.entries(existing.hooks)) {\n existingHooks[event] = toEntries(val as HookEntry | HookEntry[]);\n }\n }\n\n const added: string[] = [];\n const preserved: string[] = [];\n const replaced: string[] = [];\n\n const resultHooks: Record<string, HookEntry[]> = {};\n\n // Step 1: process existing entries\n for (const [event, entries] of Object.entries(existingHooks)) {\n resultHooks[event] = [];\n for (const entry of entries) {\n if (isLegacyPrismerEntry(entry)) {\n // Remove v1.8 Prismer hook — will be replaced by v1.9 PARA hook\n replaced.push(event);\n } else if (isParaEntry(entry)) {\n // Already a PARA hook — idempotency: keep it, don't re-add\n resultHooks[event].push(entry);\n } else {\n // User/third-party hook — preserve\n resultHooks[event].push(entry);\n preserved.push(event);\n }\n }\n }\n\n // Step 2: add PARA hooks (idempotent — skip if already present)\n for (const [event, paraEntries] of Object.entries(paraHooks)) {\n if (!resultHooks[event]) resultHooks[event] = [];\n const hasPara = resultHooks[event].some((e) => isParaEntry(e));\n if (!hasPara) {\n resultHooks[event].push(...paraEntries);\n added.push(event);\n }\n }\n\n // Step 3: clean up empty arrays\n for (const event of Object.keys(resultHooks)) {\n if (resultHooks[event].length === 0) {\n delete resultHooks[event];\n }\n }\n\n // Build the merged HookConfig, preserving any extra top-level keys\n const merged: HookConfig = {\n ...(existing ?? {}),\n hooks: resultHooks,\n };\n\n return { merged, added, preserved, replaced };\n}\n\n// ============================================================\n// readHookConfig\n// ============================================================\n\nexport async function readHookConfig(filePath: string): Promise<HookConfig | null> {\n if (!fs.existsSync(filePath)) return null;\n\n let raw: string;\n try {\n raw = fs.readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n\n try {\n const parsed = JSON.parse(raw) as unknown;\n if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {\n const obj = parsed as Record<string, unknown>;\n if (!obj['hooks'] || typeof obj['hooks'] !== 'object' || Array.isArray(obj['hooks'])) {\n // Missing or malformed hooks key — treat as empty\n return { hooks: {} };\n }\n return obj as unknown as HookConfig;\n }\n return { hooks: {} };\n } catch {\n // Malformed JSON — treat as empty\n return { hooks: {} };\n }\n}\n\n// ============================================================\n// writeHookConfig\n// ============================================================\n\nexport async function writeHookConfig(filePath: string, cfg: HookConfig): Promise<void> {\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(filePath, JSON.stringify(cfg, null, 2) + '\\n', 'utf-8');\n}\n\n// ============================================================\n// installHooks — write merged config + create backup\n// ============================================================\n\nexport async function installHooks(\n configPath: string,\n existing: HookConfig | null,\n opts: MergeOptions,\n): Promise<MergeResult> {\n const result = mergeHooks(existing, opts);\n\n if (opts.dryRun) {\n return result;\n }\n\n // Backup existing file with monotonic timestamp\n let backupPath: string | undefined;\n if (existing !== null && fs.existsSync(configPath)) {\n backupPath = `${configPath}.prismer-bak-${Date.now()}`;\n fs.copyFileSync(configPath, backupPath);\n result.backupPath = backupPath;\n }\n\n await writeHookConfig(configPath, result.merged);\n\n return result;\n}\n\n// ============================================================\n// rollbackHooks — restore from most recent backup\n// ============================================================\n\nexport async function rollbackHooks(\n configPath: string,\n): Promise<{ restored: boolean; fromBackup: string | null }> {\n const dir = path.dirname(configPath);\n const base = path.basename(configPath);\n\n let backupFiles: string[] = [];\n try {\n const entries = fs.readdirSync(dir);\n backupFiles = entries\n .filter((f) => f.startsWith(base + '.prismer-bak-'))\n .sort(); // lexicographic — monotonic timestamp makes this chronological\n } catch {\n return { restored: false, fromBackup: null };\n }\n\n if (backupFiles.length === 0) {\n return { restored: false, fromBackup: null };\n }\n\n // Most recent backup = last in sorted order\n const latestBackup = path.join(dir, backupFiles[backupFiles.length - 1]);\n\n try {\n fs.copyFileSync(latestBackup, configPath);\n fs.unlinkSync(latestBackup);\n return { restored: true, fromBackup: latestBackup };\n } catch {\n return { restored: false, fromBackup: latestBackup };\n }\n}\n","import { getMemoryDB, type DreamCompaction } from './memory-db.js';\n\nexport interface DreamResult {\n ok: boolean;\n compactedFiles: number;\n summary?: DreamCompaction;\n}\n\nexport interface DreamSchedulerOptions {\n ownerId?: string;\n scope?: string;\n intervalMs?: number;\n}\n\nexport class DreamScheduler {\n private timer: NodeJS.Timeout | null = null;\n\n constructor(private readonly opts: DreamSchedulerOptions = {}) {}\n\n start(): void {\n if (this.timer !== null) return;\n const intervalMs = this.opts.intervalMs ?? 24 * 60 * 60 * 1000;\n this.timer = setInterval(() => {\n void runDream(this.opts).catch(() => undefined);\n }, intervalMs);\n this.timer.unref();\n }\n\n stop(): void {\n if (this.timer === null) return;\n clearInterval(this.timer);\n this.timer = null;\n }\n}\n\nexport function createDreamScheduler(opts?: DreamSchedulerOptions): DreamScheduler {\n return new DreamScheduler(opts);\n}\n\nexport async function runDream(opts: DreamSchedulerOptions = {}): Promise<DreamResult> {\n const db = getMemoryDB();\n const files = db.listMemoryFiles({\n ownerId: opts.ownerId,\n scope: opts.scope,\n limit: 100,\n });\n\n return {\n ok: true,\n compactedFiles: files.length,\n };\n}\n","/**\n * Prismer Runtime — E2EE Key Storage (v1.9.0)\n *\n * Secure storage for E2EE keys on daemon side.\n * Uses keychain backend with encrypted JSON fallback for offline/keyless systems.\n *\n * Storage model:\n * - Primary: Keychain (macOS Keychain / libsecret / pass)\n * - Fallback: Encrypted JSON file (~/.prismer/e2ee-keys.json)\n * - Per-session keys with TTL (30 min default)\n * - Automatic cleanup of expired keys\n *\n * Security:\n * - Keys encrypted at rest (keychain or encrypted file)\n * - Master passphrase required for file fallback\n * - Automatic key rotation on session expiry\n * - Forward secrecy: ephemeral keys discarded after session\n */\n\nimport * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { Keychain } from './keychain';\nimport type { KeyPair } from './e2ee-crypto';\n\n// ============================================================\n// Types\n// ============================================================\n\nexport interface E2EEKeyEntry {\n /** Session ID (userId:daemonId or userId:deviceId) */\n sessionId: string;\n /** User ID who owns this key */\n userId: string;\n /** Daemon ID or Device ID */\n endpointId: string;\n /** Local keypair (ephemeral) */\n keyPair: {\n publicKey: string;\n privateKey: string;\n };\n /** Remote public key */\n remotePublicKey: string;\n /** When this key was created */\n createdAt: number;\n /** When this key expires (unix timestamp) */\n expiresAt: number;\n /** Current sequence number */\n seq: number;\n}\n\nexport interface E2EEStorageStats {\n totalKeys: number;\n activeKeys: number;\n expiredKeys: number;\n oldestKeyAge: number; // seconds\n newestKeyAge: number; // seconds\n}\n\n// ============================================================\n// Constants\n// ============================================================\n\nconst STORAGE_PATH = path.join(os.homedir(), '.prismer', 'e2ee-keys.json');\nconst STORAGE_SERVICE = 'prismer-e2ee';\nconst DEFAULT_TTL_SECONDS = 30 * 60; // 30 minutes\nconst KEY_ITERATIONS = 100000; // PBKDF2 iterations for encryption\n\n// ============================================================\n// E2EE Key Storage Class\n// ============================================================\n\nexport class E2EEKeyStorage {\n private keychain: Keychain;\n private useEncryptedFile: boolean = false;\n private masterPassphrase?: string;\n private cleanupInterval?: NodeJS.Timeout;\n\n constructor(options?: { masterPassphrase?: string }) {\n this.keychain = new Keychain({ masterPassphrase: options?.masterPassphrase });\n this.masterPassphrase = options?.masterPassphrase;\n }\n\n /**\n * Initialize storage (try keychain, fallback to encrypted file)\n */\n async initialize(): Promise<void> {\n try {\n // Try keychain first\n const backend = await this.keychain.backend();\n const available = await backend.available();\n if (available) {\n this.useEncryptedFile = false;\n return;\n }\n } catch (err) {\n // Keychain not available, fall back to encrypted file\n }\n\n // Fallback to encrypted file\n if (!this.masterPassphrase) {\n throw new Error(\n 'E2EE key storage: Keychain not available and no master passphrase provided. ' +\n 'Set PRISMER_MASTER_PASSPHRASE environment variable.'\n );\n }\n\n this.useEncryptedFile = true;\n await this.ensureStorageFile();\n\n // Start periodic cleanup (every 5 minutes)\n this.cleanupInterval = setInterval(() => {\n void this.cleanupExpiredKeys().catch((err) => {\n console.error('[E2EEKeyStorage] Cleanup failed:', err);\n });\n }, 5 * 60 * 1000);\n }\n\n /**\n * Store E2EE key for a session\n */\n async storeKey(entry: E2EEKeyEntry): Promise<void> {\n const now = Date.now();\n const expiresAt = now + DEFAULT_TTL_SECONDS * 1000;\n\n const keyEntry: E2EEKeyEntry = {\n ...entry,\n createdAt: now,\n expiresAt,\n };\n\n if (this.useEncryptedFile) {\n await this.storeInEncryptedFile(keyEntry);\n } else {\n await this.storeInKeychain(keyEntry);\n }\n }\n\n /**\n * Retrieve E2EE key for a session\n */\n async getKey(sessionId: string): Promise<E2EEKeyEntry | null> {\n let entry: E2EEKeyEntry | null;\n\n if (this.useEncryptedFile) {\n entry = await this.getFromEncryptedFile(sessionId);\n } else {\n entry = await this.getFromKeychain(sessionId);\n }\n\n if (!entry) return null;\n\n // Check if expired\n if (Date.now() > entry.expiresAt) {\n await this.removeKey(sessionId);\n return null;\n }\n\n return entry;\n }\n\n /**\n * Remove E2EE key for a session\n */\n async removeKey(sessionId: string): Promise<void> {\n if (this.useEncryptedFile) {\n await this.removeFromEncryptedFile(sessionId);\n } else {\n await this.removeFromKeychain(sessionId);\n }\n }\n\n /**\n * Get all keys for a user (for recovery)\n */\n async getAllKeysForUser(userId: string): Promise<E2EEKeyEntry[]> {\n if (this.useEncryptedFile) {\n return await this.getAllFromEncryptedFile(userId);\n } else {\n return await this.getAllFromKeychain(userId);\n }\n }\n\n /**\n * Get storage statistics\n */\n async getStats(userId?: string): Promise<E2EEStorageStats> {\n const now = Date.now();\n let keys: E2EEKeyEntry[];\n\n if (userId) {\n keys = await this.getAllKeysForUser(userId);\n } else {\n // Get all keys (for admin stats)\n if (this.useEncryptedFile) {\n const data = await this.readEncryptedFile();\n keys = Object.values(data);\n } else {\n // Keychain: we can only list by user\n keys = [];\n }\n }\n\n const activeKeys = keys.filter((k) => k.expiresAt > now);\n const expiredKeys = keys.filter((k) => k.expiresAt <= now);\n\n const ages = activeKeys.map((k) => (now - k.createdAt) / 1000);\n const oldestKeyAge = Math.min(...ages, 0);\n const newestKeyAge = Math.max(...ages, 0);\n\n return {\n totalKeys: keys.length,\n activeKeys: activeKeys.length,\n expiredKeys: expiredKeys.length,\n oldestKeyAge,\n newestKeyAge,\n };\n }\n\n /**\n * Cleanup expired keys\n */\n async cleanupExpiredKeys(): Promise<void> {\n const now = Date.now();\n let cleaned = 0;\n\n if (this.useEncryptedFile) {\n const data = await this.readEncryptedFile();\n for (const [sessionId, entry] of Object.entries(data)) {\n if (entry.expiresAt <= now) {\n delete data[sessionId];\n cleaned++;\n }\n }\n if (cleaned > 0) {\n await this.writeEncryptedFile(data);\n }\n } else {\n // Keychain: we need to list all keys and check expiry\n const accounts = await this.keychain.list(STORAGE_SERVICE);\n for (const account of accounts) {\n const entryJson = await this.keychain.get(STORAGE_SERVICE, account);\n if (entryJson) {\n const entry = JSON.parse(entryJson) as E2EEKeyEntry;\n if (entry.expiresAt <= now) {\n await this.keychain.delete(STORAGE_SERVICE, account);\n cleaned++;\n }\n }\n }\n }\n\n if (cleaned > 0) {\n console.log(`[E2EEKeyStorage] Cleaned up ${cleaned} expired keys`);\n }\n }\n\n /**\n * Shutdown storage (cleanup interval)\n */\n destroy(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = undefined;\n }\n }\n\n // ============================================================\n // Encrypted File Storage Methods\n // ============================================================\n\n private async ensureStorageFile(): Promise<void> {\n const dir = path.dirname(STORAGE_PATH);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n\n if (!fs.existsSync(STORAGE_PATH)) {\n const empty = {};\n await this.writeEncryptedFile(empty);\n // Set restrictive permissions\n fs.chmodSync(STORAGE_PATH, 0o600);\n }\n }\n\n private async readEncryptedFile(): Promise<Record<string, E2EEKeyEntry>> {\n try {\n const encrypted = fs.readFileSync(STORAGE_PATH, 'utf-8');\n if (!encrypted.trim()) return {};\n\n const decrypted = this.decryptFile(encrypted);\n return JSON.parse(decrypted) as Record<string, E2EEKeyEntry>;\n } catch (err) {\n console.error('[E2EEKeyStorage] Failed to read encrypted file:', err);\n return {};\n }\n }\n\n private async writeEncryptedFile(data: Record<string, E2EEKeyEntry>): Promise<void> {\n const json = JSON.stringify(data, null, 2);\n const encrypted = this.encryptFile(json);\n\n const tmpPath = STORAGE_PATH + '.tmp';\n fs.writeFileSync(tmpPath, encrypted, 'utf-8');\n fs.chmodSync(tmpPath, 0o600);\n fs.renameSync(tmpPath, STORAGE_PATH);\n }\n\n private encryptFile(plaintext: string): string {\n if (!this.masterPassphrase) {\n throw new Error('Master passphrase required for file encryption');\n }\n\n const salt = crypto.randomBytes(16);\n const iv = crypto.randomBytes(16);\n const key = crypto.pbkdf2Sync(\n this.masterPassphrase,\n salt,\n KEY_ITERATIONS,\n 32,\n 'sha256'\n );\n\n const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);\n let encrypted = cipher.update(plaintext, 'utf-8');\n encrypted = Buffer.concat([encrypted, cipher.final()]);\n\n const authTag = cipher.getAuthTag();\n\n const result = Buffer.concat([salt, iv, encrypted, authTag]);\n return result.toString('base64');\n }\n\n private decryptFile(encrypted: string): string {\n if (!this.masterPassphrase) {\n throw new Error('Master passphrase required for file decryption');\n }\n\n const data = Buffer.from(encrypted, 'base64');\n const salt = data.slice(0, 16);\n const iv = data.slice(16, 32);\n const ciphertext = data.slice(32, data.length - 16);\n const authTag = data.slice(data.length - 16);\n\n const key = crypto.pbkdf2Sync(\n this.masterPassphrase,\n salt,\n KEY_ITERATIONS,\n 32,\n 'sha256'\n );\n\n const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(authTag);\n\n let decrypted = decipher.update(ciphertext);\n decrypted = Buffer.concat([decrypted, decipher.final()]);\n\n return decrypted.toString('utf-8');\n }\n\n private async storeInEncryptedFile(entry: E2EEKeyEntry): Promise<void> {\n const data = await this.readEncryptedFile();\n data[entry.sessionId] = entry;\n await this.writeEncryptedFile(data);\n }\n\n private async getFromEncryptedFile(sessionId: string): Promise<E2EEKeyEntry | null> {\n const data = await this.readEncryptedFile();\n return data[sessionId] || null;\n }\n\n private async removeFromEncryptedFile(sessionId: string): Promise<void> {\n const data = await this.readEncryptedFile();\n delete data[sessionId];\n await this.writeEncryptedFile(data);\n }\n\n private async getAllFromEncryptedFile(userId: string): Promise<E2EEKeyEntry[]> {\n const data = await this.readEncryptedFile();\n return Object.values(data).filter((k) => k.userId === userId);\n }\n\n // ============================================================\n // Keychain Storage Methods\n// ============================================================\n\n private async storeInKeychain(entry: E2EEKeyEntry): Promise<void> {\n const value = JSON.stringify(entry);\n await this.keychain.set(STORAGE_SERVICE, entry.sessionId, value);\n }\n\n private async getFromKeychain(sessionId: string): Promise<E2EEKeyEntry | null> {\n const value = await this.keychain.get(STORAGE_SERVICE, sessionId);\n if (!value) return null;\n\n try {\n return JSON.parse(value) as E2EEKeyEntry;\n } catch (err) {\n console.error('[E2EEKeyStorage] Failed to parse keychain entry:', err);\n return null;\n }\n }\n\n private async removeFromKeychain(sessionId: string): Promise<void> {\n await this.keychain.delete(STORAGE_SERVICE, sessionId);\n }\n\n private async getAllFromKeychain(userId: string): Promise<E2EEKeyEntry[]> {\n const accounts = await this.keychain.list(STORAGE_SERVICE);\n const keys: E2EEKeyEntry[] = [];\n\n for (const account of accounts) {\n const entry = await this.getFromKeychain(account);\n if (entry && entry.userId === userId) {\n keys.push(entry);\n }\n }\n\n return keys;\n }\n}\n\n// ============================================================\n// Helper Functions\n// ============================================================\n\n/**\n * Generate session ID for E2EE storage\n * Format: {userId}:{endpointId}\n */\nexport function generateSessionId(userId: string, endpointId: string): string {\n return `${userId}:${endpointId}`;\n}\n\n/**\n * Parse session ID into components\n */\nexport function parseSessionId(sessionId: string): { userId: string; endpointId: string } {\n const colonIdx = sessionId.indexOf(':');\n if (colonIdx === -1) {\n throw new Error(`Invalid session ID format: ${sessionId}`);\n }\n return {\n userId: sessionId.slice(0, colonIdx),\n endpointId: sessionId.slice(colonIdx + 1),\n };\n}\n\n/**\n * Create E2EE key entry from runtime context\n */\nexport function createKeyEntry(\n userId: string,\n endpointId: string,\n keyPair: KeyPair,\n remotePublicKey: string,\n seq: number = 0\n): E2EEKeyEntry {\n return {\n sessionId: generateSessionId(userId, endpointId),\n userId,\n endpointId,\n keyPair: {\n publicKey: keyPair.publicKey.toString('base64'),\n privateKey: keyPair.privateKey.toString('base64'),\n },\n remotePublicKey,\n createdAt: Date.now(),\n expiresAt: Date.now() + DEFAULT_TTL_SECONDS * 1000,\n seq,\n };\n}\n","/**\n * secret-scan — local-side secret detection for memory team sync.\n *\n * Mirror of src/im/services/memory/team-sync.service.ts SECRET_PATTERNS.\n * Kept in sync by convention — if you add a pattern there, add it here.\n *\n * Used by memory-team-sync.ts before POSTing bytes to the server (so secrets\n * never leave the device). Server has its own independent scanner (defense\n * in depth).\n *\n * Design: docs/version190/14e-memory-cc-compat.md §8.5\n */\n\nexport interface SecretHit {\n /** Pattern name (e.g. 'aws-access-key'). */\n pattern: string;\n /** Truncated match (never more than 80 chars — no full secret echo). */\n match: string;\n /** 1-based line number. */\n line: number;\n /**\n * If true, this hit is informational only — not strong enough evidence\n * to block a push on its own (e.g. JWT-shaped strings).\n */\n warnOnly: boolean;\n}\n\ninterface SecretPatternDef {\n name: string;\n re: RegExp;\n warnOnly?: boolean;\n}\n\nconst PATTERNS: ReadonlyArray<SecretPatternDef> = [\n { name: 'aws-access-key', re: /AKIA[0-9A-Z]{16}/g },\n // Prismer keys look like `sk-prismer-live-<64-hex>` or `sk-prismer-test-<...>`.\n // Allow hyphens in the body so the `live-` / `test-` segment is tolerated.\n { name: 'prismer-api-key', re: /sk-prismer-[a-zA-Z0-9_-]{20,}/g },\n { name: 'stripe-live-key', re: /sk_live_[a-zA-Z0-9]{20,}/g },\n { name: 'stripe-test-key', re: /sk_test_[a-zA-Z0-9]{20,}/g },\n { name: 'openai-project-key', re: /sk-proj-[a-zA-Z0-9_-]{48,}/g },\n // Generic `sk-...` — must come AFTER sk-prismer-/sk-proj-; lookbehind avoids\n // re-matching inside a just-captured specific token.\n { name: 'generic-sk-key', re: /(?<![a-zA-Z0-9_-])sk-[a-zA-Z0-9]{20,}/g },\n { name: 'github-token-pat', re: /ghp_[a-zA-Z0-9]{36}/g },\n { name: 'github-token-oauth', re: /gho_[a-zA-Z0-9]{36}/g },\n { name: 'github-token-user', re: /ghu_[a-zA-Z0-9]{36}/g },\n { name: 'github-token-server', re: /ghs_[a-zA-Z0-9]{36}/g },\n { name: 'github-token-refresh', re: /ghr_[a-zA-Z0-9]{36}/g },\n { name: 'slack-token', re: /xox[baprs]-[a-zA-Z0-9-]{10,}/g },\n { name: 'private-key-block', re: /-----BEGIN (?:RSA |EC |DSA |OPENSSH |)PRIVATE KEY-----/g },\n { name: 'jwt', re: /eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g, warnOnly: true },\n];\n\n/** Scan content for known secret patterns. Returns the list of hits. */\nexport function scanForSecrets(content: string): SecretHit[] {\n const hits: SecretHit[] = [];\n if (!content) return hits;\n\n const lineOffsets: number[] = [0];\n for (let i = 0; i < content.length; i++) {\n if (content.charCodeAt(i) === 10) lineOffsets.push(i + 1);\n }\n\n const offsetToLine = (off: number): number => {\n for (let i = lineOffsets.length - 1; i >= 0; i--) {\n if (lineOffsets[i] <= off) return i + 1;\n }\n return 1;\n };\n\n for (const { name, re, warnOnly } of PATTERNS) {\n re.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = re.exec(content)) !== null) {\n hits.push({\n pattern: name,\n match: m[0].slice(0, 80),\n line: offsetToLine(m.index),\n warnOnly: warnOnly === true,\n });\n if (m.index === re.lastIndex) re.lastIndex++;\n }\n }\n\n return hits;\n}\n\n/**\n * Convenience: true if content has at least one blocking (non-warnOnly) hit.\n */\nexport function hasBlockingSecret(content: string): boolean {\n return scanForSecrets(content).some((h) => !h.warnOnly);\n}\n","/**\n * memory-team-sync — client-side delta push + server-wins pull for team memory.\n *\n * Walks a local directory (typically `~/.claude/memory/team/<owner>/<repo>/`),\n * diffs content hashes against a persisted `last-sync.json`, pushes only the\n * changed files, and writes any server-side-newer rows back to disk.\n *\n * Design: docs/version190/14e-memory-cc-compat.md §8.5\n *\n * Secret scanning (local): any file whose content matches a blocking pattern\n * is rejected before it leaves the device. The server also scans (defense in\n * depth).\n */\n\nimport { createHash } from 'node:crypto';\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n statSync,\n writeFileSync,\n unlinkSync,\n} from 'node:fs';\nimport { dirname, join, relative, sep } from 'node:path';\n\nimport { hasBlockingSecret, scanForSecrets } from './secret-scan.js';\n\n/** Per-file content size limit (matches server). */\nexport const MEMORY_TEAM_SYNC_MAX_BYTES = 250 * 1024;\n\n/** Name of the sidecar state file. */\nexport const LAST_SYNC_FILE = '.prismer-team-sync.json';\n\n/** Directories we always skip when walking rootDir. */\nconst SKIP_DIRS = new Set<string>([\n '.git',\n '.svn',\n '.hg',\n 'node_modules',\n '.next',\n '.cache',\n 'dist',\n 'build',\n '.turbo',\n '.venv',\n 'venv',\n '__pycache__',\n]);\n\n// ═══════════════════════════════════════════════════════════\n// Public types\n// ═══════════════════════════════════════════════════════════\n\nexport interface SyncTeamMemoryOptions {\n /** Team identifier, e.g. `'acme/widgets'`. */\n team: string;\n /** Root directory to sync (scanned recursively). */\n rootDir: string;\n /** Prismer API key (Bearer). */\n apiKey: string;\n /**\n * Base URL for the IM API — typically the cloud host.\n * e.g. `'https://prismer.cloud/api/im'` or `'http://localhost:3000/api/im'`.\n */\n baseUrl: string;\n /**\n * Optional override of the since timestamp. Normally we read this from the\n * sidecar state file and ignore this param. Exposed mainly for testing.\n */\n since?: string;\n /**\n * Custom fetch (for tests). Defaults to the global fetch.\n */\n fetchImpl?: typeof fetch;\n /**\n * If true, do not write pulled[] rows to disk and do not update sidecar.\n * Useful for dry-run/preflight.\n */\n dryRun?: boolean;\n}\n\nexport interface SyncTeamMemoryResult {\n pushed: number;\n pulled: number;\n rejected: Array<{ path: string; reason: string; detail?: string }>;\n skippedLocalSecrets: Array<{ path: string; pattern: string; line: number }>;\n serverTime: string;\n}\n\ninterface LastSyncState {\n /** Per-file sha256 of the last-seen content (plaintext). */\n hashes: Record<string, string>;\n /** Server time (ISO) from the last successful sync — used as next `since`. */\n serverTime: string | null;\n /** Team name this state is for. */\n team: string;\n}\n\n// ═══════════════════════════════════════════════════════════\n// Helpers\n// ═══════════════════════════════════════════════════════════\n\nfunction sha256Hex(s: string): string {\n return createHash('sha256').update(s).digest('hex');\n}\n\nfunction readLastSync(rootDir: string): LastSyncState {\n const p = join(rootDir, LAST_SYNC_FILE);\n if (!existsSync(p)) {\n return { hashes: {}, serverTime: null, team: '' };\n }\n try {\n const raw = readFileSync(p, 'utf8');\n const parsed = JSON.parse(raw) as Partial<LastSyncState>;\n return {\n hashes: parsed.hashes && typeof parsed.hashes === 'object' ? parsed.hashes : {},\n serverTime: typeof parsed.serverTime === 'string' ? parsed.serverTime : null,\n team: typeof parsed.team === 'string' ? parsed.team : '',\n };\n } catch {\n return { hashes: {}, serverTime: null, team: '' };\n }\n}\n\nfunction writeLastSync(rootDir: string, state: LastSyncState): void {\n const p = join(rootDir, LAST_SYNC_FILE);\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, JSON.stringify(state, null, 2), 'utf8');\n}\n\n/** Walk rootDir recursively for .md files (only). Returns POSIX-style rel paths. */\nexport function listMarkdownFiles(rootDir: string): string[] {\n const out: string[] = [];\n function walk(dir: string) {\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return;\n }\n for (const entry of entries) {\n if (SKIP_DIRS.has(entry)) continue;\n if (entry === LAST_SYNC_FILE) continue;\n const full = join(dir, entry);\n let st: ReturnType<typeof statSync>;\n try {\n st = statSync(full);\n } catch {\n continue;\n }\n if (st.isDirectory()) walk(full);\n else if (st.isFile() && /\\.md$/i.test(entry)) out.push(full);\n }\n }\n walk(rootDir);\n return out.map((abs) => relative(rootDir, abs).split(sep).join('/'));\n}\n\n/**\n * Write pulled content to disk inside rootDir. Creates parent directories as\n * needed. Refuses to write outside rootDir (path traversal guard).\n */\nfunction writePulledFile(rootDir: string, relPath: string, content: string): void {\n if (relPath.includes('..') || relPath.startsWith('/')) {\n throw new Error(`Refusing to write outside rootDir: ${relPath}`);\n }\n const target = join(rootDir, relPath);\n const root = join(rootDir, '.'); // normalized\n // belt & suspenders: ensure target is under root after join\n if (!target.startsWith(root)) {\n throw new Error(`Refusing to write outside rootDir: ${relPath}`);\n }\n mkdirSync(dirname(target), { recursive: true });\n writeFileSync(target, content, 'utf8');\n}\n\n// ═══════════════════════════════════════════════════════════\n// Public entry point\n// ═══════════════════════════════════════════════════════════\n\n/**\n * Sync a team-memory directory with the cloud.\n *\n * 1. Walk rootDir for .md files\n * 2. Hash each; diff against last-sync.json → push[] candidates\n * 3. Local secret scan → any hits are skipped (not pushed)\n * 4. POST /memory/team/sync with push[] and since\n * 5. Write pulled[] to disk (server wins)\n * 6. Update last-sync.json\n */\nexport async function syncTeamMemory(opts: SyncTeamMemoryOptions): Promise<SyncTeamMemoryResult> {\n const { team, rootDir, apiKey, baseUrl, fetchImpl, dryRun } = opts;\n const doFetch = fetchImpl ?? fetch;\n\n if (!existsSync(rootDir)) {\n mkdirSync(rootDir, { recursive: true });\n }\n\n const lastSync = readLastSync(rootDir);\n const since = opts.since ?? (lastSync.team === team ? lastSync.serverTime ?? undefined : undefined);\n\n // ── Gather push candidates ────────────────────────────────\n const files = listMarkdownFiles(rootDir);\n const pushEntries: Array<{ path: string; content: string; contentHash: string }> = [];\n const skippedLocalSecrets: SyncTeamMemoryResult['skippedLocalSecrets'] = [];\n const newHashes: Record<string, string> = {};\n\n for (const rel of files) {\n const abs = join(rootDir, rel);\n let raw: string;\n try {\n raw = readFileSync(abs, 'utf8');\n } catch {\n continue;\n }\n\n const byteLen = Buffer.byteLength(raw, 'utf8');\n if (byteLen > MEMORY_TEAM_SYNC_MAX_BYTES) {\n // Skip oversized locally — server would reject anyway.\n continue;\n }\n\n const hash = sha256Hex(raw);\n newHashes[rel] = hash;\n\n // Only push when hash changed vs last sync.\n if (lastSync.team === team && lastSync.hashes[rel] === hash) continue;\n\n if (hasBlockingSecret(raw)) {\n const hit = scanForSecrets(raw).find((h) => !h.warnOnly)!;\n skippedLocalSecrets.push({ path: rel, pattern: hit.pattern, line: hit.line });\n continue;\n }\n\n pushEntries.push({ path: rel, content: raw, contentHash: hash });\n }\n\n // ── POST to server ───────────────────────────────────────\n const url = `${baseUrl.replace(/\\/$/, '')}/memory/team/sync`;\n const res = await doFetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ team, since, push: pushEntries }),\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`team sync failed: HTTP ${res.status} ${text}`);\n }\n\n const json = (await res.json()) as {\n ok: boolean;\n data?: {\n pulled: Array<{\n path: string;\n contentHash: string;\n content: string;\n memoryType: string | null;\n description: string | null;\n updatedAt: string;\n }>;\n pushed: { accepted: number; rejected: Array<{ path: string; reason: string; detail?: string }> };\n serverTime: string;\n };\n error?: string;\n };\n\n if (!json.ok || !json.data) {\n throw new Error(`team sync rejected: ${json.error ?? 'unknown'}`);\n }\n\n const data = json.data;\n\n // ── Write pulled back to disk ────────────────────────────\n if (!dryRun) {\n for (const row of data.pulled) {\n try {\n writePulledFile(rootDir, row.path, row.content);\n newHashes[row.path] = row.contentHash;\n } catch (err) {\n // Don't crash the whole sync over one bad path; surface via rejected list.\n data.pushed.rejected.push({\n path: row.path,\n reason: 'write_failed',\n detail: (err as Error).message,\n });\n }\n }\n }\n\n // Drop any entries whose local file disappeared (filter newHashes to what\n // still exists on disk OR what we just pulled).\n const finalHashes: Record<string, string> = {};\n for (const [p, h] of Object.entries(newHashes)) {\n finalHashes[p] = h;\n }\n\n if (!dryRun) {\n writeLastSync(rootDir, {\n team,\n hashes: finalHashes,\n serverTime: data.serverTime,\n });\n }\n\n return {\n pushed: data.pushed.accepted,\n pulled: data.pulled.length,\n rejected: data.pushed.rejected,\n skippedLocalSecrets,\n serverTime: data.serverTime,\n };\n}\n\n/**\n * Remove the sidecar state file — forces the next sync to re-push everything.\n * Useful from CLI tooling.\n */\nexport function resetTeamSyncState(rootDir: string): void {\n const p = join(rootDir, LAST_SYNC_FILE);\n if (existsSync(p)) {\n try {\n unlinkSync(p);\n } catch {\n /* ignore */\n }\n }\n}\n","/**\n * Shamir Secret Sharing over GF(256) — byte-oriented implementation.\n *\n * Split a secret Buffer into N shares such that any M (threshold) shares can\n * reconstruct the original, but fewer than M reveal zero information.\n *\n * Field: GF(256) with AES irreducible polynomial 0x11B.\n * Addition = XOR. Multiplication = carryless multiply mod 0x11B.\n * Share-id x ∈ {1..255} (x=0 is the secret itself).\n *\n * Each byte of the secret is split independently using a polynomial of degree\n * m-1: P(x) = s + a_1*x + a_2*x^2 + ... + a_{m-1}*x^{m-1} (all arithmetic in GF(256))\n * where s is the secret byte and a_1..a_{m-1} are uniformly random.\n *\n * Recovery uses Lagrange interpolation evaluated at x=0.\n *\n * Mnemonic format: Crockford base32 with 1-byte version header (0x01) and\n * CRC-16/CCITT-FALSE checksum. Groups of 4 characters separated by hyphens.\n *\n * No external npm dependencies.\n *\n * See: Shamir, \"How to Share a Secret\", 1979. GF(256) byte-level variant used\n * by industry (Trezor Shamir Backup, HashiCorp Vault, etc.).\n */\n\nimport * as crypto from 'node:crypto';\n\n// ============================================================\n// Branded type — nominal typing for Shamir shares\n// ============================================================\n\n/**\n * Branded `Buffer` that has been validated as a Shamir share by this module.\n *\n * Nominal typing prevents accidentally passing an arbitrary `Buffer` (e.g.\n * `Buffer.from('hello')`) into {@link combineShares} or\n * {@link encodeShareAsMnemonic}. TypeScript structural equality is defeated\n * by the `__brand` phantom field, so the only path to a `ShamirShare` value\n * is through this module's own functions (`splitSecret`,\n * `decodeShareFromMnemonic`) or the explicit escape hatch\n * {@link unsafeAsShamirShare}.\n *\n * This is a compile-time guard only; runtime validation (duplicate ids,\n * inconsistent lengths, CRC) still happens inside `combineShares` /\n * `decodeShareFromMnemonic`.\n */\nexport type ShamirShare = Buffer & { readonly __brand: unique symbol };\n\n/**\n * Escape hatch for interop paths that already hold raw share Buffers\n * (e.g. legacy callers that read bytes off the wire themselves and cannot\n * route through {@link decodeShareFromMnemonic}).\n *\n * This is a **sharp edge**: the caller is asserting the buffer is a\n * well-formed share byte string (`[share_id, y_byte_1, y_byte_2, ...]` with\n * `share_id ∈ 1..255`). Passing an arbitrary buffer here will compile, and\n * will pass length / id / duplicate checks inside `combineShares`, but will\n * reconstruct a plausibly-shaped yet **semantically wrong** secret.\n *\n * Prefer `decodeShareFromMnemonic` wherever possible — the CRC-16 check\n * there catches tampered or wrong-batch shares.\n */\nexport function unsafeAsShamirShare(buf: Buffer): ShamirShare {\n return buf as ShamirShare;\n}\n\n// ============================================================\n// GF(256) arithmetic\n// ============================================================\n\n// Precompute log/antilog (exp) tables for fast multiplication using the\n// generator g=0x03 (primitive element of GF(256) with polynomial 0x11B).\n// x * y = antilog[(log[x] + log[y]) mod 255] for x,y ≠ 0.\nconst GF_LOG: number[] = new Array(256).fill(0);\nconst GF_EXP: number[] = new Array(256).fill(0);\n\n(function initGfTables(): void {\n let x = 1;\n for (let i = 0; i < 255; i++) {\n GF_EXP[i] = x;\n GF_LOG[x] = i;\n // Multiply by generator 0x03 in GF(256) with AES poly 0x11B:\n // 0x03 * x = (x << 1) ^ x, reduced by 0x11B if overflow.\n let next = (x << 1) ^ x;\n if (next & 0x100) next ^= 0x11b;\n x = next & 0xff;\n }\n GF_EXP[255] = GF_EXP[0]; // wrap-around convenience\n})();\n\n/** GF(256) multiplication. */\nfunction gfMul(a: number, b: number): number {\n if (a === 0 || b === 0) return 0;\n return GF_EXP[(GF_LOG[a] + GF_LOG[b]) % 255];\n}\n\n/** GF(256) division. */\nfunction gfDiv(a: number, b: number): number {\n if (b === 0) throw new Error('GF(256) division by zero');\n if (a === 0) return 0;\n return GF_EXP[(GF_LOG[a] - GF_LOG[b] + 255) % 255];\n}\n\n/** Evaluate polynomial (coeffs[0] + coeffs[1]*x + ...) at x using Horner's method. */\nfunction gfEval(coeffs: number[], x: number): number {\n let result = 0;\n for (let i = coeffs.length - 1; i >= 0; i--) {\n result = gfMul(result, x) ^ coeffs[i];\n }\n return result;\n}\n\n/**\n * Lagrange interpolation at x=0 given (x_i, y_i) points.\n * Returns P(0) = Σ y_i * Π_{j≠i} (0 - x_j) / (x_i - x_j) in GF(256).\n * Since subtraction = XOR in GF(256), (0 - x_j) = x_j and (x_i - x_j) = x_i ^ x_j.\n */\nfunction gfInterpolateAtZero(xs: number[], ys: number[]): number {\n let result = 0;\n const k = xs.length;\n for (let i = 0; i < k; i++) {\n let num = 1;\n let den = 1;\n for (let j = 0; j < k; j++) {\n if (i === j) continue;\n num = gfMul(num, xs[j]); // (0 - x_j) in GF(256) is x_j (XOR-based subtraction)\n den = gfMul(den, xs[i] ^ xs[j]);\n }\n const term = gfMul(ys[i], gfDiv(num, den));\n result ^= term;\n }\n return result;\n}\n\n// ============================================================\n// Split / Combine\n// ============================================================\n\n/**\n * Split a secret into n shares; any m can recombine.\n *\n * Each returned share Buffer is [share_id_byte, y_byte_1, y_byte_2, ...].\n * The share-id is 1..n (never 0).\n *\n * @param secret plaintext bytes\n * @param n total shares (2..255)\n * @param m threshold (2..n)\n */\nexport function splitSecret(secret: Buffer, n: number, m: number): ShamirShare[] {\n if (!Number.isInteger(n) || !Number.isInteger(m)) {\n throw new Error('splitSecret: n and m must be integers');\n }\n if (m < 2) {\n throw new Error('splitSecret: threshold m must be >= 2');\n }\n if (n < m) {\n throw new Error('splitSecret: total shares n must be >= threshold m');\n }\n if (n > 255) {\n throw new Error('splitSecret: n must be <= 255 (GF(256) x-range)');\n }\n if (secret.length === 0) {\n throw new Error('splitSecret: secret cannot be empty');\n }\n\n const secretLen = secret.length;\n // For each byte of the secret, pick m-1 random coefficients. We allocate\n // `secretLen * (m-1)` random bytes once from crypto.randomBytes for performance.\n const randomCoeffs =\n m > 1 ? crypto.randomBytes(secretLen * (m - 1)) : Buffer.alloc(0);\n\n // Prepare share buffers: 1 byte share-id + secretLen y bytes per share.\n const shares: Buffer[] = [];\n for (let i = 0; i < n; i++) {\n const buf = Buffer.alloc(secretLen + 1);\n buf[0] = i + 1; // share-id 1..n\n shares.push(buf);\n }\n\n // For each byte of the secret, build the polynomial and evaluate at each share-id.\n const coeffs = new Array(m).fill(0);\n for (let byteIdx = 0; byteIdx < secretLen; byteIdx++) {\n coeffs[0] = secret[byteIdx];\n for (let k = 1; k < m; k++) {\n coeffs[k] = randomCoeffs[byteIdx * (m - 1) + (k - 1)];\n }\n for (let i = 0; i < n; i++) {\n const xVal = i + 1;\n shares[i][byteIdx + 1] = gfEval(coeffs, xVal);\n }\n }\n\n // Brand cast: these buffers were constructed here under the Shamir\n // invariants (valid share-id in [1..n], secretLen+1 bytes, polynomial\n // evaluation y_bytes). Safe to assert as ShamirShare.\n return shares as ShamirShare[];\n}\n\n/**\n * Combine shares to recover the secret. Any m of n suffice (where m is the\n * threshold used at split time).\n *\n * @param shares array of share Buffers (each [x_byte, y_bytes...])\n * @returns recovered secret\n */\nexport function combineShares(shares: ShamirShare[]): Buffer {\n if (!Array.isArray(shares) || shares.length === 0) {\n throw new Error('combineShares: at least one share is required');\n }\n if (shares.length < 2) {\n throw new Error('combineShares: at least 2 shares required');\n }\n\n const expectedLen = shares[0].length;\n if (expectedLen < 2) {\n throw new Error('combineShares: share too short to contain id + data');\n }\n\n const xs: number[] = [];\n const seen = new Set<number>();\n for (const s of shares) {\n if (!Buffer.isBuffer(s)) {\n throw new Error('combineShares: all shares must be Buffers');\n }\n if (s.length !== expectedLen) {\n throw new Error(\n `combineShares: inconsistent share lengths (expected ${expectedLen}, got ${s.length})`,\n );\n }\n const x = s[0];\n if (x === 0) {\n throw new Error('combineShares: share-id byte cannot be 0');\n }\n if (seen.has(x)) {\n throw new Error(`combineShares: duplicate share-id ${x}`);\n }\n seen.add(x);\n xs.push(x);\n }\n\n const secretLen = expectedLen - 1;\n const secret = Buffer.alloc(secretLen);\n\n const ys = new Array(shares.length).fill(0);\n for (let byteIdx = 0; byteIdx < secretLen; byteIdx++) {\n for (let i = 0; i < shares.length; i++) {\n ys[i] = shares[i][byteIdx + 1];\n }\n secret[byteIdx] = gfInterpolateAtZero(xs, ys);\n }\n\n return secret;\n}\n\n// ============================================================\n// Mnemonic encoding (Crockford base32 + version + CRC-16)\n// ============================================================\n\nconst CROCKFORD_ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';\nconst CROCKFORD_LOOKUP: Record<string, number> = (() => {\n const map: Record<string, number> = {};\n for (let i = 0; i < CROCKFORD_ALPHABET.length; i++) {\n map[CROCKFORD_ALPHABET[i]] = i;\n }\n // Crockford aliases (O→0, I/L→1)\n map['O'] = 0;\n map['I'] = 1;\n map['L'] = 1;\n return map;\n})();\n\nconst MNEMONIC_VERSION = 0x01;\n\n/** CRC-16/CCITT-FALSE (poly 0x1021, init 0xFFFF). */\nfunction crc16(buf: Buffer): number {\n let crc = 0xffff;\n for (let i = 0; i < buf.length; i++) {\n crc ^= buf[i] << 8;\n for (let j = 0; j < 8; j++) {\n if (crc & 0x8000) {\n crc = ((crc << 1) ^ 0x1021) & 0xffff;\n } else {\n crc = (crc << 1) & 0xffff;\n }\n }\n }\n return crc & 0xffff;\n}\n\n/** Encode bytes as Crockford base32 string (no padding). */\nfunction base32Encode(buf: Buffer): string {\n let bits = 0;\n let value = 0;\n let out = '';\n for (let i = 0; i < buf.length; i++) {\n value = (value << 8) | buf[i];\n bits += 8;\n while (bits >= 5) {\n out += CROCKFORD_ALPHABET[(value >>> (bits - 5)) & 0x1f];\n bits -= 5;\n }\n }\n if (bits > 0) {\n out += CROCKFORD_ALPHABET[(value << (5 - bits)) & 0x1f];\n }\n return out;\n}\n\n/** Decode Crockford base32 string back into bytes.\n * Requires the caller to know the original byte length (stored in the\n * version header of the mnemonic framing so this is never ambiguous).\n */\nfunction base32Decode(s: string, expectedByteLen: number): Buffer {\n const normalized = s.toUpperCase();\n let bits = 0;\n let value = 0;\n const out = Buffer.alloc(expectedByteLen);\n let outIdx = 0;\n for (const ch of normalized) {\n const n = CROCKFORD_LOOKUP[ch];\n if (n === undefined) {\n throw new Error(`base32Decode: invalid character \"${ch}\"`);\n }\n value = (value << 5) | n;\n bits += 5;\n if (bits >= 8) {\n if (outIdx >= expectedByteLen) {\n // Extra trailing bits are padding — validate they are zero, then stop.\n bits -= 8; // discard the high byte we would have emitted\n value &= (1 << bits) - 1;\n continue;\n }\n out[outIdx++] = (value >>> (bits - 8)) & 0xff;\n bits -= 8;\n }\n }\n if (outIdx !== expectedByteLen) {\n throw new Error(\n `base32Decode: decoded ${outIdx} bytes, expected ${expectedByteLen}`,\n );\n }\n return out;\n}\n\n/**\n * Encode a share as a mnemonic string.\n *\n * Framing (before base32 encoding):\n * [0x01 version] [share bytes...] [CRC-16/CCITT-FALSE of (version||share)]\n *\n * Output is Crockford base32, grouped in blocks of 4 characters separated by\n * hyphens for readability. Case-insensitive on decode.\n */\nexport function encodeShareAsMnemonic(share: ShamirShare): string {\n if (!Buffer.isBuffer(share) || share.length < 2) {\n throw new Error('encodeShareAsMnemonic: share must be a Buffer of length >= 2');\n }\n const versioned = Buffer.concat([Buffer.from([MNEMONIC_VERSION]), share]);\n const crc = crc16(versioned);\n const crcBuf = Buffer.from([(crc >> 8) & 0xff, crc & 0xff]);\n const framed = Buffer.concat([versioned, crcBuf]);\n const raw = base32Encode(framed);\n // Group into 4-char blocks, separated by '-'.\n const groups: string[] = [];\n for (let i = 0; i < raw.length; i += 4) {\n groups.push(raw.slice(i, i + 4));\n }\n return groups.join('-');\n}\n\n/**\n * Decode a mnemonic string back into a share Buffer. Strips whitespace,\n * hyphens, and normalizes case. Validates the version byte and CRC-16.\n */\nexport function decodeShareFromMnemonic(encoded: string): ShamirShare {\n if (typeof encoded !== 'string' || encoded.length === 0) {\n throw new Error('decodeShareFromMnemonic: input must be a non-empty string');\n }\n // Strip whitespace, hyphens, normalize case.\n const stripped = encoded.replace(/[\\s-]/g, '').toUpperCase();\n if (stripped.length === 0) {\n throw new Error('decodeShareFromMnemonic: empty after stripping');\n }\n\n // Each 5 characters of base32 encodes roughly 3.125 bytes; the exact byte\n // length depends on the share length (which we don't know yet). Strategy:\n // decode into the maximum possible byte length, then trim using the CRC.\n // We know the framing is [version(1) || share(k) || crc(2)] for k >= 1.\n // base32Encode produces ceil(totalBits / 5) chars → totalBytes = floor(bits/8).\n const totalBits = stripped.length * 5;\n const maxBytes = Math.floor(totalBits / 8);\n if (maxBytes < 4) {\n // Need at least version(1) + share(1) + crc(2).\n throw new Error('decodeShareFromMnemonic: input too short to contain version + share + CRC');\n }\n\n const decoded = base32Decode(stripped, maxBytes);\n\n // decoded = [version, ...share, crc_hi, crc_lo]\n if (decoded[0] !== MNEMONIC_VERSION) {\n throw new Error(\n `decodeShareFromMnemonic: unsupported version 0x${decoded[0].toString(16)} (expected 0x${MNEMONIC_VERSION.toString(16)})`,\n );\n }\n const crcRead = (decoded[decoded.length - 2] << 8) | decoded[decoded.length - 1];\n const body = decoded.subarray(0, decoded.length - 2);\n const crcCalc = crc16(body);\n if (crcRead !== crcCalc) {\n throw new Error(\n `decodeShareFromMnemonic: CRC mismatch (got 0x${crcRead.toString(16)}, expected 0x${crcCalc.toString(16)})`,\n );\n }\n\n // share bytes are decoded[1..length-2]\n // Brand cast: CRC-16 passed, so the buffer is a validated share from a\n // mnemonic produced by {@link encodeShareAsMnemonic}. Safe to assert.\n return Buffer.from(decoded.subarray(1, decoded.length - 2)) as ShamirShare;\n}\n\n// Internal helpers exposed for tests only.\nexport const __internal = {\n gfMul,\n gfDiv,\n gfEval,\n gfInterpolateAtZero,\n crc16,\n base32Encode,\n base32Decode,\n};\n","// Barrel re-export for the @prismer/runtime daemon library API.\n\nexport const RUNTIME_VERSION = '1.9.0';\n\nexport {\n DaemonProcess,\n DaemonAlreadyRunningError,\n} from './daemon-process.js';\n\nexport type {\n DaemonState,\n DaemonOptions,\n ShutdownHandler,\n} from './daemon-process.js';\n\nexport {\n EventBus,\n} from './event-bus.js';\n\nexport type {\n EventBusEnvelope,\n SubscriptionHandler,\n Subscription,\n EventBusOptions,\n} from './event-bus.js';\n\nexport {\n AgentSupervisor,\n} from './agent-supervisor.js';\n\nexport type {\n AgentState,\n AgentDescriptor,\n AgentStatus,\n SupervisorOptions,\n} from './agent-supervisor.js';\n\n// Sprint A3 — AdapterRegistry / DispatchMux (D4)\nexport { AdapterRegistry } from './adapter-registry.js';\nexport type {\n AdapterDescriptor,\n AdapterDispatchInput,\n AdapterDispatchResult,\n AdapterImpl,\n} from './adapter-registry.js';\nexport { DispatchMux } from './dispatch-mux.js';\nexport type { DispatchMuxRequest, DispatchMuxResult } from './dispatch-mux.js';\n\nexport {\n DaemonHttpServer,\n} from './daemon-http.js';\n\nexport type {\n DaemonHttpOptions,\n AuthenticatedIdentity,\n RouteHandler,\n} from './daemon-http.js';\n\nexport {\n EvolutionGatewayHttpHandler,\n} from './evolution-gateway.js';\n\nexport type {\n EvolutionGatewayOptions,\n SignalExtractionRequest,\n AnalyzeRequest,\n RecordRequest,\n CreateGeneRequest,\n DistillationRequest,\n} from './evolution-gateway.js';\n\nexport {\n TaskRouter,\n TaskRouteState,\n} from './task-router.js';\n\nexport type {\n TaskRouterOptions,\n TaskInfo,\n RouteTaskRequest,\n RouteTaskResponse,\n AssignTaskRequest,\n StepCompletedRequest,\n CancelTaskRequest,\n StepFailedRequest,\n StepTimeoutRequest,\n} from './task-router.js';\n\nexport {\n LLMDispatcher,\n AllProvidersFailedError,\n} from './llm-dispatcher.js';\n\nexport type {\n LLMMessage,\n LLMRequest,\n LLMResponse,\n LLMProvider,\n RoutingPolicy,\n ProviderStats,\n} from './llm-dispatcher.js';\n\nexport {\n Keychain,\n NoKeychainBackendError,\n KeychainOperationError,\n} from './keychain.js';\n\nexport type {\n KeychainBackend,\n KeychainAdapter,\n KeychainOptions,\n} from './keychain.js';\n\nexport {\n loadConfig,\n writeConfig,\n parseKeyringPlaceholder,\n ConfigError,\n} from './config.js';\n\nexport type {\n PrismerConfig,\n LoadConfigOptions,\n} from './config.js';\n\nexport {\n migrateSecrets,\n} from './commands/migrate-secrets.js';\n\nexport {\n startDaemonRunner,\n} from './daemon/runner.js';\n\nexport type {\n DaemonRunnerOptions,\n DaemonRunnerHandle,\n} from './daemon/runner.js';\n\nexport type {\n MigrateSecretsOptions,\n MigrateSecretsResult,\n} from './commands/migrate-secrets.js';\n\nexport {\n UI,\n getUI,\n setUI,\n applyCommonFlags,\n assertBrandVoice,\n} from './cli/ui.js';\n\nexport type {\n OutputMode,\n UIOptions,\n TableRow,\n TableOptions,\n} from './cli/ui.js';\n\nexport {\n createCliContext,\n} from './cli/context.js';\n\nexport type {\n CliContext,\n} from './cli/context.js';\n\nexport {\n AGENT_CATALOG,\n getAgent,\n} from './agents/registry.js';\n\nexport type {\n AgentCatalogEntry,\n} from './agents/registry.js';\n\nexport {\n mergeHooks,\n readHookConfig,\n writeHookConfig,\n installHooks,\n rollbackHooks,\n} from './agents/hooks.js';\n\nexport type {\n HookFormat,\n HookConfig,\n HookEntry,\n MergeResult,\n MergeOptions,\n} from './agents/hooks.js';\n\nexport type {\n PairOffer,\n PairedDevice,\n} from './commands/pair.js';\n\nexport type {\n MigrateOptions,\n MigrateResult,\n} from './commands/migrate.js';\n\nexport {\n MemoryDB,\n type MemoryFile,\n type MemoryFileVersion,\n type DreamCompaction,\n getMemoryDB,\n closeMemoryDB,\n type EncryptionConfig,\n encrypt,\n decrypt,\n deriveKey,\n generateSalt,\n} from './memory-db.js';\n\nexport {\n type WriteMemoryRequest,\n type RecallRequest,\n type ListMemoryRequest,\n type MemoryResponse,\n} from './memory-gateway.js';\n\nexport {\n DreamScheduler,\n createDreamScheduler,\n runDream,\n type DreamResult,\n type DreamSchedulerOptions,\n} from './memory-dream-runtime.js';\n\n// PARA L8 Session Export — trace writer + manager\n// See docs/version190/03-para-spec.md §4.2 L8\nexport {\n TraceWriter,\n TraceWriterManager,\n} from './trace-writer.js';\n\nexport type {\n TraceWriterOptions,\n TraceWriterManagerOptions,\n} from './trace-writer.js';\n\n// Event bus integration for runtime package (requires wire package exports)\n// @ts-ignore - Cannot find module './event-bus.js' in wire package, skip for now\n// Temporarily commented out to unblock build\n// export {\n// EventBus,\n// Subscription,\n// SubscriptionHandler,\n// EventBusEnvelope,\n// EventBusOptions,\n// } from './event-bus.js';\n\n// E2EE Crypto exports (v1.9.0) — exported separately to avoid conflict with memory-db encrypt/decrypt\nexport {\n generateKeyPair as generateE2EEKeyPair,\n deriveSharedSecret,\n deriveSessionKeys,\n createE2EEContext,\n encryptMessage,\n decryptMessage,\n deserializeEnvelope,\n serializeEnvelope,\n} from './e2ee-crypto.js';\n\nexport type {\n KeyPair as E2EEKeyPair,\n E2EEContext,\n EncryptedEnvelope,\n} from './e2ee-crypto.js';\n\n// E2EE Key Storage exports (v1.9.0)\nexport {\n E2EEKeyStorage,\n createKeyEntry,\n generateSessionId,\n parseSessionId,\n} from './e2ee-key-storage.js';\n\nexport type {\n E2EEKeyEntry,\n E2EEStorageStats,\n} from './e2ee-key-storage.js';\n\n// v1.9.0: Team Memory sync (delta push + secret scanning)\n// Design: docs/version190/14e-memory-cc-compat.md §8.5\nexport {\n scanForSecrets,\n hasBlockingSecret,\n} from './secret-scan.js';\n\nexport type {\n SecretHit,\n} from './secret-scan.js';\n\nexport {\n syncTeamMemory,\n resetTeamSyncState,\n listMarkdownFiles,\n LAST_SYNC_FILE,\n MEMORY_TEAM_SYNC_MAX_BYTES,\n} from './memory-team-sync.js';\n\nexport type {\n SyncTeamMemoryOptions,\n SyncTeamMemoryResult,\n} from './memory-team-sync.js';\n\n// v1.9.0: Shamir secret sharing for MEMORY_ENCRYPTION_SECRET key recovery.\n// Design: docs/version190/14d-memory-infra.md §9.3\nexport {\n splitSecret,\n combineShares,\n encodeShareAsMnemonic,\n decodeShareFromMnemonic,\n unsafeAsShamirShare,\n} from './shamir.js';\n\nexport type {\n ShamirShare,\n} from './shamir.js';\n\n// v1.9.0: Daemon-side outbox + timeline for disconnect compensation (§5.6.5).\n// Paired with cloud relay-handler OPCODE 0x05/0x06 backfill protocol.\nexport { DaemonOutbox, frameFromParts } from './daemon-outbox.js';\nexport type {\n DaemonOutboxOptions,\n TimelineEntry,\n OutboxEntry,\n} from './daemon-outbox.js';\n\nexport { RelayClient, OPCODE } from './relay-client.js';\nexport type { RelayClientOptions, RelayState, RemoteCommand } from './relay-client.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA,YAAY,QAAQ;AACpB,SAAS,aAAa,mBAAmB;AACzC,YAAY,UAAU;AACtB,YAAY,QAAQ;AAwBb,IAAM,4BAAN,cAAwC,MAAM;AAAA,EAC1C;AAAA,EACA;AAAA,EAET,YAAY,KAAa,SAAiB;AACxC,UAAM,mDAAmD,GAAG,eAAe,OAAO,GAAG;AACrF,SAAK,OAAO;AACZ,SAAK,cAAc;AACnB,SAAK,UAAU;AAAA,EACjB;AACF;AAMO,IAAM,gBAAN,MAAM,eAAc;AAAA,EACjB,SAAsB;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAuC,CAAC;AAAA,EACxC,iBAAwD,CAAC;AAAA,EAClE,sBAAsB;AAAA,EAEtB,kBAAuC;AAAA,EACvC,iBAAsC;AAAA,EACtC,iBAAsC;AAAA;AAAA;AAAA,EAGtC,kBAAkB;AAAA,EAE1B,YAAY,MAAsB;AAChC,UAAM,OAAU,WAAQ;AACxB,SAAK,WAAW,MAAM,WAAgB,UAAK,MAAM,YAAY,YAAY;AACzE,SAAK,WAAW,MAAM,WAAgB,UAAK,MAAM,UAAU;AAC3D,SAAK,WAAW,MAAM,WAAgB,UAAK,MAAM,YAAY,YAAY;AACzE,SAAK,yBAAyB,MAAM,yBAAyB;AAAA,EAC/D;AAAA,EAEA,IAAI,QAAqB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,MAAc;AAChB,WAAO,QAAQ;AAAA,EACjB;AAAA,EAEA,IAAI,UAAkB;AACpB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,UAAkB;AACpB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,gBAA+D;AACjE,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,WAAW,YAAY;AAC9B,YAAM,IAAI,MAAM,mCAAmC,KAAK,MAAM,wBAAwB;AAAA,IACxF;AAEA,UAAM,UAAU;AAAA,MACd,KAAK;AAAA,MACA,UAAK,KAAK,UAAU,MAAM;AAAA,MAC1B,UAAK,KAAK,UAAU,SAAS;AAAA,MAC7B,UAAK,KAAK,UAAU,MAAM;AAAA,MAC1B,UAAK,KAAK,UAAU,QAAQ;AAAA,IACnC;AACA,eAAW,OAAO,SAAS;AACzB,MAAG,aAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACvC;AAEA,SAAK,gBAAgB;AAErB,QAAI,KAAK,wBAAwB;AAM/B,YAAM,aAAa,CAAC,WAAiC,YAA2B;AAC9E,YAAI,KAAK,iBAAiB;AAExB,kBAAQ,KAAK,CAAC;AAAA,QAChB;AACA,aAAK,kBAAkB;AACvB,aAAK,cAAc,MAAM;AACzB,YAAI;AACF,gBAAM,KAAK,SAAS,MAAM;AAAA,QAC5B,QAAQ;AAAA,QAER;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,WAAK,kBAAkB,MAAY;AAAE,aAAK,WAAW,SAAS,EAAE;AAAA,MAAG;AACnE,WAAK,iBAAiB,MAAY;AAAE,aAAK,WAAW,QAAQ,EAAE;AAAA,MAAG;AACjE,WAAK,iBAAiB,MAAM;AAC1B,aAAK,cAAc,QAAQ;AAC3B,aAAK,KAAK,OAAO;AAAA,MACnB;AACA,cAAQ,GAAG,WAAW,KAAK,eAAe;AAC1C,cAAQ,GAAG,UAAU,KAAK,cAAc;AACxC,cAAQ,GAAG,UAAU,KAAK,cAAc;AAAA,IAC1C;AAEA,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,WAAW,GAA0B;AACnC,SAAK,kBAAkB,KAAK,CAAC;AAAA,EAC/B;AAAA,EAEA,MAAM,SAAS,QAAmD;AAChE,QAAI,KAAK,WAAW,aAAa,KAAK,WAAW,iBAAiB;AAChE;AAAA,IACF;AACA,QAAI,KAAK,WAAW,WAAW;AAC7B,YAAM,IAAI,MAAM,sCAAsC,KAAK,MAAM,uBAAuB;AAAA,IAC1F;AAEA,QAAI,KAAK,qBAAqB;AAC5B;AAAA,IACF;AACA,SAAK,sBAAsB;AAE3B,SAAK,SAAS;AAEd,UAAM,WAAW,CAAC,GAAG,KAAK,iBAAiB,EAAE,QAAQ;AACrD,eAAW,EAAE,MAAM,QAAQ,KAAK,UAAU;AACxC,UAAI;AACF,cAAM,QAAQ;AAAA,MAChB,SAAS,KAAc;AACrB,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,gBAAQ,IAAI,qCAAqC,IAAI,aAAa,GAAG,EAAE;AAAA,MACzE;AAAA,IACF;AAEA,QAAI;AACF,MAAG,UAAO,KAAK,UAAU,EAAE,OAAO,KAAK,CAAC;AAAA,IAC1C,QAAQ;AAAA,IAER;AAEA,QAAI,KAAK,wBAAwB;AAC/B,UAAI,KAAK,gBAAiB,SAAQ,IAAI,WAAW,KAAK,eAAe;AACrE,UAAI,KAAK,eAAgB,SAAQ,IAAI,UAAU,KAAK,cAAc;AAClE,UAAI,KAAK,eAAgB,SAAQ,IAAI,UAAU,KAAK,cAAc;AAClE,WAAK,kBAAkB;AACvB,WAAK,iBAAiB;AACtB,WAAK,iBAAiB;AAAA,IACxB;AAEA,SAAK,SAAS;AACd,YAAQ,IAAI,mCAAmC,UAAU,QAAQ,GAAG;AAAA,EACtE;AAAA,EAEA,MAAM,SAAwB;AAC5B,YAAQ,IAAI,yDAAoD;AAAA,EAClE;AAAA,EAEA,OAAO,UAAU,SAA0B;AACzC,QAAI,CAAI,cAAW,OAAO,GAAG;AAC3B,aAAO;AAAA,IACT;AACA,QAAI;AACF,YAAM,MAAS,gBAAa,SAAS,OAAO,EAAE,KAAK;AACnD,YAAM,MAAM,SAAS,KAAK,EAAE;AAC5B,UAAI,MAAM,GAAG,KAAK,OAAO,GAAG;AAC1B,eAAO;AAAA,MACT;AACA,cAAQ,KAAK,KAAK,CAAC;AACnB,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,OAAO,oBAAoB,SAA0B;AACnD,QAAI,eAAc,UAAU,OAAO,GAAG;AACpC,aAAO;AAAA,IACT;AACA,QAAI;AACF,MAAG,UAAO,SAAS,EAAE,OAAO,KAAK,CAAC;AAClC,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,kBAAwB;AAC9B,QAAI;AACJ,QAAI,eAAe;AAEnB,UAAM,gBAAgB,MAAc;AAClC,aAAU;AAAA,QACR,KAAK;AAAA,QACL,YAAY,WAAW,YAAY,UAAU,YAAY;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,WAAK,cAAc;AAAA,IACrB,SAAS,KAAK;AACZ,YAAM,IAAI;AACV,UAAI,EAAE,SAAS,SAAU,OAAM;AAG/B,UAAI,eAAc,UAAU,KAAK,QAAQ,GAAG;AAC1C,cAAM,MAAM,KAAK,iBAAiB,KAAK,QAAQ,KAAK;AACpD,cAAM,IAAI,0BAA0B,KAAK,KAAK,QAAQ;AAAA,MACxD;AAGA,MAAG,UAAO,KAAK,UAAU,EAAE,OAAO,KAAK,CAAC;AACxC,qBAAe;AAEf,UAAI;AACF,aAAK,cAAc;AAAA,MACrB,SAAS,UAAU;AACjB,cAAM,KAAK;AACX,YAAI,GAAG,SAAS,UAAU;AAExB,cAAI,eAAc,UAAU,KAAK,QAAQ,GAAG;AAC1C,kBAAM,MAAM,KAAK,iBAAiB,KAAK,QAAQ,KAAK;AACpD,kBAAM,IAAI,0BAA0B,KAAK,KAAK,QAAQ;AAAA,UACxD;AACA,gBAAM,IAAI,MAAM,oBAAoB,KAAK,QAAQ,eAAe;AAAA,QAClE;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAEA,QAAI;AACF,MAAG,aAAU,IAAI,OAAO,QAAQ,GAAG,CAAC;AAAA,IACtC,UAAE;AACA,MAAG,aAAU,EAAE;AAAA,IACjB;AAEA,QAAI,cAAc;AAChB,cAAQ,IAAI,wCAAwC;AAAA,IACtD;AAAA,EACF;AAAA,EAEQ,cAAc,QAAsB;AAC1C,SAAK,eAAe,KAAK,EAAE,QAAQ,IAAI,KAAK,IAAI,EAAE,CAAC;AAAA,EACrD;AAAA,EAEQ,iBAAiB,SAAgC;AACvD,QAAI;AACF,YAAM,MAAS,gBAAa,SAAS,OAAO,EAAE,KAAK;AACnD,YAAM,MAAM,SAAS,KAAK,EAAE;AAC5B,aAAO,MAAM,GAAG,KAAK,OAAO,IAAI,OAAO;AAAA,IACzC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACnNA,SAAS,aAAa,OAAe,SAA0B;AAC7D,MAAI,YAAY,KAAK;AACnB,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,SAAS,IAAI,GAAG;AAC1B,UAAM,SAAS,QAAQ,MAAM,GAAG,EAAE;AAClC,WAAO,MAAM,WAAW,MAAM;AAAA,EAChC;AACA,SAAO,UAAU;AACnB;AAMO,IAAM,WAAN,MAAe;AAAA,EACH,eAAe,oBAAI,IAA6B;AAAA,EACzD,eAAe;AAAA,EACf,kBAAkB;AAAA,EACT;AAAA,EACA;AAAA,EAEjB,YAAY,MAAwB;AAClC,SAAK,iBAAiB,MAAM,sBAAsB;AAClD,SAAK,WAAW,MAAM,sBAAsB,CAAC,QAAQ;AACnD,cAAQ,OAAO;AAAA,QACb,gCAAgC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,QACE,OACA,SACA,MACM;AACN,UAAM,MAAM,KAAK,IAAI;AACrB,SAAK,eAAe,KAAK,IAAI,KAAK,eAAe,GAAG,GAAG;AAEvD,UAAM,WAAgC,EAAE,OAAO,IAAI,KAAK,cAAc,QAAQ;AAC9E,QAAI,MAAM,WAAW,OAAW,CAAC,SAAiC,SAAS,KAAK;AAChF,QAAI,MAAM,cAAc,OAAW,CAAC,SAAiC,YAAY,KAAK;AAEtF,SAAK;AAEL,eAAW,SAAS,KAAK,aAAa,OAAO,GAAG;AAC9C,UAAI,aAAa,OAAO,MAAM,OAAO,GAAG;AACtC,cAAM,MAAM,KAAK,QAA+B;AAEhD,YAAI,MAAM,MAAM,UAAU,KAAK,gBAAgB;AAC7C,kBAAQ,OAAO;AAAA,YACb,0BAA0B,MAAM,aAAa,EAAE,aAAa,MAAM,MAAM,MAAM;AAAA;AAAA,UAChF;AAAA,QACF;AAAA,MACF;AAEA,WAAK,OAAO,KAAK;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,UACE,OACA,SACc;AACd,UAAM,KAAK,OAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC;AAEnE,UAAM,eAA6B;AAAA,MACjC;AAAA,MACA,SAAS;AAAA,MACT,aAAa,MAAM;AACjB,aAAK,aAAa,OAAO,EAAE;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,QAAyB;AAAA,MAC7B;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA,OAAO,CAAC;AAAA,MACR,UAAU;AAAA,IACZ;AAEA,SAAK,aAAa,IAAI,IAAI,KAAK;AAC/B,WAAO;AAAA,EACT;AAAA,EAEA,iBAAuB;AACrB,SAAK,aAAa,MAAM;AAAA,EAC1B;AAAA,EAEA,IAAI,kBAA0B;AAC5B,WAAO,KAAK,aAAa;AAAA,EAC3B;AAAA,EAEA,IAAI,iBAAyB;AAC3B,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,OAAO,OAA8B;AAC3C,QAAI,MAAM,UAAU;AAClB;AAAA,IACF;AAEA,UAAM,WAAW;AAEjB,UAAM,OAAO,YAAY;AACvB,aAAO,MAAM,MAAM,SAAS,GAAG;AAC7B,cAAM,KAAK,MAAM,MAAM,MAAM;AAC7B,YAAI;AACF,gBAAM,MAAM,QAAQ,EAAE;AAAA,QACxB,SAAS,KAAc;AACrB,eAAK,SAAS,KAAK,MAAM,cAAc,EAAE;AAAA,QAC3C;AAAA,MACF;AACA,YAAM,WAAW;AAAA,IACnB;AAEA,SAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,cAAQ,OAAO,MAAM,2BAA2B,GAAG;AAAA,CAAI;AAAA,IACzD,CAAC;AAAA,EACH;AACF;;;ACvMA,YAAY,QAAQ;AAkFpB,IAAM,eAAe;AAMd,IAAM,kBAAN,MAAsB;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU,oBAAI,IAAwB;AAAA,EAEvD,YAAY,MAAyB;AACnC,SAAK,OAAO,KAAK;AACjB,SAAK,mBAAmB,KAAK,yBAAyB;AACtD,SAAK,qBAAqB,KAAK,qBAAqB;AACpD,SAAK,iBAAiB,KAAK,iBAAiB;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,YAAmC;AAC1C,QAAI,KAAK,QAAQ,IAAI,WAAW,EAAE,GAAG;AACnC,YAAM,IAAI,MAAM,UAAU,WAAW,EAAE,yBAAyB;AAAA,IAClE;AACA,UAAM,QAAoB;AAAA,MACxB;AAAA,MACA,QAAQ;AAAA,QACN,IAAI,WAAW;AAAA,QACf,OAAO;AAAA,QACP,UAAU;AAAA,MACZ;AAAA,MACA,OAAO;AAAA,MACP,2BAA2B;AAAA,IAC7B;AACA,SAAK,QAAQ,IAAI,WAAW,IAAI,KAAK;AACrC,SAAK,SAAS,oBAAoB,EAAE,IAAI,WAAW,GAAG,CAAC;AAAA,EACzD;AAAA,EAEA,MAAM,WAAW,IAA2B;AAC1C,UAAM,QAAQ,KAAK,SAAS,EAAE;AAC9B,UAAM,EAAE,MAAM,IAAI,MAAM;AACxB,QAAI,UAAU,gBAAgB,UAAU,aAAa,UAAU,UAAU;AACvE,YAAM,KAAK,KAAK,IAAI,YAAY;AAAA,IAClC;AACA,SAAK,QAAQ,OAAO,EAAE;AAAA,EACxB;AAAA,EAEA,MAAM,MAAM,IAA2B;AACrC,UAAM,QAAQ,KAAK,SAAS,EAAE;AAC9B,QAAI,MAAM,OAAO,UAAU,cAAc;AACvC,YAAM,IAAI;AAAA,QACR,UAAU,EAAE,uDAAuD,MAAM,OAAO,KAAK;AAAA,MACvF;AAAA,IACF;AACA,UAAM,KAAK,SAAS,KAAK;AAAA,EAC3B;AAAA,EAEA,MAAM,KAAK,IAAY,QAAgC;AACrD,UAAM,QAAQ,KAAK,SAAS,EAAE;AAC9B,UAAM,EAAE,MAAM,IAAI,MAAM;AAGxB,SAAK,eAAe,KAAK;AACzB,SAAK,WAAW,KAAK;AAErB,QAAI,UAAU,aAAa,UAAU,gBAAgB,UAAU,UAAU;AACvE,YAAM,OAAO,QAAQ;AACrB;AAAA,IACF;AAEA,UAAM,OAAO,QAAQ;AACrB,SAAK,SAAS,kBAAkB,EAAE,IAAI,OAAO,CAAC;AAE9C,QAAI,MAAM,SAAS,MAAM,OAAO;AAC9B,YAAM,KAAK,WAAW,KAAK;AAAA,IAC7B,WAAW,CAAC,MAAM,SAAS,MAAM,OAAO,QAAQ,QAAW;AAEzD,UAAI;AACF,gBAAQ,KAAK,MAAM,OAAO,KAAK,SAAS;AAAA,MAC1C,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,OAAO,QAAQ;AACrB,UAAM,OAAO,MAAM;AACnB,UAAM,QAAQ;AACd,SAAK,SAAS,iBAAiB,EAAE,GAAG,CAAC;AAAA,EACvC;AAAA,EAEA,MAAM,QAAQ,IAA2B;AACvC,UAAM,QAAQ,KAAK,SAAS,EAAE;AAC9B,SAAK,eAAe,KAAK;AACzB,SAAK,WAAW,KAAK;AAErB,QAAI,MAAM,OAAO;AACf,YAAM,KAAK,WAAW,KAAK;AAC3B,YAAM,QAAQ;AAAA,IAChB;AAEA,UAAM,OAAO,QAAQ;AACrB,UAAM,OAAO,WAAW;AACxB,UAAM,KAAK,SAAS,KAAK;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,IAAY,KAA4B;AACnD,UAAM,QAAQ,KAAK,SAAS,EAAE;AAE9B,UAAM,QAAQ;AACd,UAAM,OAAO,MAAM;AACnB,UAAM,OAAO,QAAQ;AACrB,UAAM,OAAO,YAAY,KAAK,IAAI;AAClC,UAAM,eAAe,MAAM,OAAO;AAElC,SAAK,SAAS,iBAAiB,EAAE,IAAI,IAAI,CAAC;AAC1C,SAAK,YAAY,KAAK;AAItB,SAAK,cAAc,KAAK;AAAA,EAC1B;AAAA,EAEA,IAAI,IAAqC;AACvC,UAAM,QAAQ,KAAK,QAAQ,IAAI,EAAE;AACjC,WAAO,QAAQ,EAAE,GAAG,MAAM,OAAO,IAAI;AAAA,EACvC;AAAA,EAEA,OAAsB;AACpB,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE;AAAA,EACvE;AAAA,EAEA,MAAM,WAA0B;AAC9B,UAAM,MAAM,MAAM,KAAK,KAAK,QAAQ,KAAK,CAAC;AAC1C,UAAM,QAAQ,IAAI,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,IAAI,UAAU,EAAE,MAAM,MAAM,MAAS,CAAC,CAAC;AACnF,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,SAAS,OAAkC;AACvD,UAAM,EAAE,YAAY,OAAO,IAAI;AAC/B,UAAM,KAAK,WAAW;AAEtB,WAAO,QAAQ;AACf,UAAM,4BAA4B;AAClC,SAAK,SAAS,kBAAkB,EAAE,GAAG,CAAC;AAEtC,QAAI;AACJ,QAAI;AACF,cAAW,SAAM,WAAW,SAAS,WAAW,QAAQ,CAAC,GAAG;AAAA,QAC1D,KAAK,WAAW;AAAA,QAChB,KAAK,WAAW;AAAA,QAChB,OAAO;AAAA,MACT,CAAC;AAAA,IACH,SAAS,KAAc;AACrB,YAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC9D,aAAO,QAAQ;AACf,WAAK,SAAS,iBAAiB,EAAE,IAAI,OAAO,CAAC;AAC7C,WAAK,iBAAiB,KAAK;AAC3B;AAAA,IACF;AAEA,UAAM,QAAQ;AACd,UAAM,QAAQ;AACd,WAAO,MAAM,MAAM;AACnB,WAAO,YAAY,KAAK,IAAI;AAC5B,UAAM,eAAe,OAAO;AAG5B,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC1C,YAAM,OAAO,MAAM,SAAS,MAAM,EAAE,MAAM,GAAG,YAAY;AACzD,WAAK,SAAS,gBAAgB,EAAE,IAAI,KAAK,CAAC;AAAA,IAC5C,CAAC;AACD,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC1C,YAAM,OAAO,MAAM,SAAS,MAAM,EAAE,MAAM,GAAG,YAAY;AACzD,WAAK,SAAS,gBAAgB,EAAE,IAAI,KAAK,CAAC;AAAA,IAC5C,CAAC;AAGD,UAAM,KAAK,SAAS,CAAC,QAAQ;AAC3B,UAAI,OAAO,UAAU,cAAc,OAAO,UAAU,UAAW;AAC/D,aAAO,QAAQ;AACf,WAAK,SAAS,iBAAiB,EAAE,IAAI,QAAQ,IAAI,QAAQ,CAAC;AAC1D,WAAK,WAAW,KAAK;AACrB,YAAM,QAAQ;AACd,WAAK,iBAAiB,KAAK;AAAA,IAC7B,CAAC;AAED,UAAM,KAAK,QAAQ,CAAC,MAAM,WAAW;AACnC,UAAI,OAAO,UAAU,cAAc,OAAO,UAAU,UAAW;AAC/D,WAAK,WAAW,KAAK;AACrB,YAAM,QAAQ;AACd,aAAO,eAAe,QAAQ;AAC9B,aAAO,aAAa;AACpB,aAAO,MAAM;AACb,WAAK,SAAS,gBAAgB,EAAE,IAAI,MAAM,OAAO,CAAC;AAClD,WAAK,aAAa,KAAK;AAAA,IACzB,CAAC;AAED,WAAO,QAAQ;AACf,SAAK,SAAS,iBAAiB,EAAE,IAAI,KAAK,MAAM,IAAI,CAAC;AACrD,SAAK,YAAY,KAAK;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAMQ,aAAa,OAAyB;AAC5C,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,KAAK,MAAM,WAAW;AAE5B,WAAO,QAAQ;AACf,SAAK,SAAS,iBAAiB,EAAE,IAAI,QAAQ,gBAAgB,OAAO,gBAAgB,MAAM,WAAW,OAAO,cAAc,MAAM,GAAG,CAAC;AAEpI,SAAK,iBAAiB,KAAK;AAAA,EAC7B;AAAA,EAEQ,iBAAiB,OAAyB;AAChD,UAAM,EAAE,YAAY,OAAO,IAAI;AAC/B,UAAM,KAAK,WAAW;AACtB,UAAM,MAAM,WAAW,WAAW,CAAC;AACnC,UAAM,YAAY,IAAI,aAAa;AACnC,UAAM,aAAa,IAAI,cAAc;AACrC,UAAM,QAAQ,IAAI,SAAS;AAC3B,UAAM,cAAc,IAAI,eAAe;AACvC,UAAM,eAAe,IAAI,gBAAgB;AAGzC,QAAI,MAAM,iBAAiB,QAAW;AACpC,YAAM,SAAS,KAAK,IAAI,IAAI,MAAM;AAClC,UAAI,UAAU,cAAc;AAC1B,eAAO,WAAW;AAAA,MACpB;AAAA,IACF;AAEA,QAAI,OAAO,YAAY,aAAa;AAClC,aAAO,QAAQ;AACf,WAAK,SAAS,gBAAgB,EAAE,IAAI,QAAQ,yBAAyB,WAAW,IAAI,CAAC;AACrF;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,IAAI,YAAY,KAAK,IAAI,YAAY,OAAO,QAAQ,GAAG,KAAK;AAC/E,UAAM,UAAU,OAAO,WAAW;AAClC,UAAM,gBAAgB,KAAK,IAAI,IAAI;AACnC,WAAO,gBAAgB;AACvB,WAAO,QAAQ;AACf,SAAK,SAAS,oBAAoB,EAAE,IAAI,SAAS,SAAS,MAAM,CAAC;AAEjE,UAAM,QAAQ,WAAW,YAAY;AACnC,YAAM,eAAe;AACrB,aAAO,gBAAgB;AACvB,aAAO;AACP,YAAM,KAAK,SAAS,KAAK;AAAA,IAC3B,GAAG,KAAK;AAGR,UAAM,MAAM;AACZ,UAAM,eAAe;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,WAAW,OAAkC;AACnD,UAAM,QAAQ,MAAM;AACpB,QAAI,CAAC,SAAS,MAAM,aAAa,QAAQ,MAAM,eAAe,MAAM;AAClE,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAEA,WAAO,IAAI,QAAc,CAACA,aAAY;AACpC,YAAM,OAAO,MAAY;AACvB,qBAAa,SAAS;AACtB,QAAAA,SAAQ;AAAA,MACV;AAEA,YAAM,KAAK,QAAQ,IAAI;AAEvB,UAAI;AACF,cAAM,KAAK,SAAS;AAAA,MACtB,QAAQ;AAEN,aAAK;AACL;AAAA,MACF;AAEA,YAAM,YAAY,WAAW,MAAM;AACjC,YAAI;AACF,gBAAM,KAAK,SAAS;AAAA,QACtB,QAAQ;AAAA,QAER;AAAA,MACF,GAAG,KAAK,cAAc;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EAEQ,eAAe,OAAyB;AAC9C,QAAI,MAAM,iBAAiB,QAAW;AACpC,mBAAa,MAAM,YAAY;AAC/B,YAAM,eAAe;AACrB,YAAM,OAAO,gBAAgB;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,OAAyB;AAC3C,QAAI,CAAC,MAAM,WAAW,YAAa;AACnC,SAAK,WAAW,KAAK;AAErB,UAAM,WAAW,YAAY,YAAY;AACvC,YAAM,KAAK,UAAU,KAAK;AAAA,IAC5B,GAAG,KAAK,gBAAgB;AAExB,aAAS,MAAM;AACf,UAAM,gBAAgB;AAAA,EACxB;AAAA,EAEQ,WAAW,OAAyB;AAC1C,QAAI,MAAM,kBAAkB,QAAW;AACrC,oBAAc,MAAM,aAAa;AACjC,YAAM,gBAAgB;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAc,UAAU,OAAkC;AACxD,UAAM,EAAE,QAAQ,WAAW,IAAI;AAC/B,QAAI,CAAC,WAAW,YAAa;AAC7B,QAAI,OAAO,UAAU,aAAa,OAAO,UAAU,WAAY;AAE/D,QAAI,UAAU;AACd,QAAI;AAEJ,QAAI;AACF,gBAAU,MAAM,WAAW,YAAY;AAAA,IACzC,SAAS,KAAc;AACrB,gBAAU;AACV,iBAAW,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IAC5D;AAEA,QAAI,SAAS;AACX,UAAI,OAAO,UAAU,YAAY;AAE/B,cAAM,4BAA4B;AAClC,eAAO,QAAQ;AACf,eAAO,OAAO;AAAA,MAChB,OAAO;AACL,cAAM,4BAA4B;AAAA,MACpC;AAAA,IACF,OAAO;AACL,YAAM;AACN,UAAI,aAAa,QAAW;AAC1B,eAAO,kBAAkB;AAAA,MAC3B;AACA,UAAI,MAAM,6BAA6B,KAAK,oBAAoB;AAC9D,eAAO,QAAQ;AACf,aAAK,SAAS,kBAAkB,EAAE,IAAI,WAAW,IAAI,iBAAiB,OAAO,gBAAgB,CAAC;AAAA,MAChG;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,cAAc,OAAyB;AAC7C,UAAM,EAAE,QAAQ,WAAW,IAAI;AAC/B,UAAM,KAAK,WAAW;AAEtB,UAAM,OAAO,MAAY;AACvB,UAAI,OAAO,UAAU,aAAa,OAAO,UAAU,WAAY;AAC/D,YAAM,MAAM,OAAO;AACnB,UAAI,QAAQ,OAAW;AAEvB,UAAI,QAAQ;AACZ,UAAI;AACF,gBAAQ,KAAK,KAAK,CAAC;AACnB,gBAAQ;AAAA,MACV,QAAQ;AACN,gBAAQ;AAAA,MACV;AAEA,UAAI,CAAC,OAAO;AACV,aAAK,WAAW,KAAK;AACrB,eAAO,QAAQ;AACf,eAAO,MAAM;AACb,aAAK,SAAS,gBAAgB,EAAE,IAAI,MAAM,MAAM,QAAQ,KAAK,CAAC;AAE9D;AAAA,MACF;AAGA,YAAMC,KAAI,WAAW,MAAM,GAAI;AAC/B,MAAAA,GAAE,MAAM;AAAA,IACV;AAEA,UAAM,IAAI,WAAW,MAAM,GAAI;AAC/B,MAAE,MAAM;AAAA,EACV;AAAA;AAAA;AAAA;AAAA,EAMQ,SAAS,IAAwB;AACvC,UAAM,QAAQ,KAAK,QAAQ,IAAI,EAAE;AACjC,QAAI,CAAC,MAAO,OAAM,IAAI,MAAM,UAAU,EAAE,aAAa;AACrD,WAAO;AAAA,EACT;AAAA,EAEQ,SAAS,OAAe,SAAwC;AACtE,SAAK,KAAK,QAAQ,OAAO,SAAS,EAAE,QAAQ,aAAa,CAAC;AAAA,EAC5D;AACF;;;AC9fA,YAAY,UAAU;;;ACSf,IAAM,iBAAiB,KAAK,OAAO;AAMnC,SAAS,SAAS,KAA0B,QAAgB,MAAqB;AACtF,QAAM,OAAO,KAAK,UAAU,IAAI;AAChC,MAAI,UAAU,QAAQ;AAAA,IACpB,gBAAgB;AAAA,IAChB,kBAAkB,OAAO,WAAW,IAAI;AAAA,EAC1C,CAAC;AACD,MAAI,IAAI,IAAI;AACd;AAMO,SAAS,SAAS,KAA2B,WAAmB,gBAAiC;AACtG,SAAO,IAAI,QAAgB,CAACC,UAAS,WAAW;AAC9C,UAAM,SAAmB,CAAC;AAC1B,QAAI,QAAQ;AACZ,QAAI,UAAU;AAEd,QAAI,GAAG,QAAQ,CAAC,UAAkB;AAChC,UAAI,QAAS;AACb,eAAS,MAAM;AACf,UAAI,QAAQ,UAAU;AACpB,kBAAU;AAIV,YAAI,OAAO;AAEX,qBAAa,MAAM,IAAI,QAAQ,IAAI,MAAM,gBAAgB,CAAC,CAAC;AAC3D,eAAO,OAAO,OAAO,IAAI,MAAM,gBAAgB,GAAG,EAAE,MAAM,cAAc,CAAC,CAAC;AAC1E;AAAA,MACF;AACA,aAAO,KAAK,KAAK;AAAA,IACnB,CAAC;AACD,QAAI,GAAG,OAAO,MAAM;AAClB,UAAI,CAAC,SAAS;AACZ,kBAAU;AACV,QAAAA,SAAQ,OAAO,OAAO,MAAM,CAAC;AAAA,MAC/B;AAAA,IACF,CAAC;AACD,QAAI,GAAG,SAAS,CAAC,QAAQ;AACvB,UAAI,CAAC,SAAS;AACZ,kBAAU;AACV,eAAO,GAAG;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAMO,SAAS,UAAU,KAAsB;AAC9C,MAAI;AACF,WAAO,KAAK,MAAM,IAAI,SAAS,MAAM,CAAC;AAAA,EACxC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,cAAc,KAA+C;AAC3E,QAAM,OAAO,IAAI,QAAQ,eAAe;AACxC,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,KAAK,WAAW,SAAS,EAAG,QAAO,KAAK,MAAM,CAAC;AACnD,SAAO;AACT;AAMO,SAAS,aAAa,OAAe,SAA0B;AACpE,MAAI,YAAY,IAAK,QAAO;AAC5B,MAAI,QAAQ,SAAS,IAAI,GAAG;AAC1B,UAAM,SAAS,QAAQ,MAAM,GAAG,EAAE;AAClC,WAAO,MAAM,WAAW,MAAM;AAAA,EAChC;AACA,SAAO,UAAU;AACnB;;;AC7FO,IAAM,mBAAmB;AACzB,IAAM,kBAAkB;AAOxB,SAAS,UACd,KACA,KACA,KACA,MACM;AACN,MAAI,KAAK,WAAW,QAAQ,iBAAiB;AAC3C,aAAS,KAAK,KAAK,EAAE,OAAO,uBAAuB,CAAC;AACpD;AAAA,EACF;AAEA,QAAM,cAAc,IAAI,aAAa,IAAI,QAAQ,KAAK;AACtD,QAAM,WAAW,YACd,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAE7B,MAAI,UAAU,KAAK;AAAA,IACjB,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,cAAc;AAAA,EAChB,CAAC;AACD,MAAI,aAAa;AAEjB,OAAK,WAAW,IAAI,GAAG;AAGvB,QAAM,OAAO,CAAC,aAAqC;AACjD,QAAI,IAAI,cAAe;AACvB,QAAI,MAAM,SAAS,KAAK,UAAU,QAAQ,CAAC;AAAA;AAAA,CAAM;AAAA,EACnD;AAGA,QAAM,OAAO,SAAS;AAAA,IAAI,CAAC,YACzB,KAAK,IAAI,UAAU,SAAS,CAAC,OAAO;AAClC,UAAI,SAAS,KAAK,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC,CAAC,GAAG;AACnD,aAAK,EAAE;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACH;AAGA,QAAM,YAAY,YAAY,MAAM;AAClC,QAAI,CAAC,IAAI,eAAe;AACtB,UAAI,MAAM,iBAAiB;AAAA,IAC7B;AAAA,EACF,GAAG,gBAAgB;AACnB,YAAU,MAAM;AAEhB,QAAM,UAAU,MAAY;AAC1B,kBAAc,SAAS;AACvB,eAAW,OAAO,KAAM,KAAI,YAAY;AACxC,SAAK,WAAW,OAAO,GAAG;AAAA,EAC5B;AAEA,MAAI,GAAG,SAAS,OAAO;AACvB,MAAI,GAAG,SAAS,OAAO;AACzB;;;AChEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA4BA,SAAS,eACd,KACA,aACA,QACe;AACf,MAAI,WAAW,MAAM;AAEnB,QAAI,gBAAgB,UAAa,gBAAgB,OAAO,SAAS;AAC/D,eAAS,KAAK,KAAK;AAAA,QACjB,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AACD,aAAO;AAAA,IACT;AACA,WAAO,OAAO;AAAA,EAChB;AAEA,MAAI,gBAAgB,UAAa,gBAAgB,IAAI;AACnD,aAAS,KAAK,KAAK,EAAE,OAAO,mBAAmB,CAAC;AAChD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAMA,SAAS,SACP,MACA,SACA,WACuB;AACvB,MAAI,CAAC,KAAK,kBAAmB,QAAO;AACpC,QAAM,MAAM,KAAK,kBAAkB,EAAE,SAAS,UAAU,CAAC;AACzD,MAAI,CAAC,IAAK,QAAO;AAEjB,SAAO,EAAE,GAAG,KAAK,UAAU,OAAO;AACpC;AAMO,SAAS,WAAW,KAA0B,KAAoB;AACvE,MAAI,eAAe,cAAc;AAC/B,aAAS,KAAK,KAAK,EAAE,OAAO,YAAY,SAAU,IAAc,QAAQ,CAAC;AACzE;AAAA,EACF;AACA,MAAI,eAAe,qBAAqB;AACtC,aAAS,KAAK,KAAK,EAAE,OAAO,mBAAmB,SAAU,IAAc,QAAQ,CAAC;AAChF;AAAA,EACF;AACA,MAAI,eAAe,uBAAuB;AACxC,aAAS,KAAK,KAAK,EAAE,OAAO,qBAAqB,SAAU,IAAc,QAAQ,CAAC;AAClF;AAAA,EACF;AACA,MACE,eAAe,SACf,UAAU,OACT,IAA8B,SAAS,UACxC;AACA,aAAS,KAAK,KAAK,EAAE,OAAO,aAAa,SAAU,IAAc,QAAQ,CAAC;AAC1E;AAAA,EACF;AACA,QAAM,OAAO,eAAe,QAAQ,IAAI,OAAO;AAC/C,QAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAS,KAAK,KAAK,EAAE,OAAO,MAAM,QAAQ,CAAC;AAC7C;AAOA,eAAe,wBACb,KACA,KACA,QACkC;AAClC,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,SAAS,GAAG;AAAA,EAC1B,SAAS,KAAc;AACrB,QAAI,eAAe,SAAU,IAAkC,SAAS,eAAe;AACrF,eAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,KAAK,KAAK,OAAO,KAAK,CAAC;AACrE,aAAO;AAAA,IACT;AACA,aAAS,KAAK,KAAK,EAAE,OAAO,aAAa,CAAC;AAC1C,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,UAAU,GAAG;AAC5B,MAAI,WAAW,QAAW;AACxB,aAAS,KAAK,KAAK,EAAE,OAAO,WAAW,CAAC;AACxC,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAChB,QAAM,cAAc,OAAO,QAAQ,SAAS,MAAM,WAAW,QAAQ,SAAS,IAAI;AAClF,QAAM,UAAU,eAAe,KAAK,aAAa,MAAM;AACvD,MAAI,YAAY,KAAM,QAAO;AAE7B,SAAO,CAAC,KAAK,OAAO;AACtB;AAMA,eAAsB,aACpB,KACA,KACA,MACA,QACe;AACf,QAAM,OAAO,MAAM,wBAAwB,KAAK,KAAK,MAAM;AAC3D,MAAI,SAAS,KAAM;AACnB,QAAM,CAAC,KAAK,OAAO,IAAI;AAEvB,QAAM,OAAO,UAAU,GAAG;AAC1B,QAAM,MAAM,SAAS,MAAM,SAAS,KAAK,SAAS;AAClD,MAAI,CAAC,KAAK;AAAE,aAAS,KAAK,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAG;AAAA,EAAQ;AAEhF,MAAI;AACF,UAAM,SAAS,MAAM,OAAO,KAAK,EAAE,MAAM,KAAK,MAAM,QAAQ,KAAK,QAAQ,OAAO,KAAK,MAAM,CAAC;AAC5F,aAAS,KAAK,KAAK,MAAM;AAAA,EAC3B,SAAS,KAAK;AACZ,eAAW,KAAK,GAAG;AAAA,EACrB;AACF;AAEA,eAAsB,cACpB,KACA,KACA,MACA,QACe;AACf,QAAM,OAAO,MAAM,wBAAwB,KAAK,KAAK,MAAM;AAC3D,MAAI,SAAS,KAAM;AACnB,QAAM,CAAC,KAAK,OAAO,IAAI;AAEvB,QAAM,OAAO,UAAU,GAAG;AAC1B,QAAM,MAAM,SAAS,MAAM,SAAS,KAAK,SAAS;AAClD,MAAI,CAAC,KAAK;AAAE,aAAS,KAAK,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAG;AAAA,EAAQ;AAEhF,MAAI;AACF,UAAM,SAAS,MAAM,QAAQ,KAAK,EAAE,MAAM,KAAK,MAAM,SAAS,KAAK,SAAS,UAAU,KAAK,SAAS,CAAC;AACrG,aAAS,KAAK,KAAK,MAAM;AAAA,EAC3B,SAAS,KAAK;AACZ,eAAW,KAAK,GAAG;AAAA,EACrB;AACF;AAEA,eAAsB,eACpB,KACA,KACA,MACA,QACe;AACf,QAAM,OAAO,MAAM,wBAAwB,KAAK,KAAK,MAAM;AAC3D,MAAI,SAAS,KAAM;AACnB,QAAM,CAAC,KAAK,OAAO,IAAI;AAEvB,QAAM,OAAO,UAAU,GAAG;AAC1B,QAAM,MAAM,SAAS,MAAM,SAAS,KAAK,SAAS;AAClD,MAAI,CAAC,KAAK;AAAE,aAAS,KAAK,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAG;AAAA,EAAQ;AAEhF,MAAI;AACF,UAAM,SAAS,MAAM,SAAS,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;AACtD,aAAS,KAAK,KAAK,MAAM;AAAA,EAC3B,SAAS,KAAK;AACZ,eAAW,KAAK,GAAG;AAAA,EACrB;AACF;AAEA,eAAsB,aACpB,KACA,KACA,MACA,QACe;AACf,QAAM,OAAO,MAAM,wBAAwB,KAAK,KAAK,MAAM;AAC3D,MAAI,SAAS,KAAM;AACnB,QAAM,CAAC,KAAK,OAAO,IAAI;AAEvB,QAAM,OAAO,UAAU,GAAG;AAO1B,QAAM,MAAM,SAAS,MAAM,SAAS,KAAK,SAAS;AAClD,MAAI,CAAC,KAAK;AAAE,aAAS,KAAK,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAG;AAAA,EAAQ;AAEhF,MAAI;AACF,UAAM,SAAS,MAAM,OAAO,KAAK;AAAA,MAC/B,MAAM,KAAK;AAAA,MACX,WAAW,KAAK;AAAA,MAChB,WAAW,KAAK;AAAA,MAChB,YAAY,KAAK;AAAA,IACnB,CAAC;AACD,aAAS,KAAK,KAAK,MAAM;AAAA,EAC3B,SAAS,KAAK;AACZ,eAAW,KAAK,GAAG;AAAA,EACrB;AACF;AAEA,eAAsB,aACpB,KACA,KACA,MACA,QACe;AACf,QAAM,OAAO,MAAM,wBAAwB,KAAK,KAAK,MAAM;AAC3D,MAAI,SAAS,KAAM;AACnB,QAAM,CAAC,KAAK,OAAO,IAAI;AAEvB,QAAM,OAAO,UAAU,GAAG;AAC1B,QAAM,MAAM,SAAS,MAAM,SAAS,KAAK,SAAS;AAClD,MAAI,CAAC,KAAK;AAAE,aAAS,KAAK,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAG;AAAA,EAAQ;AAEhF,MAAI;AACF,UAAM,SAAS,MAAM,OAAO,KAAK,EAAE,MAAM,KAAK,MAAM,UAAU,KAAK,SAAS,CAAC;AAC7E,aAAS,KAAK,KAAK,MAAM;AAAA,EAC3B,SAAS,KAAK;AACZ,eAAW,KAAK,GAAG;AAAA,EACrB;AACF;AAEA,eAAsB,eACpB,KACA,KACA,MACA,QACe;AACf,QAAM,OAAO,MAAM,wBAAwB,KAAK,KAAK,MAAM;AAC3D,MAAI,SAAS,KAAM;AACnB,QAAM,CAAC,KAAK,OAAO,IAAI;AAEvB,QAAM,OAAO,UAAU,GAAG;AAC1B,QAAM,MAAM,SAAS,MAAM,SAAS,KAAK,SAAS;AAClD,MAAI,CAAC,KAAK;AAAE,aAAS,KAAK,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAAG;AAAA,EAAQ;AAEhF,MAAI;AACF,UAAM,SAAS,MAAM,SAAS,KAAK,EAAE,OAAO,KAAK,OAAO,MAAM,KAAK,MAAM,MAAM,KAAK,KAAK,CAAC;AAC1F,aAAS,KAAK,KAAK,MAAM;AAAA,EAC3B,SAAS,KAAK;AACZ,eAAW,KAAK,GAAG;AAAA,EACrB;AACF;;;ACpRA,eAAe,eACb,KACA,KACwB;AACxB,MAAI;AACF,WAAO,MAAM,SAAS,GAAG;AAAA,EAC3B,SAAS,KAAc;AACrB,QAAI,eAAe,SAAU,IAAkC,SAAS,eAAe;AACrF,eAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,KAAK,KAAK,OAAO,KAAK,CAAC;AACrE,aAAO;AAAA,IACT;AACA,aAAS,KAAK,KAAK,EAAE,OAAO,aAAa,CAAC;AAC1C,WAAO;AAAA,EACT;AACF;AAMO,SAAS,gBAAgB,KAA0B,MAA6B;AACrF,WAAS,KAAK,KAAK,EAAE,QAAQ,KAAK,WAAW,KAAK,EAAE,CAAC;AACvD;AAEO,SAAS,eAAe,KAA0B,IAAY,MAA6B;AAChG,QAAM,SAAkC,KAAK,WAAW,IAAI,EAAE;AAC9D,MAAI,WAAW,QAAW;AACxB,aAAS,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;AACzC;AAAA,EACF;AACA,WAAS,KAAK,KAAK,MAAM;AAC3B;AAEA,eAAsB,oBACpB,KACA,KACA,MACe;AACf,QAAM,MAAM,MAAM,eAAe,KAAK,GAAG;AACzC,MAAI,QAAQ,KAAM;AAClB,QAAM,OAAO,IAAI,SAAS,IAAI,UAAU,GAAG,IAAI;AAC/C,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,aAAS,KAAK,KAAK,EAAE,OAAO,WAAW,CAAC;AACxC;AAAA,EACF;AAEA,QAAM,QAAQ;AACd,QAAM,KAAK,OAAO,MAAM,IAAI,MAAM,WAAW,MAAM,IAAI,IAAI;AAC3D,QAAM,OAAO,OAAO,MAAM,MAAM,MAAM,WAAW,MAAM,MAAM,IAAI;AACjE,QAAM,UAAU,OAAO,MAAM,SAAS,MAAM,WAAW,MAAM,SAAS,IAAI;AAC1E,MAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS;AAC5B,aAAS,KAAK,KAAK,EAAE,OAAO,2BAA2B,CAAC;AACxD;AAAA,EACF;AAEA,QAAM,OAAO,MAAM,QAAQ,MAAM,MAAM,CAAC,IACpC,MAAM,MAAM,EAAE,OAAO,CAAC,QAAuB,OAAO,QAAQ,QAAQ,IACpE;AACJ,QAAM,MAAM,OAAO,MAAM,KAAK,MAAM,WAAW,MAAM,KAAK,IAAI;AAC9D,QAAM,YAAY,OAAO,MAAM,WAAW,MAAM,WAAW,MAAM,WAAW,IAAI;AAEhF,MAAI;AACF,UAAM,WAAW,KAAK,WAAW,IAAI,EAAE;AACvC,QAAI,aAAa,QAAW;AAC1B,eAAS,KAAK,KAAK,EAAE,IAAI,MAAM,mBAAmB,MAAM,OAAO,SAAS,CAAC;AACzE;AAAA,IACF;AAEA,SAAK,WAAW,SAAS,EAAE,IAAI,MAAM,SAAS,MAAM,KAAK,UAAU,CAAC;AACpE,aAAS,KAAK,KAAK,EAAE,IAAI,MAAM,OAAO,KAAK,WAAW,IAAI,EAAE,EAAE,CAAC;AAAA,EACjE,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,aAAS,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,QAAQ,CAAC;AAAA,EAClD;AACF;AAEA,eAAsB,mBACpB,KACA,KACA,SACA,MACe;AACf,QAAM,MAAM,MAAM,eAAe,KAAK,GAAG;AACzC,MAAI,QAAQ,KAAM;AAClB,QAAM,OAAO,UAAU,GAAG;AAC1B,MAAI,SAAS,QAAW;AACtB,aAAS,KAAK,KAAK,EAAE,OAAO,WAAW,CAAC;AACxC;AAAA,EACF;AACA,QAAM,EAAE,MAAM,QAAQ,IAAI;AAC1B,OAAK,IAAI,QAAQ,oBAAoB,EAAE,SAAS,MAAM,QAAQ,GAAG,EAAE,QAAQ,OAAO,CAAC;AACnF,WAAS,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;AACjC;AAEA,eAAsB,gBACpB,KACA,KACA,SACA,MACe;AACf,QAAM,MAAM,MAAM,eAAe,KAAK,GAAG;AACzC,MAAI,QAAQ,KAAM;AAElB,QAAM,OAAO,IAAI,SAAS,IAAI,UAAU,GAAG,IAAI,CAAC;AAChD,QAAM,SAAU,MAA8B;AAE9C,QAAM,gBAAgB,WAAW,MAAM;AACrC,QAAI,CAAC,IAAI,aAAa;AACpB,eAAS,KAAK,KAAK;AAAA,QACjB,UAAU;AAAA,QACV,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,EACF,GAAG,GAAI;AAEP,MAAI;AACF,UAAM,KAAK,WAAW,KAAK,SAAS,MAAM;AAC1C,iBAAa,aAAa;AAC1B,QAAI,CAAC,IAAI,aAAa;AACpB,eAAS,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,IACjC;AAAA,EACF,SAAS,KAAc;AACrB,iBAAa,aAAa;AAC1B,QAAI,CAAC,IAAI,aAAa;AACpB,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,KAAK,KAAK,EAAE,OAAO,aAAa,SAAS,IAAI,CAAC;AAAA,IACzD;AAAA,EACF;AACF;AAEA,eAAsB,mBACpB,KACA,KACA,SACA,MACe;AACf,QAAM,MAAM,MAAM,eAAe,KAAK,GAAG;AACzC,MAAI,QAAQ,KAAM;AAClB,QAAM,OAAO,UAAU,GAAG;AAC1B,MAAI,SAAS,QAAW;AACtB,aAAS,KAAK,KAAK,EAAE,OAAO,WAAW,CAAC;AACxC;AAAA,EACF;AACA,QAAM,EAAE,WAAW,UAAU,MAAM,IAAI;AAKvC,OAAK,IAAI,QAAQ,sBAAsB,EAAE,SAAS,WAAW,UAAU,MAAM,GAAG,EAAE,QAAQ,OAAO,CAAC;AAClG,WAAS,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC;AACjC;;;AC1KA,YAAY,YAAY;AAsBxB,IAAM,kBAAkB;AACxB,IAAM,cAAc,KAAK;AAElB,IAAM,iBAAN,MAAqB;AAAA,EACT,SAAS,oBAAI,IAA6B;AAAA,EAE3D,YAAY,SAAS,iBAAkC;AACrD,SAAK,aAAa;AAElB,UAAM,aAAa,OAAO,SAAS,MAAM,IACrC,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,MAAM,MAAM,GAAG,WAAW,CAAC,IACrD;AACJ,UAAM,QAAe,mBAAY,EAAE,EAAE,SAAS,WAAW;AACzD,UAAM,SAA0B;AAAA,MAC9B;AAAA,MACA,KAAK,wBAAwB,mBAAmB,KAAK,CAAC;AAAA,MACtD,WAAW,KAAK,IAAI;AAAA,MACpB,WAAW,KAAK,IAAI,IAAI,aAAa;AAAA,MACrC,QAAQ;AAAA,IACV;AACA,SAAK,OAAO,IAAI,OAAO,MAAM;AAC7B,WAAO,EAAE,GAAG,OAAO;AAAA,EACrB;AAAA,EAEA,UAAU,OAAqC;AAC7C,UAAM,SAAS,KAAK,OAAO,IAAI,KAAK;AACpC,QAAI,CAAC,OAAQ,QAAO;AAEpB,UAAM,UAAU,KAAK,IAAI,IAAI,OAAO;AACpC,WAAO;AAAA,MACL,QAAQ,OAAO;AAAA,MACf;AAAA,MACA,WAAW,OAAO;AAAA,MAClB,YAAY,OAAO;AAAA,MACnB,WAAW,OAAO;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,QACE,OACA,QAKI,CAAC,GACU;AACf,UAAM,SAAS,KAAK,OAAO,IAAI,KAAK;AACpC,QAAI,CAAC,QAAQ;AACX,YAAM,OAAO,OAAO,IAAI,MAAM,yBAAyB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC3E;AACA,QAAI,KAAK,IAAI,IAAI,OAAO,WAAW;AACjC,YAAM,OAAO,OAAO,IAAI,MAAM,uBAAuB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACzE;AAEA,WAAO,SAAS;AAChB,WAAO,YAAY,MAAM,aAAa,OAAO,aAAoB,kBAAW;AAC5E,WAAO,aAAa,MAAM,cAAc,OAAO,cAAc;AAC7D,WAAO,YAAY,MAAM,aAAa,OAAO,aAAa;AAC1D,WAAO,eAAe,MAAM,gBAAgB,OAAO;AACnD,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B;AAAA,EAEA,eAAqB;AACnB,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,OAAO,MAAM,KAAK,KAAK,QAAQ;AACzC,UAAI,CAAC,OAAO,UAAU,MAAM,OAAO,WAAW;AAC5C,aAAK,OAAO,OAAO,KAAK;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AACF;;;ALnCA,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,qBAAqB;AAC3B,IAAM,gBAAgB;AAMf,IAAM,mBAAN,MAAuB;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EAEF,cAAc,oBAAI,IAAyB;AAAA,EAC3C,YAAY,oBAAI,IAAyB;AAAA,EACzC,aAAa,KAAK,IAAI;AAAA;AAAA,EAGtB,gBAAgB,oBAAI,IAA0B;AAAA,EAE/D,YAAY,MAAyB;AACnC,SAAK,QAAQ,KAAK,QAAQ;AAC1B,SAAK,QAAQ,KAAK,QAAQ;AAC1B,SAAK,OAAO,KAAK;AACjB,SAAK,cAAc,KAAK;AACxB,SAAK,iBAAiB,KAAK;AAC3B,SAAK,gBAAgB,KAAK;AAC1B,SAAK,kBAAkB,KAAK,kBAAkB,IAAI,eAAe;AACjE,SAAK,gBAAgB,KAAK;AAAA,EAC5B;AAAA,EAEA,IAAI,MAA0B;AAAE,WAAO,KAAK;AAAA,EAAM;AAAA,EAClD,IAAI,YAAqB;AAAE,WAAO,KAAK;AAAA,EAAU;AAAA;AAAA;AAAA;AAAA,EAMjD,cACE,QACAC,QACA,SACM;AACN,SAAK,cAAc,IAAI,GAAG,MAAM,IAAIA,MAAI,IAAI,OAAO;AAAA,EACrD;AAAA;AAAA,EAGA,gBAAgB,QAAgBA,QAAoB;AAClD,SAAK,cAAc,OAAO,GAAG,MAAM,IAAIA,MAAI,EAAE;AAAA,EAC/C;AAAA,EAEQ,iBAAiB,QAAgB,UAA4C;AACnF,UAAM,QAAQ,KAAK,cAAc,IAAI,GAAG,MAAM,IAAI,QAAQ,EAAE;AAC5D,QAAI,UAAU,OAAW,QAAO;AAEhC,UAAM,gBAAgB,SAAS,WAAW,UAAU,IAChD,SAAS,MAAM,UAAU,MAAM,IAC/B;AACJ,QAAI,kBAAkB,UAAU;AAC9B,YAAM,gBAAgB,KAAK,cAAc,IAAI,GAAG,MAAM,IAAI,aAAa,EAAE;AACzE,UAAI,kBAAkB,OAAW,QAAO;AAAA,IAC1C;AAEA,eAAW,CAAC,KAAK,OAAO,KAAK,KAAK,eAAe;AAC/C,YAAMC,OAAM,IAAI,QAAQ,GAAG;AAC3B,UAAIA,OAAM,KAAK,IAAI,MAAM,GAAGA,IAAG,MAAM,OAAQ;AAC7C,YAAM,YAAY,IAAI,MAAMA,OAAM,CAAC;AACnC,UAAI,UAAU,QAAQ,GAAG,IAAI,EAAG;AAChC,UAAI,aAAa,WAAW,QAAQ,KAAK,aAAa,WAAW,aAAa,GAAG;AAC/E,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA,EAKA,QAAiD;AAC/C,WAAO,IAAI,QAAwC,CAACC,UAAS,WAAW;AACtE,YAAM,SAAc,kBAAa,CAAC,KAAK,QAAQ;AAC7C,aAAK,KAAK,eAAe,KAAK,GAAG;AAAA,MACnC,CAAC;AACD,aAAO,GAAG,SAAS,MAAM;AAEzB,aAAO,GAAG,eAAe,CAAC,MAAM,WAAW;AACzC,YAAI,CAAC,OAAO,UAAW,QAAO,QAAQ;AAAA,MACxC,CAAC;AACD,aAAO,OAAO,KAAK,OAAO,KAAK,OAAO,MAAM;AAC1C,cAAM,OAAO,OAAO,QAAQ;AAC5B,YAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,iBAAO,IAAI,MAAM,gCAAgC,CAAC;AAClD;AAAA,QACF;AACA,aAAK,UAAU;AACf,aAAK,WAAW;AAChB,aAAK,OAAO,UAAU,KAAK,OAAO,IAAI,KAAK,IAAI;AAG/C,YAAI,KAAK,eAAe;AACtB,eAAK,cAAc,MAAM;AAAA,QAC3B;AAEA,QAAAA,SAAQ,EAAE,MAAM,KAAK,SAAS,MAAM,KAAK,KAAK,CAAC;AAAA,MACjD,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,KAAK,YAAoB,eAA8B;AAC3D,QAAI,CAAC,KAAK,WAAW,CAAC,KAAK,SAAU;AACrC,SAAK,WAAW;AAChB,UAAM,SAAS,KAAK;AAGpB,QAAI,KAAK,eAAe;AACtB,WAAK,cAAc,KAAK;AAAA,IAC1B;AAEA,UAAM,IAAI,QAAc,CAACA,aAAY;AACnC,YAAM,WAAW,WAAW,MAAM;AAChC,mBAAW,OAAO,KAAK,UAAW,KAAI,QAAQ;AAC9C,mBAAW,OAAO,KAAK,YAAa,KAAI,QAAQ;AAChD,aAAK,UAAU,MAAM;AACrB,aAAK,YAAY,MAAM;AACvB,QAAAA,SAAQ;AAAA,MACV,GAAG,SAAS;AACZ,eAAS,MAAM;AAEf,iBAAW,OAAO,KAAK,YAAa,KAAI,IAAI;AAC5C,WAAK,YAAY,MAAM;AAKvB,aAAO,oBAAoB;AAE3B,aAAO,MAAM,MAAM;AACjB,qBAAa,QAAQ;AACrB,QAAAA,SAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,eAAe,KAA2B,KAAyC;AAC/F,SAAK,UAAU,IAAI,GAAG;AAMtB,QAAI,GAAG,SAAS,MAAM;AAAA,IAAC,CAAC;AAExB,UAAM,gBAAgB,WAAW,MAAM;AACrC,UAAI,CAAC,IAAI,aAAa;AACpB,iBAAS,KAAK,KAAK,EAAE,OAAO,UAAU,CAAC;AAAA,MACzC,OAAO;AACL,YAAI,QAAQ;AAAA,MACd;AAAA,IACF,GAAG,kBAAkB;AAErB,QAAI,GAAG,UAAU,MAAM;AAAE,mBAAa,aAAa;AAAG,WAAK,UAAU,OAAO,GAAG;AAAA,IAAG,CAAC;AACnF,QAAI,GAAG,SAAU,MAAM;AAAE,mBAAa,aAAa;AAAG,WAAK,UAAU,OAAO,GAAG;AAAA,IAAG,CAAC;AAEnF,UAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB;AACtD,UAAM,UAAU,IAAI,UAAU,OAAO,YAAY;AACjD,UAAM,WAAW,IAAI;AAErB,QAAI;AAEF,UAAI,WAAW,SAAS,aAAa,kBAAkB;AACrD,eAAO,KAAK,cAAc,GAAG;AAAA,MAC/B;AAGA,UAAI,SAAuC;AAC3C,UAAI,KAAK,kBAAkB,UAAa,CAAC,mBAAmB,QAAQ,QAAQ,GAAG;AAC7E,cAAM,QAAQ,cAAc,GAAG;AAC/B,cAAM,WAAW,KAAK,cAAc,KAAK;AACzC,YAAI,aAAa,MAAM;AACrB,iBAAO,SAAS,KAAK,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,QACrD;AACA,iBAAS;AAAA,MACX;AAGA,YAAM,YAA6B,EAAE,YAAY,KAAK,aAAa,KAAK,KAAK,KAAK;AAClF,YAAM,SAAuB,EAAE,mBAAmB,KAAK,eAAe;AACtE,YAAM,UAAmB,EAAE,KAAK,KAAK,MAAM,YAAY,KAAK,YAAY;AAGxE,UAAI,WAAW,SAAS,aAAa,kBAAkB;AACrD,eAAO,gBAAgB,KAAK,SAAS;AAAA,MACvC;AACA,UAAI,WAAW,UAAU,aAAa,2BAA2B;AAC/D,eAAO,MAAM,oBAAoB,KAAK,KAAK,SAAS;AAAA,MACtD;AACA,YAAM,mBAAmB,SAAS,MAAM,8BAA8B;AACtE,UAAI,WAAW,SAAS,kBAAkB;AACxC,eAAO,eAAe,KAAK,iBAAiB,CAAC,GAAG,SAAS;AAAA,MAC3D;AACA,YAAM,mBAAmB,SAAS,MAAM,uCAAuC;AAC/E,UAAI,kBAAkB;AACpB,cAAM,UAAU,iBAAiB,CAAC;AAClC,cAAM,SAAS,iBAAiB,CAAC;AACjC,YAAI,WAAW,UAAU,WAAW,WAAW;AAC7C,iBAAO,MAAM,mBAAmB,KAAK,KAAK,SAAS,SAAS;AAAA,QAC9D;AACA,YAAI,WAAW,UAAU,WAAW,QAAQ;AAC1C,iBAAO,MAAM,gBAAgB,KAAK,KAAK,SAAS,SAAS;AAAA,QAC3D;AACA,YAAI,WAAW,UAAU,WAAW,WAAW;AAC7C,iBAAO,MAAM,mBAAmB,KAAK,KAAK,SAAS,SAAS;AAAA,QAC9D;AAAA,MACF;AAGA,UAAI,WAAW,SAAS,aAAa,kBAAkB;AACrD,eAAO,UAAU,KAAK,KAAK,KAAK,OAAO;AAAA,MACzC;AAGA,UAAI,WAAW,UAAU,aAAa,sBAAsB;AAC1D,eAAO,MAAM,KAAK,iBAAiB,KAAK,GAAG;AAAA,MAC7C;AACA,UAAI,WAAW,SAAS,aAAa,uBAAuB;AAC1D,eAAO,KAAK,kBAAkB,KAAK,GAAG;AAAA,MACxC;AACA,UAAI,WAAW,UAAU,aAAa,wBAAwB;AAC5D,eAAO,MAAM,KAAK,mBAAmB,KAAK,GAAG;AAAA,MAC/C;AAGA,UAAI,WAAW,SAAS,aAAa,iBAAiB;AACpD,eAAO,KAAK,gBAAgB,KAAK,GAAG;AAAA,MACtC;AACA,UAAI,WAAW,SAAS,aAAa,4BAA4B;AAC/D,eAAO,KAAK,uBAAuB,GAAG;AAAA,MACxC;AACA,UAAI,WAAW,UAAU,aAAa,6BAA6B;AACjE,eAAO,KAAK,wBAAwB,GAAG;AAAA,MACzC;AAGA,UAAI,WAAW,UAAU,aAAa,mBAAmB;AACvD,eAAO,MAAM,aAAa,KAAK,KAAK,QAAQ,MAAM;AAAA,MACpD;AACA,UAAI,WAAW,UAAU,aAAa,oBAAoB;AACxD,eAAO,MAAM,cAAc,KAAK,KAAK,QAAQ,MAAM;AAAA,MACrD;AACA,UAAI,WAAW,UAAU,aAAa,qBAAqB;AACzD,eAAO,MAAM,eAAe,KAAK,KAAK,QAAQ,MAAM;AAAA,MACtD;AACA,UAAI,WAAW,UAAU,aAAa,mBAAmB;AACvD,eAAO,MAAM,aAAa,KAAK,KAAK,QAAQ,MAAM;AAAA,MACpD;AACA,UAAI,WAAW,UAAU,aAAa,mBAAmB;AACvD,eAAO,MAAM,aAAa,KAAK,KAAK,QAAQ,MAAM;AAAA,MACpD;AACA,UAAI,WAAW,UAAU,aAAa,qBAAqB;AACzD,eAAO,MAAM,eAAe,KAAK,KAAK,QAAQ,MAAM;AAAA,MACtD;AAMA,UAAI,WAAW,SAAS,aAAa,sBAAsB;AACzD,eAAO,gBAAgB,KAAK,SAAS;AAAA,MACvC;AACA,UAAI,WAAW,SAAS,aAAa,sBAAsB;AAEzD,eAAO,SAAS,KAAK,KAAK;AAAA,UACxB,QAAQ;AAAA,YACN,KAAK,QAAQ;AAAA,YACb,QAAQ,QAAQ,OAAO;AAAA,YACvB,SAAS;AAAA,UACX;AAAA,UACA,QAAQ,KAAK,cAAc,KAAK,YAAY,KAAK,IAAI,CAAC;AAAA,UACtD,WAAW,MAAM,KAAK,yBAAyB;AAAA,QACjD,CAAC;AAAA,MACH;AAGA,YAAM,gBAAgB,KAAK,iBAAiB,QAAQ,QAAQ;AAC5D,UAAI,kBAAkB,QAAW;AAC/B,YAAI;AACJ,YAAI;AACF,iBAAO,MAAM,SAAS,GAAG;AAAA,QAC3B,SAAS,KAAc;AACrB,cAAI,eAAe,SAAU,IAAkC,SAAS,eAAe;AACrF,mBAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,KAAK,KAAK,OAAO,KAAK,CAAC;AAAA,UAC9E;AACA,iBAAO,SAAS,KAAK,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,QACnD;AACA,cAAM,cAAc,KAAK,KAAK,EAAE,QAAQ,KAAK,CAAC;AAC9C;AAAA,MACF;AAEA,eAAS,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;AAAA,IAC3C,SAAS,KAAc;AACrB,UAAI,IAAI,YAAa;AACrB,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,KAAK,KAAK,EAAE,OAAO,YAAY,SAAS,IAAI,CAAC;AAAA,IACxD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAc,KAAgC;AACpD,UAAM,SAAS,KAAK,YAAY,KAAK;AACrC,UAAM,WAAW,QAAQ,YAAY,EAAE;AACvC,UAAM,OAAO,KAAK,SAAS,QAAQ;AACnC,UAAM,OAAO,SAAS,QAAQ,OAAO,SAAS,WAAW,KAAK,OAAO,KAAK;AAC1E,aAAS,KAAK,KAAK;AAAA,MACjB,QAAQ;AAAA,MACR,QAAQ;AAAA,QACN,KAAK,QAAQ;AAAA,QACb,QAAQ,KAAK,IAAI,IAAI,KAAK;AAAA,QAC1B,OAAO;AAAA,QACP;AAAA,QACA;AAAA,MACF;AAAA,MACA,QAAQ;AAAA,QACN,QAAQ,OAAO;AAAA,QACf,eAAe,KAAK,KAAK;AAAA,MAC3B;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,iBAAiB,KAA2B,KAAyC;AACjG,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,SAAS,GAAG;AAAA,IAC3B,SAAS,KAAc;AACrB,UAAI,eAAe,SAAU,IAAkC,SAAS,eAAe;AACrF,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,KAAK,KAAK,OAAO,KAAK,CAAC;AAAA,MAC9E;AACA,aAAO,SAAS,KAAK,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,IACnD;AAEA,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,SAAS,IAAI,KAAK,MAAM,KAAK,SAAS,MAAM,CAAC,IAA+B,CAAC;AAAA,IAC7F,QAAQ;AACN,aAAO,SAAS,KAAK,KAAK,EAAE,OAAO,WAAW,CAAC;AAAA,IACjD;AACA,UAAM,SAAS,OAAO,OAAO,QAAQ,MAAM,WAAW,OAAO,QAAQ,IAAI;AACzE,UAAM,QAAQ,KAAK,gBAAgB,YAAY,MAAM;AACrD,aAAS,KAAK,KAAK;AAAA,MACjB,IAAI;AAAA,MACJ,MAAM;AAAA,QACJ,OAAO,MAAM;AAAA,QACb,KAAK,MAAM;AAAA,QACX,WAAW,MAAM;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,kBAAkB,KAA0B,KAAgB;AAClE,UAAM,QAAQ,IAAI,aAAa,IAAI,OAAO;AAC1C,QAAI,CAAC,OAAO;AACV,eAAS,KAAK,KAAK,EAAE,OAAO,gBAAgB,CAAC;AAC7C;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,gBAAgB,UAAU,KAAK;AACnD,QAAI,CAAC,QAAQ;AACX,eAAS,KAAK,KAAK,EAAE,OAAO,mBAAmB,QAAQ,MAAM,CAAC;AAC9D;AAAA,IACF;AACA,aAAS,KAAK,KAAK,MAAM;AAAA,EAC3B;AAAA,EAEA,MAAc,mBAAmB,KAA2B,KAAyC;AACnG,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,SAAS,GAAG;AAAA,IAC3B,SAAS,KAAc;AACrB,UAAI,eAAe,SAAU,IAAkC,SAAS,eAAe;AACrF,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,KAAK,KAAK,OAAO,KAAK,CAAC;AAAA,MAC9E;AACA,aAAO,SAAS,KAAK,KAAK,EAAE,OAAO,aAAa,CAAC;AAAA,IACnD;AAEA,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,SAAS,IAAI,KAAK,MAAM,KAAK,SAAS,MAAM,CAAC,IAA+B,CAAC;AAAA,IAC7F,QAAQ;AACN,aAAO,SAAS,KAAK,KAAK,EAAE,OAAO,WAAW,CAAC;AAAA,IACjD;AAEA,UAAM,QAAQ,OAAO,OAAO,OAAO,MAAM,WAAW,OAAO,OAAO,IAAI;AACtE,QAAI,CAAC,OAAO;AACV,aAAO,SAAS,KAAK,KAAK,EAAE,OAAO,gBAAgB,CAAC;AAAA,IACtD;AAEA,QAAI;AACF,YAAM,SAAS,KAAK,gBAAgB,QAAQ,OAAO;AAAA,QACjD,WAAW,OAAO,OAAO,WAAW,MAAM,WAAW,OAAO,WAAW,IAAI;AAAA,QAC3E,YAAY,OAAO,OAAO,YAAY,MAAM,WAAW,OAAO,YAAY,IAAI;AAAA,QAC9E,WAAW,OAAO,WAAW,MAAM,UAAU,UAAU;AAAA,QACvD,cAAc,OAAO,OAAO,cAAc,MAAM,WAAW,OAAO,cAAc,IAAI;AAAA,MACtF,CAAC;AACD,eAAS,KAAK,KAAK,EAAE,IAAI,MAAM,GAAG,OAAO,CAAC;AAAA,IAC5C,SAAS,KAAK;AACZ,YAAM,IAAI;AACV,eAAS,KAAK,EAAE,UAAU,KAAK,EAAE,IAAI,OAAO,OAAO,EAAE,QAAQ,CAAC;AAAA,IAChE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,uBAAuB,KAAgC;AAS7D,UAAM,mBAAoB,WAAmB;AAmB7C,QAAI,CAAC,kBAAkB;AACrB,eAAS,KAAK,KAAK;AAAA,QACjB,QAAQ;AAAA,QACR,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM,SAAS,iBAAiB,UAAU;AAK1C,QAAI;AACJ,QAAI,OAAO,aAAa,OAAO,gBAAgB,MAAM;AACnD,gBAAU;AAAA,IACZ,WAAW,CAAC,OAAO,iBAAiB;AAClC,gBAAU;AAAA,IACZ,OAAO;AACL,gBAAU;AAAA,IACZ;AAEA,UAAM,OAaF;AAAA,MACF,QAAQ;AAAA,MACR,WAAW;AAAA,QACT,aAAa,OAAO;AAAA,QACpB,iBAAiB,OAAO;AAAA,QACxB,WAAW,OAAO;AAAA,QAClB,WAAW,OAAO;AAAA,QAClB,iBAAiB,OAAO;AAAA,QACxB,OAAO,OAAO;AAAA,MAChB;AAAA,IACF;AACA,QAAI,YAAY,aAAa;AAC3B,WAAK,OAAO,OAAO;AACnB,WAAK,YAAY,OAAO;AAAA,IAC1B,WAAW,YAAY,eAAe;AACpC,WAAK,YAAY,OAAO,aAAa;AAAA,IACvC;AACA,aAAS,KAAK,KAAK,IAAI;AAAA,EACzB;AAAA;AAAA;AAAA,EAIA,MAAc,2BAA6C;AACzD,UAAM,mBAAoB,WAAmB;AAG7C,WAAO,mBAAmB,iBAAiB,UAAU,IAAI;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA,EAMQ,gBAAgB,KAA2B,KAAgC;AAEjF,UAAM,WAAW,IAAI,OAAO;AAC5B,QAAI,CAAC,UAAU;AACb,eAAS,KAAK,KAAK,EAAE,OAAO,aAAa,SAAS,gCAAgC,CAAC;AACnF;AAAA,IACF;AAGA,UAAM,OAAO,KAAK,SAAS,QAAQ;AACnC,QAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,eAAS,KAAK,KAAK,EAAE,OAAO,YAAY,SAAS,+BAA+B,CAAC;AACjF;AAAA,IACF;AAGA,UAAM,aAAc,WAAmB;AAOvC,UAAM,WAAW,YAAY,YAAY;AACzC,UAAM,UAAU,YAAY,WAAW;AACvC,UAAM,QAAQ,YAAY,SAAS,KAAK;AACxC,UAAM,OAAO,YAAY,QAAQ,KAAK;AAGtC,YAAQ,IAAI,2BAA2B,QAAQ,uBAAuB,KAAK,IAAI,IAAI,EAAE;AAErF,aAAS,KAAK,KAAK;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,MACpB,cAAc;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,wBAAwB,KAAyC;AAC7E,UAAM,mBAAoB,WAAmB;AAI7C,QAAI,CAAC,kBAAkB;AACrB,eAAS,KAAK,KAAK;AAAA,QACjB,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,QAAI;AACF,YAAM,iBAAiB,aAAa;AACpC,eAAS,KAAK,KAAK;AAAA,QACjB,QAAQ;AAAA,QACR,SAAS;AAAA,MACX,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,KAAK,KAAK;AAAA,QACjB,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAWO,IAAM,oBAAyE;AAAA,EACpF,EAAE,QAAQ,QAAQ,UAAU,mCAAmC;AACjE;AAEA,SAAS,mBAAmB,QAAgB,UAA2B;AACrE,aAAW,SAAS,mBAAmB;AACrC,QAAI,MAAM,WAAW,UAAU,MAAM,aAAa,SAAU,QAAO;AAAA,EACrE;AACA,SAAO;AACT;AAEA,SAAS,aAAa,SAAiB,UAA2B;AAChE,QAAM,eAAe,QAAQ,MAAM,GAAG,EAAE,OAAO,OAAO;AACtD,QAAM,YAAY,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AACpD,MAAI,aAAa,WAAW,UAAU,OAAQ,QAAO;AAErD,WAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,UAAM,cAAc,aAAa,CAAC;AAClC,QAAI,YAAY,WAAW,GAAG,EAAG;AACjC,QAAI,gBAAgB,UAAU,CAAC,EAAG,QAAO;AAAA,EAC3C;AAEA,SAAO;AACT;;;AMhlBO,IAAM,8BAAN,MAAkC;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA,SAAS,oBAAI,IAA0B;AAAA,EAExD,YAAY,MAA+B;AACzC,SAAK,WAAW,KAAK;AACrB,SAAK,aAAa,KAAK;AACvB,SAAK,gBAAgB,KAAK;AAC1B,SAAK,gBAAgB,KAAK,gBAAgB,yBAAyB,QAAQ,aAAa,EAAE;AAC1F,SAAK,eAAe,KAAK;AACzB,SAAK,cAAc,KAAK;AAExB,SAAK,eAAe;AAAA,EACtB;AAAA,EAEQ,iBAAiB,SAAiB,QAAgC,CAAC,GAA2B;AACpG,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,qBAAqB;AAAA,MACrB,GAAG;AAAA,IACL;AACA,QAAI,KAAK,gBAAgB,UAAa,KAAK,YAAY,SAAS,GAAG;AACjE,cAAQ,eAAe,IAAI,UAAU,KAAK,WAAW;AAAA,IACvD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAuB;AAE7B,SAAK,OAAO,IAAI,0BAA0B,KAAK,oBAAoB,KAAK,IAAI,CAAC;AAG7E,SAAK,OAAO,IAAI,2BAA2B,KAAK,cAAc,KAAK,IAAI,CAAC;AAGxE,SAAK,OAAO,IAAI,0BAA0B,KAAK,aAAa,KAAK,IAAI,CAAC;AAGtE,SAAK,OAAO,IAAI,yBAAyB,KAAK,iBAAiB,KAAK,IAAI,CAAC;AAGzE,SAAK,OAAO,IAAI,wBAAwB,KAAK,iBAAiB,KAAK,IAAI,CAAC;AAGxE,SAAK,OAAO,IAAI,8BAA8B,KAAK,qBAAqB,KAAK,IAAI,CAAC;AAGlF,SAAK,OAAO,IAAI,2BAA2B,KAAK,cAAc,KAAK,IAAI,CAAC;AAGxE,SAAK,OAAO,IAAI,4BAA4B,KAAK,mBAAmB,KAAK,IAAI,CAAC;AAAA,EAChF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAuC;AACrC,WAAO,IAAI,IAAI,KAAK,MAAM;AAAA,EAC5B;AAAA;AAAA,EAGA,SAAS,QAAgBC,QAAwC;AAC/D,WAAO,KAAK,OAAO,IAAI,GAAG,MAAM,IAAIA,MAAI,EAAE;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAc,oBACZ,MACA,KACA,KACe;AACf,QAAI;AAEF,YAAM,OAAO,KAAK,MAAM,IAAI,KAAK,SAAS,CAAC;AAG3C,UAAI,CAAC,KAAK,cAAc,CAAC,KAAK,SAAS;AACrC,eAAO,SAAS,KAAK,KAAK;AAAA,UACxB,IAAI;AAAA,UACJ,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAGA,YAAM,UAAU,KAAK,oBAAoB,IAAI;AAG7C,YAAM,KAAK,SAAS,QAAQ,8BAA8B;AAAA,QACxD,SAAS,IAAI,QAAQ;AAAA,QACrB;AAAA,QACA,QAAQ,KAAK,aAAa,gBAAgB;AAAA,QAC1C,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC,CAAC;AAED,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,+CAAgD,IAAc,OAAO;AACnF,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,OAAO,6BAA8B,IAAc,OAAO;AAAA,MAC5D,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,cACZ,MACA,KACA,KACe;AACf,QAAI,CAAC,IAAI,QAAQ;AACf,aAAO,SAAS,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,eAAe,CAAC;AAAA,IAChE;AAEA,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,IAAI,KAAK,SAAS,CAAC;AAG3C,UAAI,CAAC,KAAK,WAAW,CAAC,MAAM,QAAQ,KAAK,OAAO,GAAG;AACjD,eAAO,SAAS,KAAK,KAAK;AAAA,UACxB,IAAI;AAAA,UACJ,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAGA,YAAM,SAAS,MAAM,KAAK,iBAAiB,MAAM,IAAI,OAAO,OAAO;AAEnE,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,qCAAsC,IAAc,OAAO;AACzE,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,OAAO,oBAAqB,IAAc,OAAO;AAAA,MACnD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,aACZ,MACA,KACA,KACe;AACf,QAAI,CAAC,IAAI,QAAQ;AACf,aAAO,SAAS,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,eAAe,CAAC;AAAA,IAChE;AAEA,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,IAAI,KAAK,SAAS,CAAC;AAG3C,UAAI,CAAC,KAAK,UAAU,CAAC,KAAK,SAAS;AACjC,eAAO,SAAS,KAAK,KAAK;AAAA,UACxB,IAAI;AAAA,UACJ,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAGA,YAAM,SAAS,MAAM,KAAK,gBAAgB,MAAM,IAAI,OAAO,OAAO;AAGlE,YAAM,KAAK,SAAS,QAAQ,8BAA8B;AAAA,QACxD,SAAS,IAAI,OAAO;AAAA,QACpB,QAAQ,KAAK;AAAA,QACb,SAAS,KAAK;AAAA,QACd,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACrC,CAAC;AAED,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACrC,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,oCAAqC,IAAc,OAAO;AACxE,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,OAAO,qBAAsB,IAAc,OAAO;AAAA,MACpD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,iBACZ,MACA,KACA,KACe;AACf,QAAI,CAAC,IAAI,QAAQ;AACf,aAAO,SAAS,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,eAAe,CAAC;AAAA,IAChE;AAEA,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,IAAI,KAAK,SAAS,CAAC;AAG3C,UAAI,CAAC,KAAK,YAAY,CAAC,KAAK,gBAAgB,CAAC,KAAK,UAAU;AAC1D,eAAO,SAAS,KAAK,KAAK;AAAA,UACxB,IAAI;AAAA,UACJ,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAGA,YAAM,OAAO,MAAM,KAAK,oBAAoB,MAAM,IAAI,OAAO,OAAO;AAGpE,YAAM,KAAK,SAAS,QAAQ,0BAA0B;AAAA,QACpD,SAAS,IAAI,OAAO;AAAA,QACpB,QAAS,KAAyB;AAAA,QAClC,UAAU,KAAK;AAAA,QACf,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,CAAC;AAED,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,yCAA0C,IAAc,OAAO;AAC7E,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,OAAO,yBAA0B,IAAc,OAAO;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,iBACZ,MACA,KACA,KACe;AACf,QAAI,CAAC,IAAI,QAAQ;AACf,aAAO,SAAS,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,eAAe,CAAC;AAAA,IAChE;AAEA,QAAI;AAEF,YAAM,QAAQ,MAAM,KAAK,oBAAoB,IAAI,OAAO,OAAO;AAE/D,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,yCAA0C,IAAc,OAAO;AAC7E,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,OAAO,iBAAkB,IAAc,OAAO;AAAA,MAChD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,qBACZ,MACA,KACA,KACe;AACf,QAAI,CAAC,IAAI,QAAQ;AACf,aAAO,SAAS,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,eAAe,CAAC;AAAA,IAChE;AAEA,QAAI;AAEF,YAAM,cAAc,MAAM,KAAK,wBAAwB,IAAI,OAAO,OAAO;AAEzE,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,6CAA8C,IAAc,OAAO;AACjF,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,OAAO,8BAA+B,IAAc,OAAO;AAAA,MAC7D,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,cACZ,MACA,KACA,KACe;AACf,QAAI,CAAC,IAAI,QAAQ;AACf,aAAO,SAAS,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,eAAe,CAAC;AAAA,IAChE;AAEA,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,IAAI,KAAK,SAAS,CAAC;AAG3C,YAAM,YAAY,KAAK,gBACnB,MAAM,KAAK,yBAAyB,IAAI,OAAO,SAAS,KAAK,MAAM,IACnE,MAAM,KAAK,iBAAiB,IAAI,OAAO,OAAO;AAGlD,YAAM,KAAK,SAAS,QAAQ,oCAAoC;AAAA,QAC9D,SAAS,IAAI,OAAO;AAAA,QACpB;AAAA,QACA,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC,CAAC;AAED,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,MAAM,EAAE,UAAU;AAAA,QAClB,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,0CAA2C,IAAc,OAAO;AAC9E,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,OAAO,wBAAyB,IAAc,OAAO;AAAA,MACvD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,mBACZ,MACA,KACA,KACe;AACf,QAAI,CAAC,IAAI,QAAQ;AACf,aAAO,SAAS,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,eAAe,CAAC;AAAA,IAChE;AAEA,QAAI;AAEF,YAAM,YAAY,MAAM,KAAK,sBAAsB;AAEnD,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,cAAQ,MAAM,2CAA4C,IAAc,OAAO;AAC/E,eAAS,KAAK,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,OAAO,oCAAqC,IAAc,OAAO;AAAA,MACnE,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,mBAAmB,UAAsC;AACrE,UAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,oBAAoB,SAAS,MAAM,MAAM,IAAI,EAAE;AAAA,IACjE;AAEA,UAAM,OAAO,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC;AACxC,QAAI,MAAM,OAAO,OAAO;AACtB,YAAM,IAAI,MAAM,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,KAAK,UAAU,KAAK,KAAK,CAAC;AAAA,IAC1F;AACA,WAAO,MAAM,QAAQ;AAAA,EACvB;AAAA,EAEA,MAAc,iBAAiB,MAAsB,SAAmC;AACtF,UAAM,MAAM,GAAG,KAAK,YAAY;AAChC,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,KAAK,iBAAiB,OAAO;AAAA,MACtC,MAAM,KAAK,UAAU;AAAA,QACnB,SAAS,KAAK;AAAA,QACd,iBAAiB,KAAK;AAAA,QACtB,MAAM,CAAC;AAAA,QACP,UAAU,KAAK;AAAA,QACf,OAAO,KAAK;AAAA,QACZ,UAAU,KAAK;AAAA,MACjB,CAAC;AAAA,IACH,CAAC;AAED,WAAO,MAAM,KAAK,mBAAmB,QAAQ;AAAA,EAC/C;AAAA,EAEA,MAAc,gBAAgB,MAAqB,SAAmC;AACpF,UAAM,MAAM,GAAG,KAAK,YAAY;AAChC,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,KAAK,iBAAiB,OAAO;AAAA,MACtC,MAAM,KAAK,UAAU;AAAA,QACnB,SAAS,KAAK;AAAA,QACd,SAAS,KAAK;AAAA,QACd,SAAS,KAAK;AAAA,QACd,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,QACd,cAAc,KAAK;AAAA,QACnB,mBAAmB,KAAK;AAAA,MAC1B,CAAC;AAAA,IACH,CAAC;AAED,WAAO,MAAM,KAAK,mBAAmB,QAAQ;AAAA,EAC/C;AAAA,EAEA,MAAc,oBAAoB,MAAyB,SAAmC;AAC5F,UAAM,MAAM,GAAG,KAAK,YAAY;AAChC,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,KAAK,iBAAiB,OAAO;AAAA,MACtC,MAAM,KAAK,UAAU;AAAA,QACnB,UAAU,KAAK;AAAA,QACf,eAAe,KAAK;AAAA,QACpB,UAAU,KAAK;AAAA,QACf,eAAe,KAAK,iBAAiB,CAAC;AAAA,QACtC,aAAa,KAAK;AAAA,MACpB,CAAC;AAAA,IACH,CAAC;AAED,WAAO,MAAM,KAAK,mBAAmB,QAAQ;AAAA,EAC/C;AAAA,EAEA,MAAc,oBAAoB,SAAmC;AACnE,UAAM,MAAM,GAAG,KAAK,YAAY;AAChC,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,KAAK,iBAAiB,OAAO;AAAA,IACxC,CAAC;AAED,WAAO,MAAM,KAAK,mBAAmB,QAAQ;AAAA,EAC/C;AAAA,EAEA,MAAc,wBAAwB,SAAmC;AACvE,UAAM,MAAM,GAAG,KAAK,YAAY,iCAAiC,mBAAmB,OAAO,CAAC;AAC5F,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,KAAK,iBAAiB,OAAO;AAAA,IACxC,CAAC;AAED,UAAM,OAAO,MAAM,KAAK,mBAAmB,QAAQ;AACnD,WAAQ,KAAmC,eAAe;AAAA,EAC5D;AAAA,EAEA,MAAc,iBAAiB,SAAmC;AAChE,UAAM,MAAM,GAAG,KAAK,YAAY;AAChC,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,KAAK,iBAAiB,OAAO;AAAA,IACxC,CAAC;AAED,UAAM,OAAO,MAAM,KAAK,mBAAmB,QAAQ;AACnD,QAAI,OAAO,SAAS,UAAW,QAAO;AACtC,WAAO,QAAS,KAAiC,SAAS;AAAA,EAC5D;AAAA,EAEA,MAAc,wBAA0C;AAGtD,UAAM,MAAM,GAAG,KAAK,YAAY;AAChC,UAAM,UAAkC,EAAE,gBAAgB,mBAAmB;AAC7E,QAAI,KAAK,gBAAgB,UAAa,KAAK,YAAY,SAAS,GAAG;AACjE,cAAQ,eAAe,IAAI,UAAU,KAAK,WAAW;AAAA,IACvD;AACA,UAAM,WAAW,MAAM,MAAM,KAAK,EAAE,QAAQ,OAAO,QAAQ,CAAC;AAE5D,WAAO,MAAM,KAAK,mBAAmB,QAAQ;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,yBAAyB,SAAiB,SAAS,OAAyB;AACxF,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,qDAAqD;AAAA,IACvE;AAEA,YAAQ,IAAI,8DAA8D,OAAO,YAAY,MAAM,GAAG;AAEtG,QAAI,QAAQ;AAEV,aAAO,MAAM,KAAK,iBAAiB,OAAO;AAAA,IAC5C;AAOA,YAAQ,KAAK,kFAAkF;AAC/F,WAAO,MAAM,KAAK,iBAAiB,OAAO;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAMQ,oBAAoB,KAAwC;AAClE,UAAM,UAAoB,CAAC;AAG3B,QAAI,IAAI,YAAY;AAClB,YAAM,SAAS,IAAI,WAAW,UAAU;AACxC,YAAM,QAAQ,IAAI,WAAW,SAAS;AAGtC,YAAM,WAAoC;AAAA,QACxC,CAAC,sBAAsB,eAAe;AAAA,QACtC,CAAC,oCAAoC,0BAA0B;AAAA,QAC/D,CAAC,kBAAkB,iBAAiB;AAAA,QACpC,CAAC,oBAAoB,kBAAkB;AAAA,QACvC,CAAC,qBAAqB,kBAAkB;AAAA,QACxC,CAAC,kBAAkB,iBAAiB;AAAA,QACpC,CAAC,mBAAmB,iBAAiB;AAAA,QACrC,CAAC,wBAAwB,oBAAoB;AAAA,QAC7C,CAAC,cAAc,kBAAkB;AAAA,QACjC,CAAC,gBAAgB,oBAAoB;AAAA,QACrC,CAAC,mBAAmB,uBAAuB;AAAA,QAC3C,CAAC,sBAAsB,WAAW;AAAA,QAClC,CAAC,iCAAiC,kBAAkB;AAAA,QACpD,CAAC,kBAAkB,sBAAsB;AAAA,QACzC,CAAC,wBAAwB,iBAAiB;AAAA,QAC1C,CAAC,aAAa,gBAAgB;AAAA,MAChC;AAEA,YAAM,OAAO,GAAG,MAAM,IAAI,KAAK;AAC/B,iBAAW,CAAC,SAAS,UAAU,KAAK,UAAU;AAC5C,YAAI,QAAQ,KAAK,IAAI,GAAG;AACtB,gBAAM,SAAS,IAAI,WAAW,GAAG,UAAU,aAAa,IAAI,QAAQ,KAAK;AACzE,cAAI,CAAC,QAAQ,SAAS,MAAM,GAAG;AAC7B,oBAAQ,KAAK,MAAM;AAAA,UACrB;AAAA,QACF;AAAA,MACF;AAGA,UAAI,IAAI,WAAW,YAAY,IAAI,WAAW,aAAa,GAAG;AAC5D,gBAAQ,KAAK,uBAAuB,IAAI,WAAW,QAAQ,EAAE;AAAA,MAC/D;AAGA,UAAI,IAAI,WAAW,cAAc,IAAI,WAAW,aAAa,KAAQ;AACnE,gBAAQ,KAAK,gCAAgC,IAAI,WAAW,UAAU,IAAI;AAAA,MAC5E;AAAA,IACF;AAGA,QAAI,IAAI,MAAM;AACZ,iBAAW,OAAO,IAAI,MAAM;AAC1B,gBAAQ,KAAK,OAAO,GAAG,EAAE;AAAA,MAC3B;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;ACtqBO,IAAK,iBAAL,kBAAKC,oBAAL;AACL,EAAAA,gBAAA,aAAU;AACV,EAAAA,gBAAA,iBAAc;AACd,EAAAA,gBAAA,iBAAc;AACd,EAAAA,gBAAA,mBAAgB;AAChB,EAAAA,gBAAA,gBAAa;AACb,EAAAA,gBAAA,iBAAc;AACd,EAAAA,gBAAA,cAAW;AACX,EAAAA,gBAAA,oBAAiB;AACjB,EAAAA,gBAAA,gBAAa;AACb,EAAAA,gBAAA,eAAY;AACZ,EAAAA,gBAAA,eAAY;AACZ,EAAAA,gBAAA,eAAY;AAZF,SAAAA;AAAA,GAAA;AAeZ,IAAM,mBAAmB;AA4ElB,IAAM,aAAN,MAAiB;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,cAAc,oBAAI,IAAyB;AAAA;AAAA,EAElC,iBAAiB,oBAAI,IAAoB;AAAA,EAE1D,YAAY,MAAyB;AACnC,SAAK,OAAO,KAAK;AACjB,SAAK,cAAc,KAAK;AACxB,SAAK,gBAAgB,KAAK,gBAAgB;AAC1C,SAAK,YAAY,KAAK;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAe,QAMN;AAEP,WAAO,cAAc,QAAQ,oBAAoB,OAAO,KAAK,KAAK,QAAQ;AACxE,YAAM,KAAK,iBAAiB,KAAK,KAAK,IAAI,IAAI;AAAA,IAChD,CAAC;AAGD,WAAO,cAAc,QAAQ,qBAAqB,OAAO,KAAK,KAAK,QAAQ;AACzE,YAAM,KAAK,kBAAkB,KAAK,KAAK,IAAI,IAAI;AAAA,IACjD,CAAC;AAGD,WAAO,cAAc,QAAQ,6BAA6B,OAAO,KAAK,KAAK,QAAQ;AACjF,YAAM,KAAK,qBAAqB,KAAK,KAAK,IAAI,IAAI;AAAA,IACpD,CAAC;AAGD,WAAO,cAAc,QAAQ,qBAAqB,OAAO,KAAK,KAAK,QAAQ;AACzE,YAAM,KAAK,kBAAkB,KAAK,KAAK,IAAI,IAAI;AAAA,IACjD,CAAC;AAGD,WAAO,cAAc,QAAQ,0BAA0B,OAAO,KAAK,KAAK,QAAQ;AAC9E,YAAM,KAAK,kBAAkB,KAAK,KAAK,IAAI,IAAI;AAAA,IACjD,CAAC;AAGD,WAAO,cAAc,QAAQ,2BAA2B,OAAO,KAAK,KAAK,QAAQ;AAC/E,YAAM,KAAK,mBAAmB,KAAK,KAAK,IAAI,IAAI;AAAA,IAClD,CAAC;AAGD,WAAO,cAAc,OAAO,cAAc,OAAO,KAAK,QAAQ;AAC5D,YAAM,KAAK,eAAe,KAAK,GAAG;AAAA,IACpC,CAAC;AAGD,WAAO,cAAc,OAAO,UAAU,OAAO,KAAK,QAAQ;AACxD,YAAM,KAAK,iBAAiB,KAAK,GAAG;AAAA,IACtC,CAAC;AAGD,WAAO,cAAc,OAAO,iBAAiB,OAAO,KAAK,QAAQ;AAC/D,YAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB;AACtD,YAAM,UAAmB;AAAA,QACvB,KAAK,KAAK;AAAA,QACV,YAAY,KAAK;AAAA,MACnB;AACA,YAAM,UAAU,KAAK,KAAK,KAAK,OAAO;AAAA,IACxC,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,MAAc,iBACZ,KACA,KACA,aACe;AACf,QAAI;AAEF,YAAM,QAAQ,IAAI,KAAK,MAAM,yBAAyB;AACtD,UAAI,CAAC,OAAO;AACV,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,cAAc,CAAC;AAAA,MACpD;AACA,YAAM,SAAS,MAAM,CAAC;AAEtB,YAAM,QAA0B,YAAY,SACxC,KAAK,MAAM,YAAY,SAAS,MAAM,CAAC,IACvC,CAAC;AAGL,UAAI,MAAM,WAAW,UAAa,MAAM,WAAW,QAAQ;AACzD,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MACxD;AAGA,WAAK,cAAc,QAAQ,+BAA0B;AAGrD,YAAM,cAAc,MAAM,KAAK;AAAA,QAC7B,UAAU,MAAM;AAAA,QAChB;AAAA,QACA,EAAE,GAAG,OAAO,OAAO;AAAA,MACrB;AAEA,UAAI,CAAC,YAAY,IAAI;AACnB,eAAO,SAAS,KAAK,YAAY,UAAU,KAAK;AAAA,UAC9C,OAAO;AAAA,UACP,SAAS,YAAY;AAAA,QACvB,CAAC;AAAA,MACH;AAGA,YAAM,WAAW,YAAY;AAC7B,WAAK,KAAK,QAAQ,eAAe;AAAA,QAC/B,QAAQ,SAAS;AAAA,QACjB,SAAS,SAAS;AAAA,QAClB,YAAY,SAAS;AAAA,QACrB,SAAS,SAAS;AAAA,QAClB,YAAY,SAAS;AAAA,MACvB,CAAC;AAGD,WAAK,cAAc,QAAQ,kCAA4B;AAAA,QACrD,SAAS,SAAS;AAAA,QAClB,YAAY,SAAS;AAAA,QACrB,SAAS,SAAS;AAAA,QAClB,YAAY,SAAS;AAAA,MACvB,CAAC;AAED,eAAS,KAAK,KAAK,QAAQ;AAAA,IAC7B,SAAS,KAAc;AACrB,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,KAAK,KAAK,EAAE,OAAO,YAAY,SAAS,IAAI,CAAC;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,MAAc,kBACZ,KACA,KACA,aACe;AACf,QAAI;AACF,YAAM,QAAQ,IAAI,KAAK,MAAM,0BAA0B;AACvD,UAAI,CAAC,OAAO;AACV,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,cAAc,CAAC;AAAA,MACpD;AACA,YAAM,SAAS,MAAM,CAAC;AAEtB,YAAM,QAA2B,YAAY,SACzC,KAAK,MAAM,YAAY,SAAS,MAAM,CAAC,IACtC,CAAC;AAGN,UAAI,MAAM,WAAW,UAAa,MAAM,WAAW,QAAQ;AACzD,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MACxD;AACA,UAAI,CAAC,MAAM,SAAS;AAClB,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,mBAAmB,CAAC;AAAA,MACzD;AAGA,YAAM,cAAc,KAAK,YAAY,IAAI,MAAM,OAAO;AACtD,UAAI,CAAC,aAAa;AAChB,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MACxD;AAGA,YAAM,cAAc,MAAM,KAAK;AAAA,QAC7B,UAAU,MAAM;AAAA,QAChB;AAAA,QACA,EAAE,GAAG,OAAO,OAAO;AAAA,MACrB;AAEA,UAAI,CAAC,YAAY,IAAI;AACnB,eAAO,SAAS,KAAK,YAAY,UAAU,KAAK;AAAA,UAC9C,OAAO;AAAA,UACP,SAAS,YAAY;AAAA,QACvB,CAAC;AAAA,MACH;AAGA,WAAK,KAAK,QAAQ,iBAAiB;AAAA,QACjC;AAAA,QACA,SAAS,MAAM;AAAA,MACjB,CAAC;AAED,eAAS,KAAK,KAAK,YAAY,IAAI;AAAA,IACrC,SAAS,KAAc;AACrB,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,KAAK,KAAK,EAAE,OAAO,YAAY,SAAS,IAAI,CAAC;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,MAAc,qBACZ,KACA,KACA,aACe;AACf,QAAI;AACF,YAAM,QAAQ,IAAI,KAAK,MAAM,kCAAkC;AAC/D,UAAI,CAAC,OAAO;AACV,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,cAAc,CAAC;AAAA,MACpD;AACA,YAAM,SAAS,MAAM,CAAC;AAEtB,YAAM,QAA8B,YAAY,SAC5C,KAAK,MAAM,YAAY,SAAS,MAAM,CAAC,IACtC,CAAC;AAGN,UAAI,MAAM,WAAW,UAAa,MAAM,WAAW,QAAQ;AACzD,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MACxD;AACA,UAAI,CAAC,MAAM,QAAQ;AACjB,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MACxD;AAGA,YAAM,cAAc,MAAM,KAAK;AAAA,QAC7B,UAAU,MAAM;AAAA,QAChB;AAAA,QACA,EAAE,GAAG,OAAO,OAAO;AAAA,MACrB;AAEA,UAAI,CAAC,YAAY,IAAI;AACnB,eAAO,SAAS,KAAK,YAAY,UAAU,KAAK;AAAA,UAC9C,OAAO;AAAA,UACP,SAAS,YAAY;AAAA,QACvB,CAAC;AAAA,MACH;AAGA,WAAK,KAAK,QAAQ,uBAAuB;AAAA,QACvC;AAAA,QACA,QAAQ,MAAM;AAAA,QACd,QAAQ,MAAM;AAAA,MAChB,CAAC;AAGD,WAAK,cAAc,QAAQ,sCAA8B;AAAA,QACvD,QAAQ,MAAM;AAAA,QACd,QAAQ,MAAM;AAAA,MAChB,CAAC;AAGD,YAAM,YAAY,YAAY;AAC9B,YAAM,eAAe,WAAW,gBAAgB,WAAW,gBAAgB;AAE3E,UAAI,cAAc;AAEhB,aAAK,cAAc,QAAQ,kCAA4B;AAAA,UACrD,SAAS,WAAW;AAAA,UACpB,SAAS,WAAW;AAAA,QACtB,CAAC;AAAA,MACH,OAAO;AAEL,aAAK,cAAc,QAAQ,2BAAwB;AAAA,MACrD;AAGA,YAAM,WAAW,GAAG,MAAM,IAAI,MAAM,MAAM;AAC1C,WAAK,eAAe,OAAO,QAAQ;AAEnC,eAAS,KAAK,KAAK,YAAY,IAAI;AAAA,IACrC,SAAS,KAAc;AACrB,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,KAAK,KAAK,EAAE,OAAO,YAAY,SAAS,IAAI,CAAC;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,MAAc,kBACZ,KACA,KACA,aACe;AACf,QAAI;AACF,YAAM,QAAQ,IAAI,KAAK,MAAM,0BAA0B;AACvD,UAAI,CAAC,OAAO;AACV,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,cAAc,CAAC;AAAA,MACpD;AACA,YAAM,SAAS,MAAM,CAAC;AAEtB,YAAM,QAA2B,YAAY,SACzC,KAAK,MAAM,YAAY,SAAS,MAAM,CAAC,IACtC,CAAC;AAEN,UAAI,MAAM,WAAW,UAAa,MAAM,WAAW,QAAQ;AACzD,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MACxD;AACA,UAAI,CAAC,MAAM,QAAQ;AACjB,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MACxD;AAGA,YAAM,cAAc,MAAM,KAAK;AAAA,QAC7B,UAAU,MAAM;AAAA,QAChB;AAAA,QACA,EAAE,GAAG,OAAO,OAAO;AAAA,MACrB;AAEA,UAAI,CAAC,YAAY,IAAI;AACnB,eAAO,SAAS,KAAK,YAAY,UAAU,KAAK;AAAA,UAC9C,OAAO;AAAA,UACP,SAAS,YAAY;AAAA,QACvB,CAAC;AAAA,MACH;AAGA,WAAK,KAAK,QAAQ,kBAAkB;AAAA,QAClC;AAAA,QACA,QAAQ,MAAM;AAAA,MAChB,CAAC;AAGD,WAAK,cAAc,QAAQ,6BAA0B;AAAA,QACnD,QAAQ,MAAM;AAAA,MAChB,CAAC;AAGD,iBAAW,OAAO,KAAK,eAAe,KAAK,GAAG;AAC5C,YAAI,IAAI,WAAW,SAAS,GAAG,GAAG;AAChC,eAAK,eAAe,OAAO,GAAG;AAAA,QAChC;AAAA,MACF;AAEA,eAAS,KAAK,KAAK,YAAY,IAAI;AAAA,IACrC,SAAS,KAAc;AACrB,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,KAAK,KAAK,EAAE,OAAO,YAAY,SAAS,IAAI,CAAC;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,MAAc,kBACZ,KACA,KACA,aACe;AACf,QAAI;AACF,YAAM,QAAQ,IAAI,KAAK,MAAM,+BAA+B;AAC5D,UAAI,CAAC,OAAO;AACV,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,cAAc,CAAC;AAAA,MACpD;AACA,YAAM,SAAS,MAAM,CAAC;AAEtB,YAAM,QAA2B,YAAY,SACzC,KAAK,MAAM,YAAY,SAAS,MAAM,CAAC,IACtC,CAAC;AAEN,UAAI,MAAM,WAAW,UAAa,MAAM,WAAW,QAAQ;AACzD,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MACxD;AACA,UAAI,CAAC,MAAM,QAAQ;AACjB,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MACxD;AAGA,WAAK,cAAc,QAAQ,gCAA2B;AAAA,QACpD,QAAQ,MAAM;AAAA,QACd,OAAO,MAAM;AAAA,MACf,CAAC;AAGD,YAAM,WAAW,GAAG,MAAM,IAAI,MAAM,MAAM;AAC1C,YAAM,iBAAiB,KAAK,eAAe,IAAI,QAAQ,KAAK;AAE5D,UAAI,iBAAiB,kBAAkB;AACrC,cAAM,UAAU,iBAAiB;AACjC,aAAK,eAAe,IAAI,UAAU,OAAO;AAGzC,aAAK,cAAc,QAAQ,2BAAyB;AAAA,UAClD,QAAQ,MAAM;AAAA,UACd;AAAA,UACA,YAAY;AAAA,QACd,CAAC;AAED,iBAAS,KAAK,KAAK;AAAA,UACjB,OAAO;AAAA,UACP;AAAA,UACA,YAAY;AAAA,QACd,CAAC;AAAA,MACH,OAAO;AAEL,aAAK,cAAc,QAAQ,wCAA+B;AAAA,UACxD,QAAQ,MAAM;AAAA,UACd,UAAU;AAAA,QACZ,CAAC;AAED,aAAK,cAAc,QAAQ,gCAA2B;AAAA,UACpD,QAAQ,MAAM;AAAA,UACd,QAAQ;AAAA,QACV,CAAC;AAGD,aAAK,eAAe,OAAO,QAAQ;AAEnC,iBAAS,KAAK,KAAK;AAAA,UACjB,OAAO;AAAA,UACP,YAAY;AAAA,UACZ,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAc;AACrB,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,KAAK,KAAK,EAAE,OAAO,YAAY,SAAS,IAAI,CAAC;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,MAAc,mBACZ,KACA,KACA,aACe;AACf,QAAI;AACF,YAAM,QAAQ,IAAI,KAAK,MAAM,gCAAgC;AAC7D,UAAI,CAAC,OAAO;AACV,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,cAAc,CAAC;AAAA,MACpD;AACA,YAAM,SAAS,MAAM,CAAC;AAEtB,YAAM,QAA4B,YAAY,SAC1C,KAAK,MAAM,YAAY,SAAS,MAAM,CAAC,IACtC,CAAC;AAEN,UAAI,MAAM,WAAW,UAAa,MAAM,WAAW,QAAQ;AACzD,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MACxD;AACA,UAAI,CAAC,MAAM,QAAQ;AACjB,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,kBAAkB,CAAC;AAAA,MACxD;AAGA,WAAK,cAAc,QAAQ,kCAA4B;AAAA,QACrD,QAAQ,MAAM;AAAA,MAChB,CAAC;AAGD,WAAK,cAAc,QAAQ,6BAA0B;AAAA,QACnD,QAAQ,MAAM;AAAA,QACd,YAAY,MAAM;AAAA,MACpB,CAAC;AAGD,YAAM,YAAY,KAAK,YAAY,KAAK;AACxC,YAAM,gBAAgB,UAAU;AAAA,QAC9B,CAAC,MAAM,EAAE,UAAU,aAAa,EAAE,UAAU;AAAA,MAC9C;AAGA,UAAI,MAAM,cAAc,cAAc,SAAS,GAAG;AAChD,cAAM,cAAc,MAAM,KAAK;AAAA,UAC7B,UAAU,MAAM;AAAA,UAChB;AAAA,UACA;AAAA,YACE;AAAA,YACA,YAAY,MAAM;AAAA,YAClB,iBAAiB;AAAA,UACnB;AAAA,QACF;AAEA,YAAI,YAAY,IAAI;AAClB,gBAAM,YAAY,YAAY;AAG9B,eAAK,cAAc,QAAQ,kCAA4B;AAAA,YACrD,SAAS,UAAU;AAAA,YACnB,YAAY,UAAU;AAAA,YACtB,SAAS,UAAU;AAAA,YACnB,UAAU;AAAA,UACZ,CAAC;AAED,mBAAS,KAAK,KAAK;AAAA,YACjB,UAAU;AAAA,YACV,SAAS,UAAU;AAAA,YACnB,YAAY,UAAU;AAAA,YACtB,SAAS,UAAU;AAAA,UACrB,CAAC;AACD;AAAA,QACF;AAAA,MACF;AAGA,WAAK,cAAc,QAAQ,gCAA2B;AAAA,QACpD,QAAQ,MAAM;AAAA,QACd,QAAQ;AAAA,QACR,YAAY,MAAM;AAAA,MACpB,CAAC;AAED,eAAS,KAAK,KAAK;AAAA,QACjB,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV,CAAC;AAAA,IACH,SAAS,KAAc;AACrB,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,KAAK,KAAK,EAAE,OAAO,YAAY,SAAS,IAAI,CAAC;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,MAAc,eACZ,KACA,KACe;AACf,QAAI;AACF,YAAM,QAAQ,IAAI,KAAK,MAAM,mBAAmB;AAChD,UAAI,CAAC,OAAO;AACV,eAAO,SAAS,KAAK,KAAK,EAAE,OAAO,cAAc,CAAC;AAAA,MACpD;AACA,YAAM,SAAS,MAAM,CAAC;AAEtB,YAAM,cAAc,MAAM,KAAK,cAAc,UAAU,MAAM,IAAI,KAAK;AAEtE,UAAI,CAAC,YAAY,IAAI;AACnB,eAAO,SAAS,KAAK,YAAY,UAAU,KAAK;AAAA,UAC9C,OAAO;AAAA,UACP,SAAS,YAAY;AAAA,QACvB,CAAC;AAAA,MACH;AAEA,eAAS,KAAK,KAAK,YAAY,IAAI;AAAA,IACrC,SAAS,KAAc;AACrB,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,KAAK,KAAK,EAAE,OAAO,YAAY,SAAS,IAAI,CAAC;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,MAAc,iBACZ,KACA,KACe;AACf,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB;AACtD,YAAM,SAAS,IAAI,gBAAgB,IAAI,MAAM;AAC7C,YAAM,SAAS,OAAO,IAAI,QAAQ;AAClC,YAAM,aAAa,OAAO,IAAI,YAAY;AAC1C,YAAM,QAAQ,OAAO,IAAI,OAAO;AAChC,YAAM,QAAQ,OAAO,IAAI,OAAO;AAEhC,YAAM,cAAc,MAAM,KAAK,cAAc,UAAU,OAAO,QAAW;AAAA,QACvE,QAAQ,UAAU;AAAA,QAClB,YAAY,cAAc;AAAA,QAC1B,YAAY,SAAS;AAAA,QACrB,OAAO,SAAS;AAAA,MAClB,CAAC;AAED,UAAI,CAAC,YAAY,IAAI;AACnB,eAAO,SAAS,KAAK,YAAY,UAAU,KAAK;AAAA,UAC9C,OAAO;AAAA,UACP,SAAS,YAAY;AAAA,QACvB,CAAC;AAAA,MACH;AAEA,eAAS,KAAK,KAAK,YAAY,IAAI;AAAA,IACrC,SAAS,KAAc;AACrB,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,KAAK,KAAK,EAAE,OAAO,YAAY,SAAS,IAAI,CAAC;AAAA,IACxD;AAAA,EACF;AAAA;AAAA;AAAA,EAKQ,cACN,QACA,OACA,OACM;AACN,SAAK,KAAK,QAAQ,cAAc;AAAA,MAC9B;AAAA,MACA;AAAA,MACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,MAAc,cACZC,QACA,QACA,MACA,aAC2E;AAC3E,UAAM,UAAUA,OAAK,WAAW,OAAO,IAAIA,SAAO,UAAUA,MAAI;AAChE,UAAM,MAAM,IAAI,IAAI,SAAS,KAAK,aAAa;AAG/C,QAAI,aAAa;AACf,aAAO,QAAQ,WAAW,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACpD,YAAI,UAAU,QAAW;AACvB,cAAI,aAAa,OAAO,KAAK,KAAK;AAAA,QACpC;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,IAClB;AAEA,QAAI,KAAK,WAAW;AAClB,cAAQ,eAAe,IAAI,UAAU,KAAK,SAAS;AAAA,IACrD;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC;AAAA,MACA,SAAS;AAAA,QACP,GAAG;AAAA,MACL;AAAA,MACA,MAAM,QAAQ,WAAW,SAAS,KAAK,UAAU,IAAI,IAAI;AAAA,IAC3D,CAAC;AAED,UAAM,eAAe,MAAM,SAAS,KAAK;AACzC,QAAI,SAAc;AAClB,QAAI;AACF,eAAS,eAAe,KAAK,MAAM,YAAY,IAAI;AAAA,IACrD,QAAQ;AACN,eAAS;AAAA,IACX;AAEA,WAAO;AAAA,MACL,IAAI,SAAS,MAAM,QAAQ,OAAO;AAAA,MAClC,QAAQ,SAAS;AAAA,MACjB,MAAM,QAAQ,QAAQ;AAAA,MACtB,OAAO,QAAQ,OAAO,WAAW,QAAQ,UAAU,SAAS,KAAK,SAAY;AAAA,IAC/E;AAAA,EACF;AACF;;;ACjsBO,IAAM,0BAAN,cAAsC,MAAM;AAAA,EACjD;AAAA,EAEA,YAAY,UAA+C;AACzD,UAAM,OAAO,SAAS,MAAM,mBAAmB;AAC/C,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EAClB;AACF;AAGA,IAAM,gBAAN,MAAoB;AAAA,EACV;AAAA,EACA,MAAM;AAAA,EACN,MAAM;AAAA,EACG;AAAA,EAEjB,YAAY,UAAkB;AAC5B,SAAK,MAAM;AACX,SAAK,MAAM,IAAI,MAAc,QAAQ,EAAE,KAAK,CAAC;AAAA,EAC/C;AAAA,EAEA,KAAK,KAAmB;AACtB,SAAK,IAAI,KAAK,GAAG,IAAI;AACrB,SAAK,OAAO,KAAK,MAAM,KAAK,KAAK;AACjC,QAAI,KAAK,MAAM,KAAK,IAAK,MAAK;AAAA,EAChC;AAAA,EAEA,IAAI,QAAgB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,SAAmB;AACjB,WAAO,KAAK,IAAI,MAAM,GAAG,KAAK,GAAG,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,EACzD;AAAA,EAEA,MAAc;AACZ,WAAO,KAAK,IAAI,MAAM,GAAG,KAAK,GAAG,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AAAA,EAC9D;AACF;AAEA,SAAS,WAAW,QAAkB,GAAmB;AACvD,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,MAAM,KAAK,KAAM,IAAI,MAAO,OAAO,MAAM,IAAI;AACnD,SAAO,OAAO,KAAK,IAAI,GAAG,GAAG,CAAC;AAChC;AAEA,IAAM,iBAAiB;AACvB,IAAM,4BAA4B;AAClC,IAAM,6BAA6B;AACnC,IAAM,qBAAqB;AAC3B,IAAM,sBAAsB;AAE5B,SAAS,oBAAoB,QAAgD;AAC3E,SAAO;AAAA,IACL,UAAU,OAAO;AAAA,IACjB,gBAAgB,OAAO,mBAAmB,SAAY,OAAO,iBAAiB;AAAA,IAC9E,YAAY,OAAO,eAAe,SAAY,OAAO,aAAa;AAAA,IAClE,uBAAuB,OAAO,0BAA0B,SAAY,OAAO,wBAAwB;AAAA,IACnG,WAAW,OAAO,cAAc,SAAY,OAAO,YAAY;AAAA,EACjE;AACF;AAaO,IAAM,gBAAN,MAAoB;AAAA,EACR;AAAA,EACT;AAAA,EACS,QAAoC,oBAAI,IAAI;AAAA,EACrD,YAAY;AAAA,EACZ,cAAqD;AAAA,EAE7D,YAAY,WAA0B,QAAwB;AAC5D,SAAK,YAAY,UAAU,MAAM;AACjC,SAAK,SAAS,oBAAoB,UAAU,EAAE,UAAU,WAAW,CAAC;AAEpE,eAAW,KAAK,KAAK,WAAW;AAC9B,WAAK,MAAM,IAAI,EAAE,MAAM;AAAA,QACrB,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,iBAAiB;AAAA,QACjB,WAAW,IAAI,cAAc,cAAc;AAAA,QAC3C,OAAO,IAAI,cAAc,cAAc;AAAA,QACvC,aAAa;AAAA,QACb,WAAW;AAAA,QACX,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AAEA,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEA,MAAM,SAAS,KAAuC;AACpD,UAAM,UAAU,KAAK,gBAAgB,GAAG;AAExC,QAAI,QAAQ,WAAW,GAAG;AACxB,YAAM,IAAI,wBAAwB,CAAC,CAAC;AAAA,IACtC;AAEA,UAAM,cAAc,KAAK,OAAO,mBAAmB;AACnD,UAAM,cAAc,cAAc,KAAK,KAAK,OAAO,cAAc,uBAAuB;AACxF,UAAM,WAAuD,CAAC;AAC9D,UAAM,YAAY,KAAK,OAAO,aAAa;AAE3C,aAAS,IAAI,GAAG,IAAI,QAAQ,UAAU,SAAS,SAAS,aAAa,KAAK;AACxE,YAAM,WAAW,QAAQ,CAAC;AAC1B,YAAM,KAAK,KAAK,MAAM,IAAI,SAAS,IAAI;AACvC,SAAG;AAEH,YAAM,KAAK,IAAI,gBAAgB;AAC/B,YAAM,KAAK,YAAY,IAAI;AAE3B,UAAI;AACF,cAAM,iBAAiB,IAAI,QAAe,CAAC,GAAG,WAAW;AACvD,gBAAM,IAAI,WAAW,MAAM;AACzB,eAAG,MAAM;AACT,mBAAO,IAAI,MAAM,0BAA0B,SAAS,IAAI,CAAC;AAAA,UAC3D,GAAG,SAAS;AAEZ,cAAI,EAAE,MAAO,GAAE,MAAM;AAAA,QACvB,CAAC;AAED,cAAM,UAAU,MAAM,QAAQ,KAAK,CAAC,SAAS,OAAO,KAAK,GAAG,MAAM,GAAG,cAAc,CAAC;AACpF,cAAM,YAAY,KAAK,MAAM,YAAY,IAAI,IAAI,EAAE;AAEnD,cAAM,UAAU,YAAY,UAAU,QAAQ,KAAK;AACnD,WAAG,UAAU,KAAK,SAAS;AAC3B,YAAI,YAAY,OAAW,IAAG,MAAM,KAAK,OAAO;AAChD,WAAG;AAEH,YAAI,KAAK,OAAO,aAAa,eAAe;AAC1C,eAAK;AAAA,QACP;AAEA,eAAO;AAAA,UACL,GAAG;AAAA,UACH,UAAU,SAAS;AAAA,UACnB,OAAO,SAAS;AAAA,UAChB;AAAA,UACA;AAAA,QACF;AAAA,MACF,SAAS,KAAc;AACrB,WAAG;AACH,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,iBAAS,KAAK,EAAE,UAAU,SAAS,MAAM,OAAO,IAAI,CAAC;AAErD,YAAI,CAAC,YAAa;AAAA,MACpB;AAAA,IACF;AAEA,UAAM,IAAI,wBAAwB,QAAQ;AAAA,EAC5C;AAAA,EAEA,IAAI,QAAuC;AACzC,UAAM,SAAwC,CAAC;AAC/C,eAAW,KAAK,KAAK,WAAW;AAC9B,YAAM,KAAK,KAAK,MAAM,IAAI,EAAE,IAAI;AAChC,YAAM,YAAY,GAAG,UAAU,OAAO;AACtC,YAAM,aAAa,GAAG,MAAM,OAAO;AACnC,aAAO,EAAE,IAAI,IAAI;AAAA,QACf,aAAa,GAAG;AAAA,QAChB,WAAW,GAAG;AAAA,QACd,UAAU,GAAG;AAAA,QACb,OAAO,WAAW,WAAW,EAAE;AAAA,QAC/B,OAAO,WAAW,WAAW,EAAE;AAAA,QAC/B,YAAY,GAAG,MAAM,QAAQ,IAAI,GAAG,MAAM,IAAI,IAAI,GAAG,MAAM,QAAQ;AAAA,MACrE;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,UAAU,QAA6B;AACrC,SAAK,SAAS,oBAAoB,MAAM;AAExC,SAAK,YAAY;AAEjB,SAAK,iBAAiB;AACtB,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEA,iBAAiB,MAAoB;AACnC,UAAM,KAAK,KAAK,MAAM,IAAI,IAAI;AAC9B,QAAI,GAAI,IAAG,aAAa;AAAA,EAC1B;AAAA,EAEA,eAAe,MAAoB;AACjC,UAAM,KAAK,KAAK,MAAM,IAAI,IAAI;AAC9B,QAAI,IAAI;AACN,SAAG,aAAa;AAChB,SAAG,aAAa;AAChB,SAAG,kBAAkB;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,mBAAyB;AACvB,QAAI,KAAK,gBAAgB,MAAM;AAC7B,oBAAc,KAAK,WAAW;AAC9B,WAAK,cAAc;AAAA,IACrB;AAAA,EACF;AAAA,EAEQ,oBAA0B;AAChC,UAAM,WAAW,KAAK,OAAO,yBAAyB;AACtD,UAAM,qBAAqB,KAAK,UAAU,OAAO,CAAC,MAAM,EAAE,gBAAgB,MAAS;AACnF,QAAI,mBAAmB,WAAW,EAAG;AAErC,SAAK,cAAc,YAAY,MAAM;AACnC,WAAK,KAAK,gBAAgB,QAAQ;AAAA,IACpC,GAAG,QAAQ;AAGX,QAAI,KAAK,YAAY,OAAO;AAC1B,WAAK,YAAY,MAAM;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,MAAc,gBAAgB,YAAmC;AAC/D,eAAW,KAAK,KAAK,WAAW;AAC9B,UAAI,CAAC,EAAE,YAAa;AACpB,YAAM,KAAK,KAAK,MAAM,IAAI,EAAE,IAAI;AAGhC,UAAI,GAAG,cAAc,GAAG,kBAAkB,KAAK,KAAK,IAAI,KAAK,GAAG,iBAAiB;AAC/E,WAAG,aAAa;AAChB,WAAG,kBAAkB;AAAA,MACvB;AAEA,UAAI;AACF,cAAM,UAAU,MAAM,EAAE,YAAY;AACpC,YAAI,CAAC,SAAS;AACZ,aAAG,aAAa;AAChB,aAAG,kBAAkB,KAAK,IAAI,IAAI;AAAA,QACpC,OAAO;AACL,aAAG,aAAa;AAChB,aAAG,kBAAkB;AAAA,QACvB;AAAA,MACF,QAAQ;AACN,WAAG,aAAa;AAChB,WAAG,kBAAkB,KAAK,IAAI,IAAI;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,sBAAqC;AACzC,UAAM,KAAK,gBAAgB,KAAK,OAAO,yBAAyB,0BAA0B;AAAA,EAC5F;AAAA,EAEQ,OAAO,MAAuB;AACpC,UAAM,KAAK,KAAK,MAAM,IAAI,IAAI;AAC9B,QAAI,CAAC,GAAI,QAAO;AAChB,QAAI,GAAG,WAAY,QAAO;AAC1B,QAAI,GAAG,YAAY;AAEjB,UAAI,GAAG,kBAAkB,KAAK,KAAK,IAAI,KAAK,GAAG,iBAAiB;AAC9D,WAAG,aAAa;AAChB,WAAG,kBAAkB;AACrB,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,gBAAgB,UAAuB,KAAqC;AAClF,QAAI,CAAC,SAAS,QAAS,QAAO;AAE9B,UAAM,cAAc,IAAI,SAAS,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,QAAQ,QAAQ,CAAC;AACzE,UAAM,eAAe,KAAK,KAAK,cAAc,CAAC;AAC9C,UAAM,mBAAmB,IAAI,aAAa;AAC1C,WACG,eAAe,MAAQ,SAAS,QAAQ,gBACxC,mBAAmB,MAAQ,SAAS,QAAQ;AAAA,EAEjD;AAAA,EAEQ,gBAAgB,KAAgC;AACtD,QAAI,aAAa,KAAK,UAAU,OAAO,CAAC,MAAM,CAAC,KAAK,OAAO,EAAE,IAAI,CAAC;AAGlE,QAAI,IAAI,gBAAgB,IAAI,aAAa,SAAS,GAAG;AACnD,mBAAa,WAAW,OAAO,CAAC,MAAM;AACpC,cAAM,OAAO,EAAE,gBAAgB,CAAC;AAChC,eAAO,IAAI,aAAc,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;AAAA,MACxD,CAAC;AAAA,IACH;AAGA,QAAI,IAAI,eAAe,QAAW;AAChC,mBAAa,WAAW,OAAO,CAAC,MAAM;AACpC,cAAM,MAAM,KAAK,gBAAgB,GAAG,GAAG;AACvC,YAAI,QAAQ,OAAW,QAAO;AAC9B,eAAO,OAAO,IAAI;AAAA,MACpB,CAAC;AAAA,IACH;AAGA,QAAI,IAAI,iBAAiB,QAAW;AAClC,mBAAa,WAAW,OAAO,CAAC,MAAM;AACpC,cAAM,KAAK,KAAK,MAAM,IAAI,EAAE,IAAI;AAChC,YAAI,GAAG,UAAU,UAAU,EAAG,QAAO;AACrC,cAAM,YAAY,GAAG,UAAU,OAAO;AACtC,eAAO,WAAW,WAAW,EAAE,KAAK,IAAI;AAAA,MAC1C,CAAC;AAAA,IACH;AAGA,YAAQ,KAAK,OAAO,UAAU;AAAA,MAC5B,KAAK;AACH,mBAAW,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AACjD;AAAA,MAEF,KAAK;AACH,mBAAW,KAAK,CAAC,GAAG,MAAM;AACxB,gBAAM,KAAK,KAAK,gBAAgB,GAAG,GAAG,KAAK;AAC3C,gBAAM,KAAK,KAAK,gBAAgB,GAAG,GAAG,KAAK;AAC3C,iBAAO,OAAO,KAAK,KAAK,KAAK,EAAE,WAAW,EAAE;AAAA,QAC9C,CAAC;AACD;AAAA,MAEF,KAAK,WAAW;AACd,mBAAW,KAAK,CAAC,GAAG,MAAM;AACxB,gBAAM,MAAM,KAAK,MAAM,IAAI,EAAE,IAAI;AACjC,gBAAM,MAAM,KAAK,MAAM,IAAI,EAAE,IAAI;AACjC,gBAAM,OAAO,IAAI,UAAU,QAAQ,IAAI,WAAW,IAAI,UAAU,OAAO,GAAG,EAAE,IAAI;AAChF,gBAAM,OAAO,IAAI,UAAU,QAAQ,IAAI,WAAW,IAAI,UAAU,OAAO,GAAG,EAAE,IAAI;AAChF,iBAAO,SAAS,OAAO,OAAO,OAAO,EAAE,WAAW,EAAE;AAAA,QACtD,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,eAAe;AAClB,YAAI,WAAW,WAAW,EAAG;AAE7B,cAAM,QAAQ,KAAK,YAAY,WAAW;AAC1C,qBAAa,CAAC,GAAG,WAAW,MAAM,KAAK,GAAG,GAAG,WAAW,MAAM,GAAG,KAAK,CAAC;AACvE;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,YACP,UACA,OACoB;AACpB,MAAI,CAAC,SAAS,QAAS,QAAO;AAC9B,SACG,MAAM,eAAe,MAAQ,SAAS,QAAQ,gBAC9C,MAAM,mBAAmB,MAAQ,SAAS,QAAQ;AAEvD;;;AC7ZA,YAAYC,aAAY;AACxB,YAAYC,SAAQ;AACpB,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB,SAAS,YAAY,kBAAkB;AACvC,SAAS,iBAAiB;AAE1B,IAAM,WAAW,UAAU,UAAU;AA2B9B,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAChD,cAAc;AACZ,UAAM,mEAAmE;AACzE,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAChD,YAAY,IAAY,OAAgB;AACtC,UAAM,YAAY,EAAE,YAAY,OAAO,KAAK,CAAC,EAAE;AAC/C,SAAK,OAAO;AAAA,EACd;AACF;AAOO,IAAM,4BAAN,cAAwC,MAAM;AAAA,EAC1C;AAAA,EACT,YAAY,SAA0B,IAAY;AAChD,UAAM,iCAAiC,EAAE,aAAa,OAAO,GAAG;AAChE,SAAK,OAAO;AACZ,SAAK,UAAU;AAAA,EACjB;AACF;AAMA,SAAS,kBAAkB,KAAuB;AAChD,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO;AACpD,QAAM,MAAM;AACZ,MAAI,IAAI,SAAS,MAAM,IAAI,SAAS,GAAI,QAAO;AAC/C,MAAI,OAAO,IAAI,WAAW,UAAU;AAClC,UAAM,MAAM,IAAI,OAAO,YAAY;AACnC,QAAI,IAAI,SAAS,iCAAiC,EAAG,QAAO;AAC5D,QAAI,IAAI,SAAS,uBAAuB,EAAG,QAAO;AAClD,QAAI,IAAI,SAAS,eAAe,EAAG,QAAO;AAAA,EAC5C;AACA,SAAO;AACT;AAUA,SAAS,UAAU,WAA8B;AAC/C,MAAI;AACF,UAAM,MAAS,iBAAa,WAAW,OAAO;AAC9C,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,WAAW,WAAmB,MAAuB;AAC5D,QAAM,MAAM,YAAY;AACxB,EAAG,kBAAc,KAAK,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,OAAO;AAC5D,EAAG,eAAW,KAAK,SAAS;AAC9B;AAEA,SAAS,SAAS,WAAmB,SAAiB,SAAuB;AAC3E,QAAM,OAAO,UAAU,SAAS;AAChC,MAAI,CAAC,KAAK,OAAO,EAAG,MAAK,OAAO,IAAI,CAAC;AACrC,MAAI,CAAC,KAAK,OAAO,EAAE,SAAS,OAAO,EAAG,MAAK,OAAO,EAAE,KAAK,OAAO;AAChE,aAAW,WAAW,IAAI;AAC5B;AAEA,SAAS,YAAY,WAAmB,SAAiB,SAAuB;AAC9E,QAAM,OAAO,UAAU,SAAS;AAChC,MAAI,CAAC,KAAK,OAAO,EAAG;AACpB,OAAK,OAAO,IAAI,KAAK,OAAO,EAAE,OAAO,CAAC,MAAM,MAAM,OAAO;AACzD,MAAI,KAAK,OAAO,EAAE,WAAW,EAAG,QAAO,KAAK,OAAO;AACnD,aAAW,WAAW,IAAI;AAC5B;AAEA,SAAS,UAAU,WAAmB,SAA2B;AAC/D,QAAM,OAAO,UAAU,SAAS;AAChC,UAAQ,KAAK,OAAO,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK;AAC5C;AAMA,IAAM,oBAAyB,WAAQ,YAAQ,GAAG,YAAY,qBAAqB;AAEnF,SAAS,UAAU,GAAiB;AAClC,EAAG,cAAe,cAAQ,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;AACnD;AAEA,IAAM,uBAAN,MAAsD;AAAA,EAC3C,OAAwB;AAAA,EAEjC,MAAM,YAA8B;AAClC,QAAI,QAAQ,aAAa,SAAU,QAAO;AAC1C,QAAI;AACF,YAAM,SAAS,SAAS,CAAC,UAAU,CAAC;AACpC,YAAM,SAAS,YAAY,CAAC,gBAAgB,CAAC;AAC7C,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,SAAiB,SAAyC;AAClE,QAAI;AACF,YAAM,EAAE,OAAO,IAAI,MAAM,SAAS,YAAY;AAAA,QAC5C;AAAA,QACA;AAAA,QAAM;AAAA,QACN;AAAA,QAAM;AAAA,QACN;AAAA,MACF,CAAC;AACD,aAAO,OAAO,KAAK;AAAA,IACrB,SAAS,KAAc;AAErB,UAAI,aAAa,GAAG,EAAG,QAAO;AAC9B,UAAI,kBAAkB,GAAG,EAAG,OAAM,IAAI,0BAA0B,KAAK,MAAM,KAAK;AAChF,YAAM,IAAI,uBAAuB,OAAO,GAAG;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,SAAiB,SAAiB,OAA8B;AACxE,QAAI;AAIF,YAAM,WAAW,OAAO,KAAK,OAAO,OAAO,EAAE,SAAS,KAAK;AAC3D,YAAM,SAAS,YAAY;AAAA,QACzB;AAAA,QACA;AAAA,QAAM;AAAA,QACN;AAAA,QAAM;AAAA,QACN;AAAA,QAAM;AAAA,QACN;AAAA,MACF,CAAC;AACD,gBAAU,iBAAiB;AAE3B,UAAI;AAAE,QAAG,cAAe,cAAQ,iBAAiB,GAAG,GAAK;AAAA,MAAG,QAAQ;AAAA,MAAe;AACnF,eAAS,mBAAmB,SAAS,OAAO;AAAA,IAC9C,SAAS,KAAc;AACrB,UAAI,kBAAkB,GAAG,EAAG,OAAM,IAAI,0BAA0B,KAAK,MAAM,KAAK;AAChF,YAAM,IAAI,uBAAuB,OAAO,GAAG;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,SAAiB,SAAgC;AAC5D,QAAI;AACF,YAAM,SAAS,YAAY;AAAA,QACzB;AAAA,QACA;AAAA,QAAM;AAAA,QACN;AAAA,QAAM;AAAA,MACR,CAAC;AACD,kBAAY,mBAAmB,SAAS,OAAO;AAAA,IACjD,SAAS,KAAc;AACrB,UAAI,aAAa,GAAG,EAAG;AACvB,YAAM,IAAI,uBAAuB,UAAU,GAAG;AAAA,IAChD;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,SAAoC;AAC7C,WAAO,UAAU,mBAAmB,OAAO;AAAA,EAC7C;AACF;AAEA,SAAS,aAAa,KAAuB;AAC3C,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,UAAU,KAAK;AAC5D,WAAQ,IAA0B,SAAS;AAAA,EAC7C;AACA,SAAO;AACT;AAIA,SAAS,oBAAoB,KAAuB;AAClD,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,UAAU,KAAK;AAC5D,WAAQ,IAA0B,SAAS;AAAA,EAC7C;AACA,SAAO;AACT;AAMA,IAAM,mBAAN,MAAkD;AAAA,EACvC,OAAwB;AAAA,EAEjC,MAAM,YAA8B;AAClC,QAAI,QAAQ,aAAa,QAAS,QAAO;AACzC,QAAI;AACF,YAAM,SAAS,SAAS,CAAC,aAAa,CAAC;AAEvC,YAAM,SAAS,eAAe,CAAC,UAAU,iBAAiB,aAAa,CAAC;AACxE,aAAO;AAAA,IACT,SAAS,KAAc;AAIrB,UAAI,aAAa,GAAG,EAAG,QAAO;AAC9B,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,SAAiB,SAAyC;AAClE,QAAI;AACF,YAAM,EAAE,OAAO,IAAI,MAAM,SAAS,eAAe;AAAA,QAC/C;AAAA,QACA;AAAA,QAAmB;AAAA,QACnB;AAAA,QAAmB;AAAA,MACrB,CAAC;AACD,YAAM,UAAU,OAAO,KAAK;AAC5B,aAAO,QAAQ,SAAS,IAAI,UAAU;AAAA,IACxC,SAAS,KAAc;AACrB,UAAI,oBAAoB,GAAG,EAAG,QAAO;AACrC,YAAM,IAAI,uBAAuB,OAAO,GAAG;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,SAAiB,SAAiB,OAA8B;AACxE,QAAI;AAEF,YAAM,QAAQ,WAAW,eAAe;AAAA,QACtC;AAAA,QACA;AAAA,QAAW,GAAG,OAAO,IAAI,OAAO;AAAA,QAChC;AAAA,QAAmB;AAAA,QACnB;AAAA,QAAmB;AAAA,MACrB,CAAC;AACD,YAAM,MAAO,MAAM,KAAK;AACxB,YAAM,MAAO,IAAI;AACjB,YAAM,IAAI,QAAc,CAACC,UAAS,WAAW;AAC3C,cAAM,GAAG,SAAS,CAAC,SAAU,SAAS,IAAIA,SAAQ,IAAI,OAAO,IAAI,MAAM,QAAQ,IAAI,EAAE,CAAC,CAAE;AACxF,cAAM,GAAG,SAAS,MAAM;AAAA,MAC1B,CAAC;AACD,gBAAU,iBAAiB;AAC3B,eAAS,mBAAmB,SAAS,OAAO;AAAA,IAC9C,SAAS,KAAc;AACrB,YAAM,IAAI,uBAAuB,OAAO,GAAG;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,SAAiB,SAAgC;AAC5D,QAAI;AACF,YAAM,SAAS,eAAe;AAAA,QAC5B;AAAA,QACA;AAAA,QAAmB;AAAA,QACnB;AAAA,QAAmB;AAAA,MACrB,CAAC;AACD,kBAAY,mBAAmB,SAAS,OAAO;AAAA,IACjD,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,SAAoC;AAC7C,WAAO,UAAU,mBAAmB,OAAO;AAAA,EAC7C;AACF;AAEA,SAAS,aAAa,KAAuB;AAC3C,MAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,SAAS,KAAK;AAC3D,UAAM,MAAO,IAAyB,OAAO;AAC7C,WAAO,IAAI,WAAW,OAAO;AAAA,EAC/B;AACA,SAAO;AACT;AAMA,IAAM,cAAN,MAA6C;AAAA,EAClC,OAAwB;AAAA,EAEjC,MAAM,YAA8B;AAClC,QAAI,QAAQ,aAAa,QAAS,QAAO;AACzC,QAAI;AACF,YAAM,SAAS,SAAS,CAAC,MAAM,CAAC;AAChC,YAAM,SAAS,QAAQ,CAAC,WAAW,CAAC;AACpC,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,SAAiB,SAAyC;AAClE,QAAI;AACF,YAAM,EAAE,OAAO,IAAI,MAAM,SAAS,QAAQ;AAAA,QACxC;AAAA,QACA,WAAW,OAAO,IAAI,OAAO;AAAA,MAC/B,CAAC;AACD,aAAO,OAAO,KAAK;AAAA,IACrB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,SAAiB,SAAiB,OAA8B;AACxE,QAAI;AACF,YAAM,QAAQ,WAAW,QAAQ;AAAA,QAC/B;AAAA,QACA;AAAA,QACA,WAAW,OAAO,IAAI,OAAO;AAAA,MAC/B,CAAC;AACD,YAAM,MAAO,MAAM,KAAK;AACxB,YAAM,MAAO,IAAI;AACjB,YAAM,IAAI,QAAc,CAACA,UAAS,WAAW;AAC3C,cAAM,GAAG,SAAS,CAAC,SAAU,SAAS,IAAIA,SAAQ,IAAI,OAAO,IAAI,MAAM,QAAQ,IAAI,EAAE,CAAC,CAAE;AACxF,cAAM,GAAG,SAAS,MAAM;AAAA,MAC1B,CAAC;AACD,gBAAU,iBAAiB;AAC3B,eAAS,mBAAmB,SAAS,OAAO;AAAA,IAC9C,SAAS,KAAc;AACrB,YAAM,IAAI,uBAAuB,OAAO,GAAG;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,SAAiB,SAAgC;AAC5D,QAAI;AACF,YAAM,SAAS,QAAQ;AAAA,QACrB;AAAA,QACA;AAAA,QACA,WAAW,OAAO,IAAI,OAAO;AAAA,MAC/B,CAAC;AACD,kBAAY,mBAAmB,SAAS,OAAO;AAAA,IACjD,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,SAAoC;AAC7C,WAAO,UAAU,mBAAmB,OAAO;AAAA,EAC7C;AACF;AAMA,IAAM,oBAAoB;AAC1B,IAAM,kBAAkB;AACxB,IAAM,gBAAgB;AACtB,IAAM,mBAAmB;AACzB,IAAM,sBAAsB;AAO5B,SAAS,UAAU,YAAoB,MAAsB;AAC3D,SAAc,mBAAW,YAAY,MAAM,gBAAgB;AAC7D;AAEA,SAAS,aAAa,OAAqB,YAA4B;AACrE,QAAM,OAAc,oBAAY,iBAAiB;AACjD,QAAM,QAAe,oBAAY,eAAe;AAChD,QAAM,MAAM,UAAU,YAAY,IAAI;AACtC,QAAM,YAAY,OAAO,KAAK,KAAK,UAAU,KAAK,GAAG,OAAO;AAE5D,QAAM,SAAgB,uBAAe,eAAe,KAAK,KAAK;AAC9D,QAAM,aAAa,OAAO,OAAO,CAAC,OAAO,OAAO,SAAS,GAAG,OAAO,MAAM,CAAC,CAAC;AAC3E,QAAM,MAAM,OAAO,WAAW;AAE9B,SAAO,OAAO,OAAO,CAAC,MAAM,OAAO,YAAY,GAAG,CAAC;AACrD;AAEA,SAAS,aAAa,MAAc,YAAkC;AACpE,MAAI,KAAK,SAAS,oBAAoB,kBAAkB,eAAe;AACrE,UAAM,IAAI,uBAAuB,WAAW,qCAAqC;AAAA,EACnF;AAEA,QAAM,OAAO,KAAK,SAAS,GAAG,iBAAiB;AAC/C,QAAM,QAAQ,KAAK,SAAS,mBAAmB,oBAAoB,eAAe;AAClF,QAAM,MAAM,KAAK,SAAS,KAAK,SAAS,aAAa;AACrD,QAAM,aAAa,KAAK,SAAS,oBAAoB,iBAAiB,KAAK,SAAS,aAAa;AAEjG,QAAM,MAAM,UAAU,YAAY,IAAI;AAEtC,MAAI;AACF,UAAM,WAAkB,yBAAiB,eAAe,KAAK,KAAK;AAClE,aAAS,WAAW,GAAG;AACvB,UAAM,YAAY,OAAO,OAAO,CAAC,SAAS,OAAO,UAAU,GAAG,SAAS,MAAM,CAAC,CAAC;AAC/E,WAAO,KAAK,MAAM,UAAU,SAAS,OAAO,CAAC;AAAA,EAC/C,QAAQ;AACN,UAAM,IAAI,uBAAuB,WAAW,qCAAqC;AAAA,EACnF;AACF;AAEA,IAAM,uBAAN,MAAsD;AAAA,EAC3C,OAAwB;AAAA,EAChB;AAAA,EACA;AAAA,EAEjB,YAAY,UAAkB,YAAoB;AAChD,SAAK,WAAW;AAChB,SAAK,aAAa;AAElB,UAAM,QAAQ,WAAW;AACzB,QAAI;AAAE,UAAO,eAAW,KAAK,EAAG,CAAG,eAAW,KAAK;AAAA,IAAG,QAAQ;AAAA,IAAoB;AAAA,EACpF;AAAA,EAEA,MAAM,YAA8B;AAClC,WAAO;AAAA,EACT;AAAA,EAEQ,YAA0B;AAChC,QAAI,CAAI,eAAW,KAAK,QAAQ,GAAG;AACjC,aAAO,EAAE,SAAS,qBAAqB,SAAS,CAAC,EAAE;AAAA,IACrD;AACA,UAAM,OAAU,iBAAa,KAAK,QAAQ;AAC1C,WAAO,aAAa,MAAM,KAAK,UAAU;AAAA,EAC3C;AAAA,EAEQ,WAAW,OAA2B;AAC5C,cAAU,KAAK,QAAQ;AAEvB,QAAI;AAAE,MAAG,cAAe,cAAQ,KAAK,QAAQ,GAAG,GAAK;AAAA,IAAG,QAAQ;AAAA,IAA4B;AAC5F,UAAM,YAAY,aAAa,OAAO,KAAK,UAAU;AACrD,UAAM,MAAM,KAAK,WAAW;AAC5B,IAAG,kBAAc,KAAK,SAAS;AAE/B,IAAG,cAAU,KAAK,GAAK;AACvB,IAAG,eAAW,KAAK,KAAK,QAAQ;AAAA,EAClC;AAAA,EAEA,MAAM,IAAI,SAAiB,SAAyC;AAClE,UAAM,QAAQ,KAAK,UAAU;AAC7B,WAAO,MAAM,QAAQ,OAAO,IAAI,OAAO,KAAK;AAAA,EAC9C;AAAA,EAEA,MAAM,IAAI,SAAiB,SAAiB,OAA8B;AACxE,UAAM,QAAQ,KAAK,UAAU;AAC7B,QAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,OAAM,QAAQ,OAAO,IAAI,CAAC;AACvD,UAAM,QAAQ,OAAO,EAAE,OAAO,IAAI;AAClC,SAAK,WAAW,KAAK;AAAA,EAEvB;AAAA,EAEA,MAAM,OAAO,SAAiB,SAAgC;AAC5D,QAAI,CAAI,eAAW,KAAK,QAAQ,EAAG;AACnC,UAAM,QAAQ,KAAK,UAAU;AAC7B,QAAI,CAAC,MAAM,QAAQ,OAAO,EAAG;AAC7B,WAAO,MAAM,QAAQ,OAAO,EAAE,OAAO;AACrC,QAAI,OAAO,KAAK,MAAM,QAAQ,OAAO,CAAC,EAAE,WAAW,GAAG;AACpD,aAAO,MAAM,QAAQ,OAAO;AAAA,IAC9B;AACA,SAAK,WAAW,KAAK;AAAA,EAEvB;AAAA,EAEA,MAAM,KAAK,SAAoC;AAC7C,QAAI,CAAI,eAAW,KAAK,QAAQ,EAAG,QAAO,CAAC;AAE3C,UAAM,QAAQ,KAAK,UAAU;AAC7B,WAAO,OAAO,KAAK,MAAM,QAAQ,OAAO,KAAK,CAAC,CAAC,EAAE,KAAK;AAAA,EACxD;AACF;AAMA,IAAM,yBAA8B,WAAQ,YAAQ,GAAG,YAAY,sBAAsB;AAElF,IAAM,WAAN,MAAe;AAAA,EACH;AAAA,EACT,kBAA0C;AAAA,EAC1C,YAAY;AAAA,EAEpB,YAAY,MAAwB;AAClC,SAAK,OAAO,QAAQ,CAAC;AAAA,EACvB;AAAA,EAEA,MAAM,UAAoC;AACxC,QAAI,KAAK,gBAAiB,QAAO,KAAK;AAEtC,UAAM,YAAY,KAAK,KAAK;AAG5B,UAAM,aAAgC,YAClC,CAAC,KAAK,YAAY,SAAS,CAAC,IAC5B,KAAK,mBAAmB;AAE5B,eAAW,aAAa,YAAY;AAClC,UAAI,MAAM,UAAU,UAAU,GAAG;AAC/B,aAAK,kBAAkB;AACvB,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,IAAI,uBAAuB;AAAA,EACnC;AAAA,EAEQ,qBAAwC;AAC9C,UAAM,aAAgC,CAAC;AACvC,QAAI,QAAQ,aAAa,UAAU;AACjC,iBAAW,KAAK,IAAI,qBAAqB,CAAC;AAAA,IAC5C,WAAW,QAAQ,aAAa,SAAS;AACvC,iBAAW,KAAK,IAAI,iBAAiB,CAAC;AACtC,iBAAW,KAAK,IAAI,YAAY,CAAC;AAAA,IACnC;AAEA,UAAM,aAAa,KAAK,KAAK,oBAAoB,QAAQ,IAAI,2BAA2B;AACxF,QAAI,YAAY;AACd,YAAM,WAAW,KAAK,KAAK,qBAAqB;AAChD,iBAAW,KAAK,IAAI,qBAAqB,UAAU,UAAU,CAAC;AAAA,IAChE;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,YAAY,MAAwC;AAC1D,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,eAAO,IAAI,qBAAqB;AAAA,MAClC,KAAK;AACH,eAAO,IAAI,iBAAiB;AAAA,MAC9B,KAAK;AACH,eAAO,IAAI,YAAY;AAAA,MACzB,KAAK,kBAAkB;AACrB,cAAM,aAAa,KAAK,KAAK,oBAAoB,QAAQ,IAAI,2BAA2B;AACxF,YAAI,CAAC,WAAY,OAAM,IAAI,uBAAuB;AAClD,cAAM,WAAW,KAAK,KAAK,qBAAqB;AAChD,eAAO,IAAI,qBAAqB,UAAU,UAAU;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,SAAiB,SAAyC;AAClE,YAAQ,MAAM,KAAK,QAAQ,GAAG,IAAI,SAAS,OAAO;AAAA,EACpD;AAAA,EAEA,MAAM,IAAI,SAAiB,SAAiB,OAA8B;AACxE,YAAQ,MAAM,KAAK,QAAQ,GAAG,IAAI,SAAS,SAAS,KAAK;AAAA,EAC3D;AAAA,EAEA,MAAM,OAAO,SAAiB,SAAgC;AAC5D,YAAQ,MAAM,KAAK,QAAQ,GAAG,OAAO,SAAS,OAAO;AAAA,EACvD;AAAA,EAEA,MAAM,KAAK,SAAoC;AAC7C,YAAQ,MAAM,KAAK,QAAQ,GAAG,KAAK,OAAO;AAAA,EAC5C;AACF;;;ACvkBA,YAAYC,SAAQ;AACpB,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB,OAAO,UAAU;AAgCV,IAAM,cAAN,cAA0B,MAAM;AAAA,EACrC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAMA,IAAM,iBAAiB;AAEhB,SAAS,wBAAwB,OAA4D;AAClG,MAAI,CAAC,MAAM,WAAW,cAAc,EAAG,QAAO;AAC9C,QAAM,OAAO,MAAM,MAAM,eAAe,MAAM;AAC9C,QAAM,WAAW,KAAK,QAAQ,GAAG;AACjC,MAAI,WAAW,KAAK,aAAa,KAAK,SAAS,GAAG;AAChD,UAAM,IAAI,YAAY,oCAAoC,KAAK,gDAA2C;AAAA,EAC5G;AACA,SAAO;AAAA,IACL,SAAS,KAAK,MAAM,GAAG,QAAQ;AAAA,IAC/B,SAAS,KAAK,MAAM,WAAW,CAAC;AAAA,EAClC;AACF;AAQA,eAAe,eACb,OACA,UACA,qBACoB;AACpB,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,SAAS,wBAAwB,KAAK;AAC5C,QAAI,WAAW,KAAM,QAAO;AAC5B,QAAI,CAAC,oBAAqB,QAAO;AACjC,UAAM,SAAS,MAAM,SAAS,IAAI,OAAO,SAAS,OAAO,OAAO;AAChE,QAAI,WAAW,MAAM;AACnB,YAAM,IAAI,YAAY,mBAAmB,OAAO,OAAO,IAAI,OAAO,OAAO,EAAE;AAAA,IAC7E;AACA,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,UAAM,UAAuB,CAAC;AAC9B,eAAW,QAAQ,OAAO;AACxB,cAAQ,KAAK,MAAM,eAAe,MAAM,UAAU,mBAAmB,CAAC;AAAA,IACxE;AACA,WAAO;AAAA,EACT;AAEA,MAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAC/C,UAAM,WAAuC,CAAC;AAC9C,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC1C,eAAS,CAAC,IAAI,MAAM,eAAe,GAAgB,UAAU,mBAAmB;AAAA,IAClF;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAMA,SAAS,oBAA4B;AACnC,SAAY,WAAQ,YAAQ,GAAG,YAAY,aAAa;AAC1D;AAMA,eAAsB,WAAW,MAAkD;AACjF,QAAM,aAAa,MAAM,QAAQ,kBAAkB;AACnD,QAAM,sBAAsB,MAAM,uBAAuB;AAEzD,MAAI,MAAqB;AACzB,MAAI;AACF,UAAS,iBAAa,YAAY,OAAO;AAAA,EAC3C,SAAS,KAAK;AACZ,UAAM,IAAI;AACV,QAAI,EAAE,SAAS,UAAU;AACvB,YAAM,IAAI,YAAY,yBAAyB,UAAU,KAAK,EAAE,OAAO,EAAE;AAAA,IAC3E;AAAA,EACF;AAEA,MAAI,SAAuB,CAAC;AAC5B,MAAI,QAAQ,MAAM;AAChB,QAAI;AACF,eAAS,KAAK,MAAM,GAAG;AAAA,IACzB,SAAS,KAAK;AACZ,YAAM,IAAI,YAAY,gCAAgC,OAAO,GAAG,CAAC,EAAE;AAAA,IACrE;AAAA,EACF;AAMA,QAAM,iBAAkB,OAAuF;AAC/G,QAAM,OAAsB;AAAA,IAC1B,GAAI;AAAA,EACN;AACA,MAAI,gBAAgB,YAAY,UAAa,KAAK,WAAW,QAAW;AACtE,SAAK,SAAS,eAAe;AAAA,EAC/B;AACA,MAAI,gBAAgB,aAAa,UAAa,KAAK,YAAY,QAAW;AACxE,SAAK,UAAU,eAAe;AAAA,EAChC;AAMA,MAAI,KAAK,WAAW,QAAW;AAC7B,UAAM,SAAS,QAAQ,IAAI,iBAAiB;AAC5C,QAAI,WAAW,UAAa,OAAO,SAAS,GAAG;AAC7C,WAAK,SAAS;AAAA,IAChB;AAAA,EACF;AAEA,MAAI,CAAC,MAAM,YAAY,CAAC,qBAAqB;AAC3C,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,MAAM,eAAe,MAA8B,KAAK,UAAU,mBAAmB;AACtG,SAAO;AACT;AAMA,eAAsB,YAAY,QAAuB,MAAyC;AAChG,QAAM,aAAa,MAAM,QAAQ,kBAAkB;AACnD,QAAM,YAAiB,cAAQ,UAAU;AACzC,EAAG,cAAU,WAAW,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAExD,MAAI;AAAE,IAAG,cAAU,WAAW,GAAK;AAAA,EAAG,QAAQ;AAAA,EAAqB;AAEnE,QAAM,aAAa,KAAK,UAAU,MAAsB;AACxD,QAAM,MAAM,aAAa;AAEzB,EAAG,kBAAc,KAAK,YAAY,EAAE,UAAU,SAAS,MAAM,IAAM,CAAC;AAEpE,MAAI;AAAE,IAAG,cAAU,KAAK,GAAK;AAAA,EAAG,QAAQ;AAAA,EAAoB;AAC5D,EAAG,eAAW,KAAK,UAAU;AAC/B;;;AC7LA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB,YAAYC,SAAQ;AACpB,OAAOC,WAAU;AA+BjB,IAAM,mBAAmB,oBAAI,IAAI;AAAA,EAC/B;AAAA,EAAU;AAAA,EAAW;AAAA,EAAS;AAAA,EAAe;AAAA,EAAU;AACzD,CAAC;AAKD,IAAM,kBAAkB;AAIxB,IAAM,kBAAkB;AAExB,SAAS,YAAY,SAA0B;AAC7C,SAAO,iBAAiB,IAAI,QAAQ,YAAY,CAAC;AACnD;AAEA,SAAS,cAAc,OAAwB;AAC7C,SAAO,gBAAgB,KAAK,KAAK;AACnC;AAEA,SAAS,cAAc,aAAqB,OAAwB;AAClE,MAAI,YAAY,WAAW,EAAG,QAAO;AACrC,MAAI,cAAc,KAAK,EAAG,QAAO;AACjC,SAAO;AACT;AAEA,SAAS,iBAAiB,OAAwB;AAChD,SAAO,MAAM,SAAS,MAAM,gBAAgB,KAAK,KAAK;AACxD;AAQA,eAAe,SACb,MACA,SACA,UACA,QACA,QACA,MACoB;AACpB,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,UAAU,QAAQ,KAAK,GAAG;AAChC,UAAMC,YAAW,QAAQ,QAAQ,SAAS,CAAC,KAAK;AAEhD,QAAI,KAAK,WAAW,WAAW,GAAG;AAChC,aAAO,QAAQ,KAAK,EAAE,MAAM,SAAS,QAAQ,+BAA+B,CAAC;AAC7E,WAAK,EAAE,OAAO,QAAQ,SAAS,YAAY,OAAO,kCAAkC,CAAC;AACrF,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,cAAcA,WAAU,IAAI,GAAG;AAElC,UAAI,iBAAiB,IAAI,GAAG;AAC1B,aAAK;AAAA,UACH,OAAO;AAAA,UACP,SAAS,GAAG,OAAO,uBAAuB,KAAK,MAAM,GAAG,CAAC,CAAC;AAAA,QAC5D,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,QAAQ,KAAK,GAAG;AAC7B,UAAM,UAAU;AAChB,UAAM,UAAU;AAChB,UAAM,cAAc,YAAY,OAAO,IAAI,OAAO;AAElD,QAAI;AACF,WAAK,EAAE,OAAO,QAAQ,SAAS,aAAa,OAAO,qBAAgB,OAAO,IAAI,OAAO,IAAI,CAAC;AAE1F,UAAI,CAAC,QAAQ;AACX,cAAM,SAAS,IAAI,SAAS,SAAS,IAAI;AAAA,MAC3C;AAEA,aAAO,SAAS,KAAK,EAAE,MAAM,SAAS,SAAS,QAAQ,CAAC;AACxD,WAAK,EAAE,OAAO,MAAM,SAAS,YAAY,OAAO,qBAAgB,OAAO,IAAI,OAAO,IAAI,CAAC;AACvF,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,YAAM,SAAS,OAAO,GAAG;AACzB,aAAO,OAAO,KAAK,EAAE,MAAM,SAAS,OAAO,OAAO,CAAC;AACnD,WAAK,EAAE,OAAO,SAAS,SAAS,qBAAqB,OAAO,KAAK,MAAM,GAAG,CAAC;AAC3E,aAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,UAAM,UAAuB,CAAC;AAC9B,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,OAAO,MAAM,SAAS,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,OAAO,CAAC,CAAC,GAAG,UAAU,QAAQ,QAAQ,IAAI;AAC5F,cAAQ,KAAK,IAAI;AAAA,IACnB;AACA,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;AAC7C,UAAM,UAAsC,CAAC;AAC7C,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,IAAI,GAAG;AACzC,cAAQ,CAAC,IAAI,MAAM,SAAS,GAAgB,CAAC,GAAG,SAAS,CAAC,GAAG,UAAU,QAAQ,QAAQ,IAAI;AAAA,IAC7F;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAMA,SAAS,aAAa,YAA0B;AAC9C,QAAM,UAAU,aAAa;AAC7B,MAAO,eAAW,OAAO,GAAG;AAC1B,UAAM,KAAK,KAAK,IAAI;AACpB,UAAM,YAAY,GAAG,UAAU,QAAQ,EAAE;AACzC,IAAG,iBAAa,YAAY,SAAS;AAErC,IAAG,cAAU,WAAW,GAAK;AAAA,EAC/B,OAAO;AACL,IAAG,iBAAa,YAAY,OAAO;AAEnC,IAAG,cAAU,SAAS,GAAK;AAAA,EAC7B;AACF;AAMA,SAASC,qBAA4B;AACnC,SAAY,WAAQ,YAAQ,GAAG,YAAY,aAAa;AAC1D;AAMA,eAAsB,eAAe,MAA4D;AAC/F,QAAM,aAAa,KAAK,cAAcA,mBAAkB;AACxD,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,OAAO,KAAK,WAAW,MAAM;AAEnC,QAAM,SAA+B,EAAE,UAAU,CAAC,GAAG,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE;AAE7E,OAAK,EAAE,OAAO,QAAQ,SAAS,uBAAuB,UAAU,GAAG,CAAC;AAEpE,MAAI,CAAI,eAAW,UAAU,GAAG;AAC9B,SAAK,EAAE,OAAO,QAAQ,SAAS,uBAAuB,CAAC;AACvD,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AACF,UAAS,iBAAa,YAAY,OAAO;AAAA,EAC3C,SAAS,KAAK;AACZ,SAAK,EAAE,OAAO,SAAS,SAAS,0BAA0B,OAAO,GAAG,CAAC,GAAG,CAAC;AACzE,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AACF,aAASC,MAAK,MAAM,GAAG;AAAA,EACzB,SAAS,KAAK;AACZ,UAAM,IAAI,YAAY,gCAAgC,OAAO,GAAG,CAAC,EAAE;AAAA,EACrE;AAEA,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA,CAAC;AAAA,IACD,KAAK;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,CAAC,UAAU,OAAO,SAAS,SAAS,GAAG;AACzC,iBAAa,UAAU;AACvB,SAAK,EAAE,OAAO,QAAQ,SAAS,gCAAgC,UAAU,OAAO,CAAC;AAEjF,UAAM,aAAaA,MAAK,UAAU,OAAkC;AACpE,UAAM,MAAM,aAAa;AACzB,IAAG,kBAAc,KAAK,YAAY,OAAO;AAEzC,IAAG,cAAU,KAAK,GAAK;AACvB,IAAG,eAAW,KAAK,UAAU;AAC7B,SAAK,EAAE,OAAO,MAAM,SAAS,4CAA4C,CAAC;AAAA,EAC5E;AAEA,OAAK;AAAA,IACH,OAAO;AAAA,IACP,SAAS,SAAS,OAAO,SAAS,MAAM,cAAc,OAAO,QAAQ,MAAM,aAAa,OAAO,OAAO,MAAM;AAAA,EAC9G,CAAC;AAED,SAAO;AACT;;;ACvOA,YAAYC,UAAQ;AACpB,YAAYC,UAAQ;AACpB,YAAYC,YAAU;AACtB,YAAYC,aAAY;;;ACexB,YAAYC,SAAQ;AACpB,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB,YAAY,UAAU;AAStB,SAAS,yBAAuD;AAC9D,QAAM,UAAU;AAChB,MAAI,OAAO,QAAQ,qBAAqB,YAAY;AAClD,WAAO,QAAQ,iBAAiB,KAAK,IAAI;AAAA,EAC3C;AACA,SAAO;AACT;AAKO,IAAM,qBAAqB;AAe3B,SAAS,iBAAiB,WAA4B;AAC3D,MAAI,OAAO,cAAc,SAAU,QAAO;AAC1C,MAAI,CAAC,mBAAmB,KAAK,SAAS,EAAG,QAAO;AAGhD,MAAI,UAAU,SAAS,IAAI,EAAG,QAAO;AACrC,SAAO;AACT;AAwBO,IAAM,cAAN,MAAkB;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACT,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,UAAU;AAAA,EAElB,YAAY,MAA0B;AACpC,QAAI,CAAC,iBAAiB,KAAK,SAAS,GAAG;AACrC,YAAM,IAAI;AAAA,QACR,oCAAoC,KAAK,SAAS,iBAAiB,kBAAkB;AAAA,MACvF;AAAA,IACF;AAEA,SAAK,aAAa,KAAK;AAEvB,UAAM,WAAW,KAAK,YAAiB,WAAK,KAAK,WAAc,YAAQ,GAAG,YAAY,OAAO;AAC7F,SAAK,YAAiB,WAAK,UAAU,GAAG,KAAK,SAAS,YAAY;AAElE,SAAK,YAAY,uBAAuB;AAExC,QAAI,CAAC,KAAK,WAAW;AAEnB,UAAI;AACF,gBAAQ,OAAO;AAAA,UACb;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AACA;AAAA,IACF;AAIA,UAAM,YAAiB,cAAQ,KAAK,SAAS;AAC7C,QAAI;AACF,MAAG,cAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,IAC7C,SAAS,KAAK;AAEZ,UAAI;AACF,gBAAQ,OAAO;AAAA,UACb,4CAA4C,SAAS,KACnD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CACjD;AAAA;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAAe;AAAA,IACzB;AAAA,EACF;AAAA;AAAA,EAGA,IAAI,WAAmB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,YAAoB;AACtB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,eAAuB;AACzB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,WAAoB;AACtB,WAAO,KAAK,cAAc;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,OAA+B;AACpC,QAAI,KAAK,QAAS;AAClB,QAAI,CAAC,KAAK,UAAW;AAErB,QAAI;AACJ,QAAI;AACF,YAAM,OAAO,KAAK,UAAU,KAAK,IAAI;AACrC,mBAAa,KAAK,UAAU,OAAO,KAAK,MAAM,MAAM,CAAC;AAAA,IACvD,SAAS,KAAK;AACZ,UAAI,CAAC,KAAK,oBAAoB;AAC5B,aAAK,qBAAqB;AAC1B,YAAI;AACF,kBAAQ,OAAO;AAAA,YACb,gEAAgE,KAAK,UAAU,KAC7E,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CACjD;AAAA;AAAA,UACF;AAAA,QACF,QAAQ;AAAA,QAAe;AAAA,MACzB;AACA;AAAA,IACF;AAEA,QAAI;AACF,MAAG,mBAAe,KAAK,WAAW,YAAY,EAAE,MAAM,IAAM,CAAC;AAC7D,WAAK,iBAAiB,WAAW;AAAA,IACnC,SAAS,KAAK;AACZ,UAAI,CAAC,KAAK,oBAAoB;AAC5B,aAAK,qBAAqB;AAC1B,YAAI;AACF,kBAAQ,OAAO;AAAA,YACb,oDAAoD,KAAK,UAAU,KACjE,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CACjD;AAAA;AAAA,UACF;AAAA,QACF,QAAQ;AAAA,QAAe;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAc;AACZ,SAAK,UAAU;AAAA,EACjB;AACF;AAsBO,IAAM,qBAAN,MAAyB;AAAA,EACb,WAAW,oBAAI,IAAyB;AAAA,EACxC;AAAA,EACA;AAAA;AAAA;AAAA,EAGA,sBAAsB,oBAAI,IAAY;AAAA,EAEvD,YAAY,MAAkC;AAC5C,SAAK,WAAW,MAAM;AACtB,SAAK,YAAY,MAAM;AAAA,EACzB;AAAA;AAAA,EAGS,SAAS,CAAC,OAA+B;AAChD,UAAM,YAAY,iBAAiB,EAAE;AAErC,QAAI,GAAG,UAAU,yBAAyB;AACxC,UAAI,WAAW;AACb,aAAK,YAAY,SAAS;AAC1B,cAAMC,UAAS,KAAK,SAAS,IAAI,SAAS;AAC1C,YAAIA,QAAQ,CAAAA,QAAO,OAAO,EAAE;AAAA,MAC9B;AACA;AAAA,IACF;AAEA,QAAI,GAAG,UAAU,uBAAuB;AACtC,UAAI,WAAW;AACb,cAAMA,UAAS,KAAK,SAAS,IAAI,SAAS;AAC1C,YAAIA,QAAQ,CAAAA,QAAO,OAAO,EAAE;AAC5B,aAAK,aAAa,SAAS;AAAA,MAC7B;AACA;AAAA,IACF;AAEA,QAAI,CAAC,WAAW;AAEd;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,SAAS,IAAI,SAAS;AAC1C,QAAI,QAAQ;AACV,aAAO,OAAO,EAAE;AAAA,IAClB;AAAA,EACF;AAAA;AAAA,EAGA,WAAiB;AACf,eAAW,UAAU,KAAK,SAAS,OAAO,GAAG;AAC3C,aAAO,MAAM;AAAA,IACf;AACA,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA;AAAA,EAGA,iBAA2B;AACzB,WAAO,CAAC,GAAG,KAAK,SAAS,KAAK,CAAC;AAAA,EACjC;AAAA,EAEQ,YAAY,WAAyB;AAC3C,QAAI,KAAK,SAAS,IAAI,SAAS,EAAG;AAClC,QAAI;AACF,YAAM,SAAS,IAAI,YAAY;AAAA,QAC7B;AAAA,QACA,GAAI,KAAK,aAAa,SAAY,EAAE,SAAS,KAAK,SAAS,IAAI,CAAC;AAAA,QAChE,GAAI,KAAK,cAAc,SAAY,EAAE,UAAU,KAAK,UAAU,IAAI,CAAC;AAAA,MACrE,CAAC;AACD,WAAK,SAAS,IAAI,WAAW,MAAM;AAAA,IACrC,SAAS,KAAK;AAIZ,UAAI,CAAC,KAAK,oBAAoB,IAAI,SAAS,GAAG;AAC5C,aAAK,oBAAoB,IAAI,SAAS;AACtC,YAAI;AACF,kBAAQ,OAAO;AAAA,YACb,0DAA0D,SAAS,KACjE,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CACjD;AAAA;AAAA,UACF;AAAA,QACF,QAAQ;AAAA,QAAe;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aAAa,WAAyB;AAC5C,UAAM,SAAS,KAAK,SAAS,IAAI,SAAS;AAC1C,QAAI,QAAQ;AACV,aAAO,MAAM;AACb,WAAK,SAAS,OAAO,SAAS;AAAA,IAChC;AAAA,EACF;AACF;AAMA,SAAS,iBAAiB,IAA0C;AAClE,QAAM,UAAU,GAAG;AACnB,MAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,QAAM,IAAI;AACV,QAAM,YAAY,EAAE,WAAW,KAAK,EAAE,SAAS;AAC/C,MAAI,OAAO,cAAc,YAAY,UAAU,SAAS,GAAG;AACzD,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;ACjUA,SAAS,gBAAAC,qBAAoB;;;ACE7B,YAAY,SAAS;AACrB,YAAYC,SAAQ;AACpB,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AAEtB,OAAO,eAAe;AACtB,SAAS,eAAAC,oBAAmB;AA2D5B,IAAM,yBAAyB;AAC/B,IAAM,2BAA2B;AACjC,IAAM,gCAAgC;AACtC,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB;AAC3B,IAAM,iBAAiB;AAMhB,IAAM,mBAAN,MAAuB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,MAA+B;AACzC,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,IAAI,MAAM,2FAA2F;AAAA,IAC7G;AACA,SAAK,UAAU,KAAK,WAAgB,WAAQ,YAAQ,GAAG,UAAU;AACjE,SAAK,gBAAqB,WAAK,KAAK,SAAS,cAAc;AAC3D,SAAK,eAAe,KAAK,gBAAgB;AACzC,SAAK,iBAAiB,KAAK,kBAAkB;AAC7C,SAAK,sBAAsB,KAAK,uBAAuB;AACvD,SAAK,UAAU,KAAK,WAAW;AAC/B,SAAK,UAAU,OAAO,UAAU,eAAe,KAAK,MAAM,SAAS,IAC/D,iBAAiB,KAAK,OAAO,IAC7B,YAAY;AAOhB,UAAM,EAAE,MAAM,qBAAqB,MAAM,kBAAkB,IACzD,cAAc,KAAK,SAAS;AAC9B,SAAK,YAAY;AACjB,SAAK,YAAY,qBAAqB,KAAK,aAAa;AACxD,SAAK,cAAc,KAAK,gBAAgB,KAAK,cAAc,MAAM,QAAQ;AACzE,SAAK,YAAY,KAAK,aAAa;AAGnC,IAAG,cAAU,KAAK,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAuC;AACrC,UAAM,aAAoC,CAAC;AAC3C,QAAI,KAAK,SAAS;AAChB,iBAAW,KAAK;AAAA,QACd,MAAM;AAAA,QACN,UAAU,GAAG,KAAK,OAAO,IAAI,KAAK,OAAO;AAAA,QACzC,UAAU;AAAA;AAAA,MACZ,CAAC;AAAA,IACH;AACA,eAAW;AAAA,MACT;AAAA,QACE,MAAM;AAAA,QACN,UAAU,GAAG,KAAK,SAAS,IAAI,KAAK,SAAS;AAAA,QAC7C,UAAU;AAAA,MACZ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,YAA4D;AACzE,UAAM,UAAU,cAAc,KAAK,cAAc;AAGjD,UAAM,UAAyB,CAAC;AAChC,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,KAAK,qBAAqB;AACjE,YAAM,QAAQ,QAAQ,MAAM,GAAG,IAAI,KAAK,mBAAmB;AAC3D,YAAM,eAAe,MAAM,QAAQ;AAAA,QACjC,MAAM,IAAI,CAAC,cAAc,KAAK,eAAe,SAAS,CAAC;AAAA,MACzD;AACA,cAAQ,KAAK,GAAG,YAAY;AAAA,IAC9B;AAGA,YAAQ,KAAK,CAAC,GAAG,MAAM;AACrB,UAAI,EAAE,YAAY,EAAE,SAAS;AAC3B,eAAO,EAAE,UAAU,IAAI;AAAA,MACzB;AACA,UAAI,EAAE,iBAAiB,EAAE,cAAc;AACrC,eAAO,EAAE,eAAe,EAAE;AAAA,MAC5B;AACA,UAAI,EAAE,cAAc,EAAE,WAAW;AAC/B,eAAO,EAAE,YAAY,EAAE;AAAA,MACzB;AACA,aAAO,EAAE,UAAU,WAAW,EAAE,UAAU;AAAA,IAC5C,CAAC;AAED,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,SAAwB,MAAwF;AACzH,UAAM,YAAY,MAAM,gBAAgB,KAAK;AAC7C,UAAM,aAAa,MAAM,mBAAmB;AAE5C,eAAW,UAAU,SAAS;AAC5B,UAAI,OAAO,WACP,OAAO,aAAa,aACpB,OAAO,gBAAgB,YAAY;AACrC,eAAO;AAAA,UACL,MAAM,OAAO,UAAU;AAAA,UACvB,UAAU,OAAO,UAAU;AAAA,UAC3B,WAAW,OAAO;AAAA,UAClB,YAAY,OAAO;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,WAAsC;AACrD,QAAI;AACF,YAAM,UAAU,KAAK,gBAAgB;AACrC,MAAG,kBAAc,SAAS,KAAK,UAAU,WAAW,MAAM,CAAC,GAAG;AAAA,QAC5D,UAAU;AAAA,QACV,MAAM;AAAA,MACR,CAAC;AACD,MAAG,eAAW,SAAS,KAAK,aAAa;AAAA,IAC3C,SAAS,KAAK;AAEZ,cAAQ,MAAM,mDAAmD,GAAG;AAAA,IACtE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,gBAA4C;AAC1C,QAAI;AACF,UAAI,CAAI,eAAW,KAAK,aAAa,GAAG;AACtC,eAAO;AAAA,MACT;AAEA,YAAM,OAAU,iBAAa,KAAK,eAAe,OAAO;AACxD,YAAM,SAAS,KAAK,MAAM,IAAI;AAG9B,UAAI,CAAC,OAAO,QAAQ,CAAC,OAAO,YAAY,OAAO,OAAO,cAAc,UAAU;AAC5E,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAuB;AACrB,QAAI;AACF,MAAG,eAAW,KAAK,aAAa;AAAA,IAClC,QAAQ;AAAA,IAER;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eAAe,WAAsD;AACjF,QAAI;AACF,UAAI,UAAU,SAAS,OAAO;AAC5B,eAAO,MAAM,KAAK,SAAS,SAAS;AAAA,MACtC,WAAW,UAAU,SAAS,SAAS;AACrC,eAAO,MAAM,KAAK,WAAW,SAAS;AAAA,MACxC,WAAW,UAAU,SAAS,QAAQ;AACpC,eAAO,MAAM,KAAK,UAAU,SAAS;AAAA,MACvC,OAAO;AACL,cAAM,IAAI,MAAM,4BAA4B,UAAU,IAAI,EAAE;AAAA,MAC9D;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL;AAAA,QACA,WAAW,KAAK;AAAA,QAChB,UAAU;AAAA,QACV,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACtD,WAAW,KAAK,IAAI;AAAA,QACpB,cAAc;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,SAAS,WAAsD;AAC3E,UAAM,CAAC,MAAM,OAAO,IAAI,UAAU,SAAS,MAAM,GAAG;AACpD,UAAM,OAAO,SAAS,SAAS,EAAE;AAGjC,UAAM,YAAsB,CAAC;AAC7B,QAAI,eAAe;AAEnB,aAAS,IAAI,GAAG,IAAI,KAAK,WAAW,KAAK;AACvC,UAAI;AACF,cAAM,UAAU,MAAM,KAAK,QAAQ,MAAM,IAAI;AAC7C,kBAAU,KAAK,OAAO;AACtB;AAGA,YAAI,IAAI,KAAK,YAAY,GAAG;AAC1B,gBAAM,IAAI,QAAQ,CAAAC,aAAW,WAAWA,UAAS,EAAE,CAAC;AAAA,QACtD;AAAA,MACF,SAAS,KAAK;AAEZ,gBAAQ,KAAK,+BAA+B,IAAI,CAAC,IAAI,KAAK,SAAS,YAAY,GAAG;AAAA,MACpF;AAAA,IACF;AAEA,QAAI,UAAU,WAAW,GAAG;AAC1B,aAAO;AAAA,QACL;AAAA,QACA,WAAW,KAAK;AAAA,QAChB,UAAU;AAAA,QACV,SAAS;AAAA,QACT,OAAO;AAAA,QACP,WAAW,KAAK,IAAI;AAAA,QACpB,cAAc;AAAA,MAChB;AAAA,IACF;AAGA,UAAM,aAAa,UAAU,OAAO,CAAC,KAAK,QAAQ,MAAM,KAAK,CAAC,IAAI,UAAU;AAC5E,UAAM,aAAa,KAAK,IAAI,GAAG,SAAS;AACxC,UAAM,aAAa,KAAK,IAAI,GAAG,SAAS;AACxC,UAAM,SAAS,aAAa;AAC5B,UAAM,cAAe,KAAK,YAAY,gBAAgB,KAAK,YAAa;AAGxE,UAAM,eAAe,KAAK,sBAAsB;AAAA,MAC9C;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL;AAAA,MACA,WAAW;AAAA,MACX,UAAU;AAAA,MACV,SAAS;AAAA,MACT,WAAW,KAAK,IAAI;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,QAAQ,MAAc,MAA+B;AACjE,WAAO,IAAI,QAAQ,CAACA,UAAS,WAAW;AACtC,YAAM,YAAYD,aAAY,IAAI;AAClC,YAAM,SAAS,IAAQ,WAAO;AAC9B,UAAI,YAAY;AAEhB,aAAO,WAAW,KAAK,gBAAgB,MAAM;AAC3C,YAAI,CAAC,WAAW;AACd,iBAAO,QAAQ;AACf,iBAAO,IAAI,MAAM,oBAAoB,CAAC;AAAA,QACxC;AAAA,MACF,CAAC;AAED,aAAO,GAAG,WAAW,MAAM;AACzB,oBAAY;AACZ,cAAM,UAAUA,aAAY,IAAI,IAAI;AACpC,eAAO,QAAQ;AACf,QAAAC,SAAQ,OAAO;AAAA,MACjB,CAAC;AAED,aAAO,GAAG,SAAS,CAAC,QAAQ;AAC1B,eAAO,QAAQ;AACf,eAAO,GAAG;AAAA,MACZ,CAAC;AAED,aAAO,QAAQ,MAAM,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAAsB,SAInB;AACT,UAAM,EAAE,YAAY,QAAQ,WAAW,IAAI;AAI3C,UAAM,eAAe,KAAK,IAAI,GAAG,IAAK,aAAa,GAAI;AAGvD,UAAM,cAAc,KAAK,IAAI,GAAG,IAAK,SAAS,GAAI;AAGlD,UAAM,YAAY,KAAK,IAAI,GAAG,IAAK,aAAa,EAAG;AAGnD,UAAM,eAAgB,eAAe,MAAQ,cAAc,MAAQ,YAAY;AAE/E,WAAO,KAAK,MAAM,eAAe,GAAG;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,WAAW,WAAsD;AAC7E,UAAM,CAAC,MAAM,OAAO,IAAI,UAAU,SAAS,MAAM,GAAG;AACpD,UAAM,OAAO,SAAS,SAAS,EAAE;AAGjC,UAAM,YAAsB,CAAC;AAC7B,QAAI,eAAe;AAEnB,aAAS,IAAI,GAAG,IAAI,KAAK,WAAW,KAAK;AACvC,UAAI;AACF,cAAM,UAAU,MAAM,KAAK,OAAO,MAAM,IAAI;AAC5C,kBAAU,KAAK,OAAO;AACtB;AAGA,YAAI,IAAI,KAAK,YAAY,GAAG;AAC1B,gBAAM,IAAI,QAAQ,CAAAA,aAAW,WAAWA,UAAS,EAAE,CAAC;AAAA,QACtD;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,KAAK,iCAAiC,IAAI,CAAC,IAAI,KAAK,SAAS,YAAY,GAAG;AAAA,MACtF;AAAA,IACF;AAEA,QAAI,UAAU,WAAW,GAAG;AAC1B,aAAO;AAAA,QACL;AAAA,QACA,WAAW,KAAK;AAAA,QAChB,UAAU;AAAA,QACV,SAAS;AAAA,QACT,OAAO;AAAA,QACP,WAAW,KAAK,IAAI;AAAA,QACpB,cAAc;AAAA,MAChB;AAAA,IACF;AAGA,UAAM,aAAa,UAAU,OAAO,CAAC,KAAK,QAAQ,MAAM,KAAK,CAAC,IAAI,UAAU;AAC5E,UAAM,aAAa,KAAK,IAAI,GAAG,SAAS;AACxC,UAAM,aAAa,KAAK,IAAI,GAAG,SAAS;AACxC,UAAM,SAAS,aAAa;AAC5B,UAAM,cAAe,KAAK,YAAY,gBAAgB,KAAK,YAAa;AAGxE,UAAM,eAAe,KAAK,sBAAsB;AAAA,MAC9C;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL;AAAA,MACA,WAAW;AAAA,MACX,UAAU;AAAA,MACV,SAAS;AAAA,MACT,WAAW,KAAK,IAAI;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,OAAO,MAAc,MAA+B;AAChE,WAAO,IAAI,QAAQ,CAACA,UAAS,WAAW;AACtC,YAAM,YAAYD,aAAY,IAAI;AAIlC,YAAM,QAAQ,GAAG,KAAK,WAAW,MAAM,IAAI,IAAI,IAAI;AAEnD,YAAM,KAAK,IAAI,UAAU,OAAO;AAAA,QAC9B,kBAAkB,KAAK;AAAA,MACzB,CAAC;AAED,SAAG,GAAG,QAAQ,MAAM;AAClB,cAAM,UAAUA,aAAY,IAAI,IAAI;AACpC,WAAG,MAAM;AACT,QAAAC,SAAQ,OAAO;AAAA,MACjB,CAAC;AAED,SAAG,GAAG,SAAS,CAAC,QAAQ;AACtB,WAAG,MAAM;AACT,eAAO,GAAG;AAAA,MACZ,CAAC;AAGD,iBAAW,MAAM;AACf,YAAI,GAAG,eAAe,UAAU,YAAY;AAC1C,aAAG,MAAM;AACT,iBAAO,IAAI,MAAM,6BAA6B,CAAC;AAAA,QACjD;AAAA,MACF,GAAG,KAAK,cAAc;AAAA,IACxB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,UAAU,WAAsD;AAE5E,UAAM,YAAsB,CAAC;AAC7B,QAAI,eAAe;AAEnB,aAAS,IAAI,GAAG,IAAI,KAAK,WAAW,KAAK;AACvC,UAAI;AACF,cAAM,UAAU,MAAM,KAAK,SAAS,UAAU,QAAQ;AACtD,kBAAU,KAAK,OAAO;AACtB;AAGA,YAAI,IAAI,KAAK,YAAY,GAAG;AAC1B,gBAAM,IAAI,QAAQ,CAAAA,aAAW,WAAWA,UAAS,GAAG,CAAC;AAAA,QACvD;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,KAAK,gCAAgC,IAAI,CAAC,IAAI,KAAK,SAAS,YAAY,GAAG;AAAA,MACrF;AAAA,IACF;AAEA,QAAI,UAAU,WAAW,GAAG;AAC1B,aAAO;AAAA,QACL;AAAA,QACA,WAAW,KAAK;AAAA,QAChB,UAAU;AAAA,QACV,SAAS;AAAA,QACT,OAAO;AAAA,QACP,WAAW,KAAK,IAAI;AAAA,QACpB,cAAc;AAAA,MAChB;AAAA,IACF;AAGA,UAAM,aAAa,UAAU,OAAO,CAAC,KAAK,QAAQ,MAAM,KAAK,CAAC,IAAI,UAAU;AAC5E,UAAM,aAAa,KAAK,IAAI,GAAG,SAAS;AACxC,UAAM,aAAa,KAAK,IAAI,GAAG,SAAS;AACxC,UAAM,SAAS,aAAa;AAC5B,UAAM,cAAe,KAAK,YAAY,gBAAgB,KAAK,YAAa;AAGxE,UAAM,eAAe,KAAK,sBAAsB;AAAA,MAC9C;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL;AAAA,MACA,WAAW;AAAA,MACX,UAAU;AAAA,MACV,SAAS;AAAA,MACT,WAAW,KAAK,IAAI;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,SAAS,UAAmC;AACxD,UAAM,YAAYD,aAAY,IAAI;AAClC,UAAM,MAAM,WAAW,QAAQ;AAE/B,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ;AAAA,QACR,QAAQ,YAAY,QAAQ,KAAK,cAAc;AAAA,MACjD,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,EAAE;AAAA,MAC3C;AAEA,aAAOA,aAAY,IAAI,IAAI;AAAA,IAC7B,SAAS,KAAK;AACZ,YAAM,IAAI,MAAM,qBAAqB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,IACzF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,UAAkB,MAAqE;AAC1G,QAAI;AACF,YAAM,YAAiC,EAAE,MAAM,UAAU,UAAU,GAAG;AACtE,YAAM,SAAS,MAAM,KAAK,eAAe,SAAS;AAElD,aAAO;AAAA,QACL,SAAS,OAAO;AAAA,QAChB,SAAS,OAAO;AAAA,MAClB;AAAA,IACF,QAAQ;AACN,aAAO,EAAE,SAAS,UAAU,SAAS,EAAE;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAIH;AACD,UAAM,YAAY,KAAK,cAAc;AACrC,UAAM,YAAY,MAAM,KAAK,SAAS;AAEtC,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AACF;AAEA,SAAS,cAAkC;AACzC,QAAM,OAAU,sBAAkB;AAClC,aAAW,WAAW,OAAO,OAAO,IAAI,GAAG;AACzC,eAAW,SAAS,WAAW,CAAC,GAAG;AACjC,UAAI,MAAM,WAAW,UAAU,CAAC,MAAM,YAAY,iBAAiB,MAAM,OAAO,GAAG;AACjF,eAAO,MAAM;AAAA,MACf;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAcA,SAAS,cAAc,KAA8C;AAEnE,QAAM,cAAc,IAAI,MAAM,IAAI,KAAK,CAAC,GAAG;AAC3C,MAAI,eAAe,GAAG;AACpB,WAAO,EAAE,MAAM,IAAI;AAAA,EACrB;AACA,QAAM,MAAM,IAAI,YAAY,GAAG;AAC/B,QAAM,WAAW,IAAI,MAAM,GAAG,GAAG;AACjC,QAAM,WAAW,IAAI,MAAM,MAAM,CAAC;AAClC,MAAI,CAAC,YAAY,CAAC,UAAU;AAC1B,WAAO,EAAE,MAAM,IAAI;AAAA,EACrB;AACA,QAAM,OAAO,OAAO,QAAQ;AAC5B,MAAI,CAAC,OAAO,SAAS,IAAI,KAAK,CAAC,OAAO,UAAU,IAAI,KAAK,QAAQ,KAAK,OAAO,OAAO;AAClF,WAAO,EAAE,MAAM,IAAI;AAAA,EACrB;AACA,SAAO,EAAE,MAAM,UAAU,KAAK;AAChC;AAEA,SAAS,iBAAiB,MAA8C;AACtE,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,SAAS,eAAe,SAAS,aAAa,SAAS,QAAQ,SAAS,OAAO;AACjF,WAAO;AAAA,EACT;AACA,MAAI,KAAK,WAAW,MAAM,KAAK,KAAK,WAAW,UAAU,GAAG;AAC1D,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;ACtqBA,OAAOE,gBAAe;AACtB,SAAS,oBAAoB;;;ACJ7B,OAAO,cAAc;AACrB,YAAYC,SAAQ;AACpB,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AA4CtB,IAAM,cAAc;AACpB,IAAM,uBAAuB;AAEtB,IAAM,eAAN,MAAmB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAqB;AAAA,EACrB,eAAuB;AAAA,EAE/B,YAAY,MAA2B;AACrC,SAAK,YAAY,KAAK;AACtB,SAAK,cAAc,KAAK,eAAe;AACvC,SAAK,YAAY,KAAK,aAAa;AACnC,SAAK,cAAc,KAAK,eAAe;AACvC,SAAK,SAAS,KAAK;AAEnB,UAAM,UAAU,KAAK,WAAgB,WAAQ,YAAQ,GAAG,YAAY,UAAU,KAAK,SAAS;AAC5F,IAAG,cAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAEzC,UAAM,SAAc,WAAK,SAAS,WAAW;AAC7C,SAAK,KAAK,IAAI,SAAS,MAAM;AAC7B,SAAK,GAAG,OAAO,oBAAoB;AACnC,SAAK,WAAW;AAEhB,UAAM,MAAM,KAAK,GAAG,QAAQ,oDAAoD,EAAE,IAAI;AAGtF,SAAK,aAAa,KAAK,OAAO;AAAA,EAChC;AAAA,EAEQ,aAAmB;AACzB,SAAK,GAAG;AAAA,MACN;AAAA,IAyBF;AAAA,EACF;AAAA,EAEA,WAAW,QAAgB,MAAc,SAAyB;AAChE,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,SAAS,KAAK,GACjB,QAAQ,6EAA6E,EACrF,IAAI,QAAQ,MAAM,SAAS,GAAG;AACjC,SAAK,aAAa,OAAO,OAAO,eAAe;AAC/C,SAAK,mBAAmB;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,iBAAiB,SAAiB,QAAQ,KAAsB;AAC9D,WAAO,KAAK,GACT,QAAQ,mGAAmG,EAC3G,IAAI,SAAS,KAAK;AAAA,EACvB;AAAA,EAEA,gBAAwB;AACtB,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,qBAA2B;AACjC,UAAM,QAAS,KAAK,GAAG,QAAQ,oCAAoC,EAAE,IAAI,EAAoB;AAC7F,QAAI,QAAQ,KAAK,aAAa;AAC5B,YAAM,SAAS,QAAQ,KAAK;AAC5B,WAAK,GACF,QAAQ,uFAAuF,EAC/F,IAAI,MAAM;AAAA,IACf;AAAA,EACF;AAAA,EAEA,MAAM,KAAa,OAAuB;AACxC,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,SAAS,KAAK,GACjB,QAAQ,0EAA0E,EAClF,IAAI,KAAK,OAAO,GAAG;AACtB,SAAK,iBAAiB;AACtB,WAAO,OAAO,OAAO,eAAe;AAAA,EACtC;AAAA,EAEA,MAAM,QAAQ,KAAoB;AAChC,WAAO,KAAK,GACT,QAAQ,gFAAgF,EACxF,IAAI,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,UAAwB;AAC1B,SAAK,GAAG,QAAQ,iCAAiC,EAAE,IAAI,QAAQ;AAAA,EACjE;AAAA,EAEA,aAAa,UAA+D;AAC1E,UAAM,MAAM,KAAK,GACd,QAAQ,2EAA2E,EACnF,IAAI,QAAQ;AACf,QAAI,CAAC,IAAK,QAAO,EAAE,UAAU,GAAG,cAAc,MAAM;AACpD,QAAI,IAAI,YAAY,KAAK,aAAa;AACpC,WAAK,iBAAiB,QAAQ;AAC9B,aAAO,EAAE,UAAU,IAAI,UAAU,cAAc,KAAK;AAAA,IACtD;AACA,WAAO,EAAE,UAAU,IAAI,UAAU,cAAc,MAAM;AAAA,EACvD;AAAA,EAEQ,iBAAiB,UAAwB;AAC/C,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,OAAO,KAAK,GAAG,YAAY,MAAM;AACrC,YAAM,MAAM,KAAK,GACd,QAAQ,qEAAqE,EAC7E,IAAI,QAAQ;AACf,UAAI,CAAC,IAAK;AACV,WAAK,GACF;AAAA,QACC;AAAA,MACF,EACC,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,OAAO,IAAI,WAAW,KAAK,IAAI,QAAQ;AACnE,WAAK,GAAG,QAAQ,iCAAiC,EAAE,IAAI,QAAQ;AAAA,IACjE,CAAC;AACD,SAAK;AAAA,EACP;AAAA,EAEA,qBAA6B;AAC3B,WAAQ,KAAK,GAAG,QAAQ,8CAA8C,EAAE,IAAI,EAAoB;AAAA,EAClG;AAAA,EAEA,qBAAqB,QAAQ,KAAK,eAAe,OAAiD;AAChG,UAAM,OAAO,eACT,8DACA;AACJ,WAAO,KAAK,GACT,QAAQ,UAAU,IAAI,kDAAkD,EACxE,IAAI,KAAK;AAAA,EACd;AAAA,EAEA,eAAuB;AACrB,WAAQ,KAAK,GAAG,QAAQ,kCAAkC,EAAE,IAAI,EAAoB;AAAA,EACtF;AAAA,EAEA,kBAA0B;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,mBAAyB;AAC/B,UAAM,QAAQ,KAAK,aAAa;AAChC,QAAI,QAAQ,KAAK,WAAW;AAC1B,YAAM,SAAS,QAAQ,KAAK;AAC5B,YAAM,WAAW,KAAK,GACnB,QAAQ,8DAA8D,EACtE,IAAI,MAAM;AACb,WAAK,GACF,QAAQ,gFAAgF,EACxF,IAAI,MAAM;AACb,WAAK,gBAAgB,SAAS;AAC9B,UAAI,KAAK,UAAU,SAAS,SAAS,GAAG;AACtC,aAAK,OAAO,QAAQ;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,SAAK,GAAG,MAAM;AAAA,EAChB;AACF;AAGO,SAAS,eAAe,QAAgB,MAAc,SAAyB;AACpF,QAAM,MAAM,OAAO,MAAM,IAAI,QAAQ,MAAM;AAC3C,MAAI,CAAC,IAAI;AACT,MAAI,CAAC,IAAI;AACT,UAAQ,KAAK,KAAK,CAAC;AACnB,SAAO;AACT;;;ADvOO,IAAM,SAAS;AAAA,EACpB,cAAc;AAAA,EACd,cAAc;AAAA,EACd,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,kBAAkB;AAAA;AAAA,EAClB,gBAAgB;AAAA;AAClB;AAEA,IAAM,2BAAgD,oBAAI,IAAI;AAAA,EAC5D,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT,CAAC;AA8CD,IAAM,gCAAgC;AACtC,IAAM,6BAA6B;AACnC,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;AAMtB,IAAM,cAAN,cAA0B,aAAa;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAA8B;AAAA,EAC9B,SAA2B;AAAA,EAE3B;AAAA,EACA;AAAA,EACA;AAAA,EAEA,QAAoB;AAAA,IAC1B,WAAW;AAAA,IACX,SAAS;AAAA,IACT,mBAAmB;AAAA,EACrB;AAAA,EAEQ,iBAAiB;AAAA,EACjB;AAAA,EAER,YAAY,MAA0B;AACpC,UAAM;AAEN,SAAK,SAAS,KAAK;AACnB,SAAK,WAAW,KAAK;AACrB,SAAK,SAAS,KAAK;AACnB,QAAI,CAAC,KAAK,UAAU;AAClB,YAAM,IAAI,MAAM,mFAAmF;AAAA,IACrG;AACA,SAAK,WAAW,KAAK;AACrB,SAAK,sBAAsB,KAAK,uBAAuB;AACvD,SAAK,mBAAmB,KAAK,oBAAoB;AACjD,SAAK,sBAAsB,KAAK,uBAAuB;AACvD,SAAK,gBAAgB,KAAK,iBAAiB;AAG3C,QAAI,KAAK,WAAW;AAClB,WAAK,SAAS,IAAI,aAAa;AAAA,QAC7B,WAAW,KAAK;AAAA,QAChB,SAAS,KAAK;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAyB;AAC7B,QAAI,KAAK,gBAAgB;AACvB,YAAM,IAAI,MAAM,yCAAyC;AAAA,IAC3D;AAEA,QAAI,KAAK,WAAW,eAAe,GAAG;AACpC,cAAQ,KAAK,oDAAoD;AACjE;AAAA,IACF;AAEA,YAAQ,IAAI,sCAAsC,KAAK,QAAQ;AAE/D,QAAI;AAEF,YAAM,KAAK,sBAAsB;AAGjC,YAAM,KAAK,mBAAmB;AAG9B,WAAK,eAAe;AAEpB,WAAK,MAAM,YAAY;AACvB,WAAK,MAAM,oBAAoB;AAC/B,WAAK,KAAK,WAAW;AAGrB,WAAK,aAAa;AAAA,IACpB,SAAS,KAAK;AACZ,cAAQ,MAAM,oCAAoC,GAAG;AACrD,WAAK,MAAM,YAAY,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAEtE,UAAI,KAAK,iBAAiB,CAAC,KAAK,gBAAgB;AAC9C,aAAK,kBAAkB;AAAA,MACzB;AAEA,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA4B;AAChC,YAAQ,IAAI,wCAAwC;AACpD,SAAK,iBAAiB;AACtB,SAAK,gBAAgB;AAGrB,SAAK,eAAe;AACpB,SAAK,oBAAoB;AAGzB,UAAM,KAAK,oBAAoB;AAC/B,UAAM,KAAK,iBAAiB;AAE5B,SAAK,MAAM,YAAY;AACvB,SAAK,MAAM,UAAU;AAGrB,SAAK,QAAQ,MAAM;AACnB,SAAK,SAAS;AAEd,SAAK,KAAK,cAAc;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,YAAY,SAA2B;AACrC,QAAI,CAAC,KAAK,aAAa,KAAK,UAAU,eAAe,GAAG;AACtD,aAAO;AAAA,IACT;AACA,QAAI;AACF,WAAK,UAAU,KAAK,KAAK,UAAU,OAAO,CAAC;AAC3C,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,cAAQ,MAAM,iDAAiD,GAAG;AAClE,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,YAAY,MAAgC;AAC1C,UAAM,QAAQ,OAAO,SAAS,WAAW,OAAO,KAAK,MAAM,OAAO,IAAI;AAGtE,QAAI;AACJ,QAAI,KAAK,UAAU,OAAO,SAAS,KAAK,KAAK,MAAM,UAAU,GAAG;AAC9D,YAAM,SAAS,MAAM,CAAC;AACtB,UAAI,yBAAyB,IAAI,MAAM,GAAG;AACxC,YAAI;AACF,gBAAM,KAAK,OAAO,WAAW,QAAQ,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC;AAAA,QAC/D,SAAS,KAAK;AACZ,kBAAQ,KAAK,qDAAqD,GAAG;AAAA,QACvE;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,UAAU,KAAK,OAAO,eAAe,GAAG;AAChD,UAAI,KAAK,UAAU,QAAQ,QAAW;AACpC,aAAK,OAAO,MAAM,KAAK,KAAe;AACtC,gBAAQ,IAAI,8DAAyD,GAAG,YAAY;AAAA,MACtF,OAAO;AACL,gBAAQ,KAAK,+DAA+D;AAAA,MAC9E;AACA,aAAO;AAAA,IACT;AAEA,QAAI;AACF,WAAK,OAAO,KAAK,IAAI;AACrB,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,cAAQ,MAAM,yCAAyC,GAAG;AAC1D,UAAI,KAAK,UAAU,QAAQ,QAAW;AACpC,aAAK,OAAO,MAAM,KAAK,KAAe;AAAA,MACxC;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAAuB;AACrB,WAAO,EAAE,GAAG,KAAK,MAAM;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,YAKE;AACA,WAAO;AAAA,MACL,kBAAkB,KAAK,WAAW,eAAe;AAAA,MACjD,eAAe,KAAK,QAAQ,eAAe;AAAA,MAC3C,eAAe,KAAK,MAAM;AAAA,MAC1B,mBAAmB,KAAK,MAAM;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,wBAAuC;AACnD,WAAO,IAAI,QAAQ,CAACC,UAAS,WAAW;AACtC,YAAM,MAAM,KAAK,cAAc,oBAAoB;AACnD,YAAM,KAAK,IAAIC,WAAU,KAAK;AAAA,QAC5B,SAAS;AAAA,UACP,iBAAiB,UAAU,KAAK,MAAM;AAAA,UACtC,eAAe,KAAK;AAAA,UACpB,aAAa,KAAK;AAAA,QACpB;AAAA,MACF,CAAC;AAED,SAAG,GAAG,QAAQ,MAAM;AAClB,gBAAQ,IAAI,yCAAyC;AACrD,aAAK,YAAY;AACjB,aAAK,MAAM,UAAU;AAGrB,aAAK,eAAe;AAEpB,QAAAD,SAAQ;AAAA,MACV,CAAC;AAED,SAAG,GAAG,WAAW,CAAC,SAAiB;AACjC,aAAK,qBAAqB,IAAI;AAAA,MAChC,CAAC;AAED,SAAG,GAAG,SAAS,CAAC,QAAe;AAC7B,gBAAQ,MAAM,wCAAwC,GAAG;AACzD,eAAO,GAAG;AAAA,MACZ,CAAC;AAED,SAAG,GAAG,SAAS,CAAC,MAAc,WAAmB;AAC/C,gBAAQ,IAAI,yCAAyC,MAAM,MAAM;AACjE,aAAK,YAAY;AAEjB,YAAI,KAAK,MAAM,YAAY,WAAW;AACpC,eAAK,MAAM,UAAU;AAAA,QACvB;AAEA,aAAK,iBAAiB,SAAS;AAE/B,YAAI,KAAK,iBAAiB,CAAC,KAAK,gBAAgB;AAC9C,eAAK,kBAAkB;AAAA,QACzB;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,qBAAoC;AAChD,WAAO,IAAI,QAAQ,CAACA,UAAS,WAAW;AACtC,YAAM,MAAM,KAAK,cAAc,iBAAiB;AAChD,YAAM,KAAK,IAAIC,WAAU,KAAK;AAAA,QAC5B,SAAS;AAAA,UACP,iBAAiB,UAAU,KAAK,MAAM;AAAA,UACtC,eAAe,KAAK;AAAA,UACpB,aAAa,KAAK;AAAA,QACpB;AAAA,MACF,CAAC;AAED,SAAG,GAAG,QAAQ,MAAM;AAClB,gBAAQ,IAAI,sCAAsC;AAClD,aAAK,SAAS;AACd,QAAAD,SAAQ;AAAA,MACV,CAAC;AAED,SAAG,GAAG,WAAW,CAAC,SAAiB;AACjC,aAAK,kBAAkB,IAAI;AAAA,MAC7B,CAAC;AAED,SAAG,GAAG,SAAS,CAAC,QAAe;AAC7B,gBAAQ,MAAM,qCAAqC,GAAG;AACtD,eAAO,GAAG;AAAA,MACZ,CAAC;AAED,SAAG,GAAG,SAAS,CAAC,MAAc,WAAmB;AAC/C,gBAAQ,IAAI,sCAAsC,MAAM,MAAM;AAC9D,aAAK,SAAS;AACd,aAAK,iBAAiB,MAAM;AAE5B,YAAI,KAAK,iBAAiB,CAAC,KAAK,gBAAgB;AAC9C,eAAK,kBAAkB;AAAA,QACzB;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEQ,cAAcE,QAAsB;AAC1C,UAAM,MAAM,IAAI,IAAIA,QAAM,KAAK,SAAS,SAAS,GAAG,IAAI,KAAK,WAAW,GAAG,KAAK,QAAQ,GAAG;AAC3F,QAAI,aAAa,IAAI,SAAS,KAAK,MAAM;AACzC,QAAI,aAAa,IAAI,YAAY,KAAK,QAAQ;AAC9C,WAAO,IAAI,SAAS;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAuB;AAC7B,QAAI,CAAC,KAAK,aAAa,KAAK,UAAU,eAAe,GAAG;AACtD;AAAA,IACF;AAEA,UAAM,kBAAkB;AAAA,MACtB,MAAM;AAAA,MACN,UAAU,KAAK;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,SAAK,UAAU,KAAK,KAAK,UAAU,eAAe,CAAC;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,MAAoB;AAC/C,QAAI;AACF,YAAM,UAAU,KAAK,MAAM,KAAK,SAAS,OAAO,CAAC;AAEjD,cAAQ,QAAQ,MAAM;AAAA,QACpB,KAAK;AAEH,eAAK,iBAAiB;AACtB;AAAA,QAEF,KAAK;AAEH,eAAK,oBAAoB,OAAO;AAChC;AAAA,QAEF,KAAK,eAAe;AAGlB,gBAAM,IAAK,QAAgB,QAAQ,CAAC;AACpC,gBAAM,UAAyB;AAAA,YAC7B,IAAI,EAAE;AAAA,YACN,MAAM,EAAE;AAAA,YACR,SAAS,EAAE,YAAY,CAAC;AAAA,YACxB,WAAW,KAAK,IAAI;AAAA,UACtB;AACA,eAAK,KAAK,WAAW,OAAO;AAC5B;AAAA,QACF;AAAA,QAEA,KAAK,oBAAoB;AAGvB,gBAAM,UAAY,QAAgB,QAAQ,CAAC;AAC3C,qBAAW,KAAK,SAAS;AACvB,kBAAM,UAAyB;AAAA,cAC7B,IAAI,EAAE;AAAA,cACN,MAAM,EAAE;AAAA,cACR,SAAU,EAAE,YAAwC,CAAC;AAAA,cACrD,WAAW,KAAK,IAAI;AAAA,YACtB;AACA,iBAAK,KAAK,WAAW,OAAO;AAAA,UAC9B;AACA;AAAA,QACF;AAAA,QAEA,KAAK;AAMH,eAAK,KAAK,iBAAiB,OAAO;AAClC;AAAA,QAEF,KAAK;AACH,kBAAQ,MAAM,8BAA8B,QAAQ,KAAK;AACzD,eAAK,KAAK,cAAc,QAAQ,KAAK;AACrC;AAAA,QAEF;AACE,kBAAQ,KAAK,+CAA+C,QAAQ,IAAI;AAAA,MAC5E;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,kDAAkD,GAAG;AAAA,IACrE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,oBAAI,IAAmD;AAAA;AAAA;AAAA,EAI7E,mBAAmB,QAAgB,SAAsD;AACvF,SAAK,YAAY,IAAI,QAAQ,OAAO;AAAA,EACtC;AAAA,EAEA,MAAc,iBAAiB,SAIb;AAChB,UAAM,QAAQ,QAAQ;AACtB,UAAM,SAAS,QAAQ;AACvB,QAAI,CAAC,SAAS,CAAC,OAAQ;AAEvB,UAAM,UAAU,KAAK,YAAY,IAAI,MAAM;AAC3C,QAAI,CAAC,SAAS;AACZ,WAAK,gBAAgB,OAAO,QAAW,uBAAuB,MAAM,EAAE;AACtE;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,QAAQ,QAAQ,MAAM;AAC3C,WAAK,gBAAgB,OAAO,MAAM;AAAA,IACpC,SAAS,KAAU;AACjB,WAAK,gBAAgB,OAAO,QAAW,KAAK,WAAW,OAAO,GAAG,CAAC;AAAA,IACpE;AAAA,EACF;AAAA,EAEQ,gBAAgB,OAAe,QAAiB,OAAsB;AAC5E,QAAI,CAAC,KAAK,aAAa,KAAK,UAAU,eAAe,EAAG;AACxD,SAAK,UAAU,KAAK,KAAK,UAAU;AAAA,MACjC,MAAM;AAAA,MACN;AAAA,MACA,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,EAAE,OAAO;AAAA,IACjD,CAAC,CAAC;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,kBAAkB,MAAoB;AAC5C,QAAI,KAAK,UAAU,KAAK,UAAU,KAAK,KAAK,CAAC,MAAM,OAAO,kBAAkB;AAC1E,UAAI;AACF,cAAM,UAAU,KAAK,MAAM,KAAK,MAAM,CAAC,EAAE,SAAS,OAAO,CAAC;AAC1D,cAAM,UAAU,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU;AACxE,cAAM,UAAU,KAAK,OAAO,iBAAiB,OAAO;AACpD,iBAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,gBAAM,QAAQ,QAAQ,CAAC;AACvB,gBAAM,YAAY,OAAO;AAAA,YACvB,KAAK,UAAU;AAAA,cACb,KAAK,MAAM;AAAA,cACX,QAAQ,MAAM;AAAA,cACd,MAAM,MAAM;AAAA,cACZ,SAAS,MAAM,QAAQ,SAAS,QAAQ;AAAA,cACxC,MAAM,IAAI,QAAQ,SAAS;AAAA,YAC7B,CAAC;AAAA,YACD;AAAA,UACF;AACA,gBAAM,QAAQ,eAAe,OAAO,gBAAgB,GAAG,SAAS;AAChE,cAAI,KAAK,UAAU,KAAK,OAAO,eAAe,GAAG;AAC/C,iBAAK,OAAO,KAAK,KAAK;AAAA,UACxB;AAAA,QACF;AACA,gBAAQ,IAAI,wBAAwB,QAAQ,MAAM,+BAA+B,OAAO,EAAE;AAAA,MAC5F,SAAS,KAAK;AACZ,gBAAQ,MAAM,2CAA2C,GAAG;AAAA,MAC9D;AACA;AAAA,IACF;AACA,SAAK,KAAK,QAAQ,IAAI;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,eAAqB;AAC3B,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,UAAU,KAAK,OAAO,eAAe,EAAG;AAClE,UAAM,UAAU,KAAK,OAAO,MAAM;AAClC,QAAI,QAAQ,WAAW,EAAG;AAC1B,YAAQ,IAAI,2BAA2B,QAAQ,MAAM,4BAA4B;AACjF,eAAW,SAAS,SAAS;AAC3B,UAAI;AACF,aAAK,OAAO,KAAK,MAAM,KAAK;AAC5B,aAAK,OAAO,IAAI,MAAM,EAAE;AAAA,MAC1B,SAAS,KAAK;AACZ,gBAAQ,MAAM,kEAA6D,GAAG;AAC9E,aAAK,OAAO,aAAa,MAAM,EAAE;AACjC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,mBAA2B;AACzB,WAAO,KAAK,QAAQ,aAAa,KAAK;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAoB,SAAoB;AAC9C,UAAM,UAAyB;AAAA,MAC7B,IAAI,QAAQ;AAAA,MACZ,MAAM,QAAQ;AAAA,MACd,SAAS,QAAQ,WAAW,CAAC;AAAA,MAC7B,WAAW,QAAQ,aAAa,KAAK,IAAI;AAAA,IAC3C;AAEA,SAAK,KAAK,WAAW,OAAO;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAuB;AAC7B,SAAK,eAAe;AAEpB,SAAK,oBAAoB,YAAY,MAAM;AACzC,WAAK,cAAc;AAAA,IACrB,GAAG,KAAK,mBAAmB;AAG3B,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAuB;AAC7B,QAAI,KAAK,mBAAmB;AAC1B,oBAAc,KAAK,iBAAiB;AACpC,WAAK,oBAAoB;AAAA,IAC3B;AAEA,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAsB;AAC5B,QAAI,CAAC,KAAK,aAAa,KAAK,UAAU,eAAe,GAAG;AACtD;AAAA,IACF;AAEA,UAAM,mBAAmB;AAAA,MACvB,MAAM;AAAA,MACN,UAAU,KAAK;AAAA,MACf,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,QAAI;AACF,WAAK,UAAU,KAAK,KAAK,UAAU,gBAAgB,CAAC;AAGpD,WAAK,iBAAiB,WAAW,MAAM;AACrC,gBAAQ,KAAK,wDAAwD;AACrE,aAAK,iBAAiB,mBAAmB;AAAA,MAC3C,GAAG,oBAAoB;AAAA,IACzB,SAAS,KAAK;AACZ,cAAQ,MAAM,2CAA2C,GAAG;AAAA,IAC9D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAyB;AAE/B,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AAEA,SAAK,MAAM,gBAAgB,KAAK,IAAI;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,SAAyD;AAChF,UAAM,eAAe,KAAK,MAAM;AAEhC,QAAI,YAAY,aAAa,YAAY,qBAAqB;AAC5D,WAAK,YAAY;AAAA,IACnB;AACA,QAAI,YAAY,QAAQ;AACtB,WAAK,SAAS;AAAA,IAChB;AAEA,UAAM,sBAAsB,CAAC,KAAK,aAAa,CAAC,KAAK;AAErD,QAAI,uBAAuB,cAAc;AACvC,WAAK,MAAM,YAAY;AACvB,WAAK,MAAM,UAAU;AAErB,cAAQ,IAAI,kCAAkC;AAC9C,WAAK,KAAK,cAAc;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAA0B;AAChC,SAAK,oBAAoB;AAEzB,UAAM,QAAQ,KAAK;AAAA,MACjB,KAAK,mBAAmB,KAAK,IAAI,GAAG,KAAK,MAAM,iBAAiB;AAAA,MAChE,KAAK;AAAA,IACP;AAEA,YAAQ;AAAA,MACN,yCAAyC,KAAK,eAAe,KAAK,MAAM,oBAAoB,CAAC;AAAA,IAC/F;AAEA,SAAK,iBAAiB,WAAW,YAAY;AAC3C,WAAK,MAAM;AAEX,UAAI;AACF,cAAM,KAAK,QAAQ;AAAA,MACrB,SAAS,KAAK;AACZ,gBAAQ,MAAM,mCAAmC,GAAG;AAAA,MAEtD;AAAA,IACF,GAAG,KAAK;AAAA,EACV;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAA4B;AAClC,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,sBAAqC;AACjD,WAAO,IAAI,QAAQ,CAACF,aAAY;AAC9B,UAAI,CAAC,KAAK,WAAW;AACnB,QAAAA,SAAQ;AACR;AAAA,MACF;AAEA,WAAK,UAAU,KAAK,SAAS,MAAMA,SAAQ,CAAC;AAC5C,WAAK,UAAU,MAAM;AAAA,IACvB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,mBAAkC;AAC9C,WAAO,IAAI,QAAQ,CAACA,aAAY;AAC9B,UAAI,CAAC,KAAK,QAAQ;AAChB,QAAAA,SAAQ;AACR;AAAA,MACF;AAEA,WAAK,OAAO,KAAK,SAAS,MAAMA,SAAQ,CAAC;AACzC,WAAK,OAAO,MAAM;AAAA,IACpB,CAAC;AAAA,EACH;AACF;;;AElvBA,YAAYG,aAAY;AAgCxB,IAAM,WAAW;AACjB,IAAM,aAAa;AACnB,IAAM,gBAAgB;AAKtB,IAAM,mBAAmB,OAAO,KAAK,iBAAiB;AACtD,IAAM,mBAAmB,OAAO,KAAK,iBAAiB;AACtD,IAAM,mBAAmB;AACzB,IAAM,qBAAqB,OAAO,KAAK,4BAA4B,KAAK;AACxE,IAAM,sBAAsB,OAAO,KAAK,oCAAoC,KAAK;AAS1E,SAAS,kBAA2B;AACzC,QAAM,EAAE,WAAW,WAAW,IAAW,4BAAoB,QAAQ;AACrE,QAAM,eAAe,UAAU,OAAO,EAAE,MAAM,QAAQ,QAAQ,MAAM,CAAC;AACrE,QAAM,gBAAgB,WAAW,OAAO,EAAE,MAAM,SAAS,QAAQ,MAAM,CAAC;AAExE,QAAM,YAAY,4BAA4B,YAAY;AAC1D,QAAM,aAAa,8BAA8B,aAAa;AAE9D,SAAO;AAAA,IACL,WAAW;AAAA,IACX,YAAY;AAAA,EACd;AACF;AAKA,SAAS,4BAA4B,MAAsB;AACzD,MACE,KAAK,WAAW,mBAAmB,SAAS,YAC5C,CAAC,KAAK,SAAS,GAAG,mBAAmB,MAAM,EAAE,OAAO,kBAAkB,GACtE;AACA,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AAEA,QAAM,MAAM,KAAK,SAAS,mBAAmB,MAAM;AAEnD,MAAI,IAAI,WAAW,UAAU;AAC3B,UAAM,IAAI,MAAM,mCAAmC,IAAI,MAAM,EAAE;AAAA,EACjE;AAEA,SAAO;AACT;AAKA,SAAS,8BAA8B,OAAuB;AAC5D,MACE,MAAM,WAAW,oBAAoB,SAAS,YAC9C,CAAC,MAAM,SAAS,GAAG,oBAAoB,MAAM,EAAE,OAAO,mBAAmB,GACzE;AACA,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AAEA,QAAM,MAAM,MAAM,SAAS,oBAAoB,MAAM;AAErD,MAAI,IAAI,WAAW,UAAU;AAC3B,UAAM,IAAI,MAAM,oCAAoC,IAAI,MAAM,EAAE;AAAA,EAClE;AAEA,SAAO;AACT;AAKO,SAAS,mBACd,iBACA,iBACQ;AACR,MAAI,gBAAgB,WAAW,UAAU;AACvC,UAAM,IAAI,MAAM,mCAAmC,gBAAgB,MAAM,EAAE;AAAA,EAC7E;AACA,MAAI,gBAAgB,WAAW,UAAU;AACvC,UAAM,IAAI,MAAM,mCAAmC,gBAAgB,MAAM,EAAE;AAAA,EAC7E;AAEA,QAAM,aAAoB,yBAAiB;AAAA,IACzC,KAAK,OAAO,OAAO,CAAC,qBAAqB,eAAe,CAAC;AAAA,IACzD,QAAQ;AAAA,IACR,MAAM;AAAA,EACR,CAAC;AACD,QAAM,YAAmB,wBAAgB;AAAA,IACvC,KAAK,OAAO,OAAO,CAAC,oBAAoB,eAAe,CAAC;AAAA,IACxD,QAAQ;AAAA,IACR,MAAM;AAAA,EACR,CAAC;AACD,QAAM,eAAsB,sBAAc,EAAE,YAAY,UAAU,CAAC;AAEnE,MAAI,aAAa,WAAW,UAAU;AACpC,UAAM,IAAI,MAAM,+BAA+B,aAAa,MAAM,EAAE;AAAA,EACtE;AAEA,SAAO;AACT;AAaO,SAAS,kBACd,cACA,gBACA,iBAIA;AACA,QAAM,MACJ,mBAAmB,UACnB,oBAAoB,UACpB,OAAO,QAAQ,gBAAgB,eAAe,IAAI;AAEpD,QAAM,WAAW,MAAM,mBAAmB;AAC1C,QAAM,WAAW,MAAM,mBAAmB;AAE1C,QAAM,UAAU,WAAW,cAAc,OAAO,MAAM,CAAC,GAAG,UAAU,QAAQ;AAC5E,QAAM,UAAU,WAAW,cAAc,OAAO,MAAM,CAAC,GAAG,UAAU,QAAQ;AAE5E,SAAO,EAAE,SAAS,QAAQ;AAC5B;AAKA,SAAS,WACP,KACA,MACA,MACA,QACQ;AAER,QAAM,MACH,mBAAW,UAAU,IAAI,EACzB,OAAO,GAAG,EACV,OAAO;AAGV,QAAM,IAAc,CAAC;AACrB,MAAI,eAAe;AACnB,MAAI,IAAI;AAER,SAAO,eAAe,QAAQ;AAC5B,UAAM,OAAc,mBAAW,UAAU,GAAG;AAE5C,QAAI,EAAE,SAAS,GAAG;AAChB,WAAK,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAAA,IAC7B;AAEA,SAAK,OAAO,IAAI;AAChB,SAAK,OAAO,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;AAC5B,UAAM,MAAM,KAAK,OAAO;AAExB,MAAE,KAAK,GAAG;AACV,oBAAgB,IAAI;AACpB;AAAA,EACF;AAEA,SAAO,OAAO,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM;AACzC;AAUO,SAAS,QACd,KACA,WACA,OACmB;AACnB,MAAI,IAAI,WAAW,UAAU;AAC3B,UAAM,IAAI,MAAM,qBAAqB,IAAI,MAAM,EAAE;AAAA,EACnD;AAGA,QAAM,KAAK,SAAgB,oBAAY,UAAU;AAIjD,QAAM,cAAc,GAAG,MAAM,GAAG,EAAE;AAElC,QAAM,SAAgB,uBAAe,qBAAqB,KAAK,WAAW;AAE1E,QAAM,aAAa,OAAO,OAAO;AAAA,IAC/B,OAAO,OAAO,SAAS;AAAA,IACvB,OAAO,MAAM;AAAA,EACf,CAAC;AAED,QAAM,UAAU,OAAO,WAAW;AAElC,SAAO;AAAA,IACL,SAAS;AAAA,IACT,OAAO;AAAA,IACP;AAAA,IACA;AAAA,EACF;AACF;AAKO,SAAS,QACd,KACA,UACQ;AACR,MAAI,IAAI,WAAW,UAAU;AAC3B,UAAM,IAAI,MAAM,qBAAqB,GAAG,EAAE;AAAA,EAC5C;AACA,MAAI,SAAS,MAAM,WAAW,YAAY;AACxC,UAAM,IAAI,MAAM,uBAAuB,SAAS,MAAM,MAAM,EAAE;AAAA,EAChE;AACA,MAAI,SAAS,QAAQ,WAAW,eAAe;AAC7C,UAAM,IAAI,MAAM,0BAA0B,SAAS,OAAO,EAAE;AAAA,EAC9D;AAGA,QAAM,cAAc,SAAS,MAAM,MAAM,GAAG,EAAE;AAE9C,QAAM,WAAkB,yBAAiB,qBAAqB,KAAK,WAAW;AAC9E,WAAS,WAAW,SAAS,OAAO;AAEpC,MAAI;AACF,UAAM,YAAY,OAAO,OAAO;AAAA,MAC9B,SAAS,OAAO,SAAS,UAAU;AAAA,MACnC,SAAS,MAAM;AAAA,IACjB,CAAC;AACD,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,UAAM,IAAI,MAAM,sBAAuB,IAAc,OAAO,EAAE;AAAA,EAChE;AACF;AAKO,SAAS,kBAAkB,UAAqC;AACrE,QAAM,UAAU,OAAO,KAAK,CAAC,SAAS,OAAO,CAAC;AAC9C,QAAM,WAAW,OAAO,KAAK,CAAC,UAAU,CAAC;AACzC,QAAM,aAAa,OAAO,KAAK,CAAC,aAAa,CAAC;AAC9C,QAAM,gBAAgB,OAAO,MAAM,CAAC;AACpC,gBAAc,cAAc,SAAS,WAAW,QAAQ,CAAC;AAEzD,SAAO,OAAO,OAAO;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX,CAAC;AACH;AAKO,SAAS,oBAAoB,MAAiC;AACnE,MAAI,SAAS;AAEb,QAAM,UAAU,KAAK,MAAM;AAC3B,YAAU;AAEV,MAAI,YAAY,kBAAkB;AAChC,UAAM,IAAI,MAAM,iCAAiC,OAAO,EAAE;AAAA,EAC5D;AAEA,QAAM,WAAW,KAAK,MAAM;AAC5B,YAAU;AAEV,QAAM,aAAa,KAAK,MAAM;AAC9B,YAAU;AAEV,QAAM,gBAAgB,KAAK,aAAa,MAAM;AAC9C,YAAU;AAEV,MAAI,aAAa,YAAY;AAC3B,UAAM,IAAI,MAAM,qCAAqC,QAAQ,EAAE;AAAA,EACjE;AACA,MAAI,eAAe,eAAe;AAChC,UAAM,IAAI,MAAM,wCAAwC,UAAU,EAAE;AAAA,EACtE;AAEA,QAAM,QAAQ,KAAK,MAAM,QAAQ,SAAS,QAAQ;AAClD,YAAU;AAEV,QAAM,UAAU,KAAK,MAAM,QAAQ,SAAS,UAAU;AACtD,YAAU;AAEV,QAAM,aAAa,KAAK,MAAM,QAAQ,SAAS,aAAa;AAE5D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AASO,SAAS,kBACd,cACA,iBACa;AAEb,QAAM,eAAe;AAAA,IACnB,aAAa;AAAA,IACb;AAAA,EACF;AAIA,QAAM,EAAE,SAAS,QAAQ,IAAI;AAAA,IAC3B;AAAA,IACA,aAAa;AAAA,IACb;AAAA,EACF;AAGA,QAAM,YAAmB,oBAAY,UAAU;AAC/C,QAAM,YAAmB,oBAAY,UAAU;AAE/C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAKO,SAAS,eAAe,SAAsB,WAA2B;AAE9E,iBAAe,QAAQ,SAAS;AAEhC,QAAM,WAAW,QAAQ,QAAQ,SAAS,WAAW,QAAQ,SAAS;AAEtE,SAAO,kBAAkB,QAAQ;AACnC;AAKO,SAAS,eAAe,SAAsB,MAAsB;AACzE,QAAM,WAAW,oBAAoB,IAAI;AAKzC,QAAM,YAAY,QAAQ,QAAQ,SAAS,QAAQ;AAEnD,SAAO;AACT;AAKA,SAAS,eAAe,OAAqB;AAC3C,MAAI,QAAQ;AACZ,WAAS,IAAI,MAAM,SAAS,GAAG,KAAK,KAAK,QAAQ,GAAG,KAAK;AACvD,UAAM,MAAM,MAAM,CAAC,IAAI;AACvB,UAAM,CAAC,IAAI,MAAM;AACjB,YAAQ,OAAO;AAAA,EACjB;AAGA,MAAI,QAAQ,GAAG;AACb,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AACF;AASO,SAAS,mBAAmB,WAA2B;AAC5D,SAAO,UAAU,SAAS,QAAQ;AACpC;AAYO,SAAS,iBAAiB,SAG/B;AACA,SAAO;AAAA,IACL,WAAW,mBAAmB,QAAQ,SAAS;AAAA,IAC/C,YAAY,QAAQ,WAAW,SAAS,QAAQ;AAAA,EAClD;AACF;;;AC5cO,SAAS,iBAAiB,SAAiD;AAChF,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,QAAQ,QAAQ,SAAS,IAAI,EAAE,QAAQ,QAAQ,EAAE;AAC1D;AAUO,SAAS,mBAAmB,SAAiD;AAClF,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,OAAO;AACzB,WAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,IAAI,EAAE,IAAI,KAAK,EAAE;AAAA,EAChD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AL6DA,IAAM,4BAA4B,IAAI,KAAK;AAC3C,IAAM,mCAAmC,KAAK;AAC9C,IAAM,sCAAsC;AAC5C,IAAM,iCAAiC;AACvC,IAAM,4BAA4B;AAO3B,IAAM,mBAAN,cAA+BC,cAAa;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,mBAA+C;AAAA,EAC/C,cAAc;AAAA,EACd,oBAAoB;AAAA,EAEpB;AAAA,EACA;AAAA,EAEA,SAA0B;AAAA,IAChC,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,OAAO;AAAA,MACL,KAAK,EAAE,WAAW,OAAO,WAAW,UAAU,YAAY,EAAE;AAAA,MAC5D,OAAO,EAAE,WAAW,OAAO,WAAW,UAAU,YAAY,EAAE;AAAA,MAC9D,MAAM,EAAE,WAAW,OAAO,WAAW,UAAU,YAAY,EAAE;AAAA,IAC/D;AAAA,EACF;AAAA,EAEA,YAAY,MAA+B;AACzC,UAAM;AAEN,QAAI,CAAC,KAAK,cAAc;AACtB,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AACA,SAAK,SAAS,KAAK;AACnB,SAAK,WAAW,KAAK;AACrB,SAAK,SAAS,KAAK;AACnB,SAAK,eAAe,KAAK;AACzB,SAAK,eAAe,KAAK;AACzB,SAAK,kBAAkB,KAAK;AAC5B,SAAK,UAAU,KAAK,WAAW;AAC/B,SAAK,kBAAkB,KAAK,mBAAmB;AAC/C,SAAK,wBAAwB,KAAK,yBAAyB;AAC3D,SAAK,2BAA2B,KAAK,4BAA4B;AAGjE,UAAM,YAAY,OAAO,QAAQ,IAAI,8BAA8B;AACnE,SAAK,sBACH,KAAK,wBACJ,OAAO,SAAS,SAAS,KAAK,YAAY,IAAI,YAAY,WAC3D;AAIF,UAAM,UAAU,OAAO,QAAQ,IAAI,yBAAyB;AAC5D,SAAK,kBACH,KAAK,oBACJ,OAAO,SAAS,OAAO,KAAK,WAAW,KAAK,WAAW,MAAM,UAAU,WACxE;AAEF,UAAM,YAAY,mBAAmB,KAAK,YAAY;AACtD,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,sEAAsE,KAAK,YAAY,EAAE;AAAA,IAC3G;AAIA,UAAM,cAA4B,WAAW,KAAK,KAAK,YAAY,IAAI,QAAQ;AAC/E,SAAK,mBAAmB,IAAI,iBAAiB;AAAA,MAC3C,SAAS,KAAK;AAAA,MACd,SAAS,KAAK;AAAA,MACd,SAAS,KAAK;AAAA,MACd;AAAA,MACA;AAAA,IACF,CAAC;AAYD,SAAK,mBAAmB;AAGxB,QAAI,KAAK,iBAAiB;AACxB,WAAK,cAAc;AAAA,QACjB,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAuB;AAC3B,YAAQ,IAAI,+CAA+C;AAG3D,UAAM,KAAK,eAAe;AAG1B,SAAK,kBAAkB;AAGvB,SAAK,qBAAqB;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAsB;AAC1B,YAAQ,IAAI,+CAA+C;AAC3D,SAAK,oBAAoB;AAGzB,QAAI,KAAK,YAAY;AACnB,mBAAa,KAAK,UAAU;AAC5B,WAAK,aAAa;AAAA,IACpB;AAEA,QAAI,KAAK,kBAAkB;AACzB,mBAAa,KAAK,gBAAgB;AAClC,WAAK,mBAAmB;AAAA,IAC1B;AAGA,QAAI,KAAK,aAAa;AACpB,YAAM,KAAK,YAAY,WAAW;AAClC,WAAK,cAAc;AAAA,IACrB;AAEA,SAAK,OAAO,YAAY;AACxB,SAAK,KAAK,SAAS;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,YAA6B;AAC3B,WAAO,EAAE,GAAG,KAAK,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,MAAgC;AAC7C,QAAI,CAAC,KAAK,OAAO,WAAW;AAC1B,cAAQ,KAAK,oDAAoD;AACjE,aAAO;AAAA,IACT;AAEA,YAAQ,KAAK,OAAO,aAAa;AAAA,MAC/B,KAAK;AACH,eAAO,KAAK,YAAY,IAAI;AAAA,MAE9B,KAAK;AACH,eAAO,KAAK,cAAc,IAAI;AAAA,MAEhC,KAAK;AACH,eAAO,KAAK,aAAa,IAAI;AAAA,MAE/B;AACE,gBAAQ,KAAK,4CAA4C,KAAK,OAAO,WAAW;AAChF,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAA8B;AAClC,YAAQ,IAAI,6CAA6C;AACzD,SAAK,iBAAiB,eAAe;AACrC,UAAM,KAAK,eAAe;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,iBAA+B;AACnD,SAAK,kBAAkB;AACvB,SAAK,cAAc;AAAA,MACjB,KAAK;AAAA,MACL;AAAA,IACF;AACA,YAAQ,IAAI,8CAA8C;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,iBAAgC;AAC5C,QAAI;AACF,cAAQ,IAAI,iDAAiD;AAE7D,YAAM,UAAU,MAAM,KAAK,iBAAiB,SAAS;AAGrD,iBAAW,UAAU,SAAS;AAC5B,cAAMC,SAAO,OAAO,UAAU;AAC9B,aAAK,OAAO,MAAMA,MAAI,IAAI;AAAA,UACxB,WAAW,OAAO;AAAA,UAClB,WAAW,OAAO,UAAU,OAAO,YAAY;AAAA,UAC/C,YAAY,OAAO;AAAA,QACrB;AAEA,gBAAQ;AAAA,UACN,sBAAsBA,MAAI,KAAK,OAAO,UAAU,OAAO,OAAO,UAAU,QAAQ,CAAC,CAAC,QAAQ,QAAQ;AAAA,QACpG;AAAA,MACF;AAaA,YAAM,YAAY,KAAK,iBAAiB,WAAW,SAAS;AAAA,QAC1D,cAAc,KAAK;AAAA,QACnB,iBAAiB,KAAK;AAAA,MACxB,CAAC;AAID,WAAK,OAAO,kBAAkB;AAE9B,UAAI,CAAC,WAAW;AACd,gBAAQ,KAAK,8DAA8D;AAC3E,cAAM,SAAS,QAAQ,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO;AAC/C,YAAI,OAAO,SAAS,GAAG;AACrB,gBAAM,UAAU,OACb,IAAI,CAAC,MAAM,GAAG,EAAE,UAAU,IAAI,IAAI,EAAE,SAAS,aAAa,EAAE,EAC5D,KAAK,IAAI;AACZ,eAAK,OAAO,YAAY,sBAAsB,OAAO;AAAA,QACvD,OAAO;AACL,eAAK,OAAO,YAAY;AAAA,QAC1B;AACA;AAAA,MACF;AAQA,YAAM,kBAAkB,KAAK,mBACzB,KAAK,kBAAkB,KAAK,iBAAiB,IAAI,IACjD;AACJ,YAAM,cACJ,CAAC,KAAK,oBACN,KAAK,iBAAiB,SAAS,UAAU,QACzC,KAAK,iBAAiB,aAAa,UAAU,YAC7C,CAAC;AAEH,UAAI,aAAa;AACf,cAAM,KAAK,aAAa,SAAS;AAAA,MACnC,OAAO;AACL,gBAAQ,IAAI,+CAA+C;AAAA,MAC7D;AAEA,WAAK,mBAAmB;AACxB,WAAK,iBAAiB,iBAAiB,SAAS;AAChD,WAAK,OAAO,YAAY;AAAA,IAC1B,SAAS,KAAK;AACZ,cAAQ,MAAM,oCAAoC,GAAG;AACrD,WAAK,OAAO,kBAAkB;AAC9B,WAAK,OAAO,YAAY,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACzE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,kBAAkB,MAA+B;AACvD,YAAQ,MAAM;AAAA,MACZ,KAAK,SAAS;AACZ,YAAI,CAAC,KAAK,YAAa,QAAO;AAC9B,cAAM,SAAS,KAAK,YAAY,UAAU;AAC1C,eAAO,OAAO,qBAAqB,QAAQ,OAAO,kBAAkB;AAAA,MACtE;AAAA,MACA,KAAK;AAGH,eAAO,KAAK,OAAO,cAAc;AAAA,MACnC,KAAK;AAEH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,aAAa,WAA+C;AACxE,QAAI,KAAK,aAAa;AACpB,cAAQ,IAAI,wDAAwD;AACpE;AAAA,IACF;AAEA,UAAM,YAAY,KAAK,IAAI;AAC3B,SAAK,cAAc;AACnB,YAAQ;AAAA,MACN,mCAAmC,UAAU,IAAI,OAAO,UAAU,QAAQ;AAAA,IAC5E;AAEA,QAAI;AAEF,YAAM,KAAK,kBAAkB;AAG7B,cAAQ,UAAU,MAAM;AAAA,QACtB,KAAK;AACH,gBAAM,KAAK,WAAW;AACtB;AAAA,QAEF,KAAK;AACH,gBAAM,KAAK,aAAa;AACxB;AAAA,QAEF,KAAK;AACH,gBAAM,KAAK,YAAY;AACvB;AAAA,MACJ;AAGA,YAAM,aAAa,KAAK,IAAI,IAAI;AAChC,cAAQ,IAAI,kCAAkC,UAAU,IAAI,OAAO,UAAU,IAAI;AAEjF,UAAI,aAAa,KAAK;AACpB,gBAAQ,KAAK,kDAAkD,UAAU;AAAA,MAC3E;AAEA,WAAK,OAAO,cAAc,UAAU;AACpC,WAAK,OAAO,kBAAkB,UAAU;AACxC,WAAK,OAAO,YAAY,UAAU;AAClC,WAAK,OAAO,YAAY;AACxB,WAAK,OAAO,kBAAkB,KAAK,IAAI;AAEvC,WAAK,KAAK,YAAY,EAAE,MAAM,UAAU,MAAM,UAAU,UAAU,UAAU,WAAW,UAAU,UAAU,CAAC;AAAA,IAC9G,SAAS,KAAK;AACZ,cAAQ,MAAM,6CAA6C,GAAG;AAC9D,WAAK,OAAO,YAAY;AACxB,WAAK,OAAO,YAAY,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AACvE,WAAK,KAAK,SAAS,GAAG;AAGtB,UAAI,KAAK,kBAAkB;AACzB,cAAM,KAAK,YAAY,KAAK,iBAAiB,IAAI;AAAA,MACnD;AAAA,IACF,UAAE;AACA,WAAK,cAAc;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,oBAAmC;AAC/C,QAAI,KAAK,aAAa;AACpB,YAAM,KAAK,YAAY,WAAW;AAClC,WAAK,cAAc;AAAA,IACrB;AAAA,EAGF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,aAA4B;AACxC,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,IAAI,MAAM,gDAAgD;AAAA,IAClE;AAEA,YAAQ,IAAI,wCAAwC;AAGpD,SAAK,OAAO,YAAY;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,oBAAI,IAAmD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOpF,mBAAmB,QAAgB,SAAsD;AACvF,SAAK,mBAAmB,IAAI,QAAQ,OAAO;AAC3C,QAAI,KAAK,aAAa;AACpB,WAAK,YAAY,mBAAmB,QAAQ,OAAO;AAAA,IACrD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,SAA2B;AACrC,QAAI,CAAC,KAAK,YAAa,QAAO;AAC9B,WAAO,KAAK,YAAY,YAAY,OAAO;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eAA8B;AAC1C,YAAQ,IAAI,0CAA0C;AAEtD,UAAM,WAAW,iBAAiB,KAAK,YAAY;AACnD,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,qEAAqE,KAAK,YAAY,EAAE;AAAA,IAC1G;AACA,SAAK,cAAc,IAAI,YAAY;AAAA,MACjC,QAAQ,KAAK;AAAA,MACb,UAAU,KAAK;AAAA,MACf,QAAQ,KAAK;AAAA,MACb;AAAA,MACA,eAAe;AAAA,IACjB,CAAC;AAGD,SAAK,YAAY,GAAG,aAAa,MAAM;AACrC,cAAQ,IAAI,oCAAoC;AAChD,WAAK,OAAO,YAAY;AACxB,WAAK,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAAA,IAC1C,CAAC;AAED,SAAK,YAAY,GAAG,gBAAgB,MAAM;AACxC,cAAQ,IAAI,uCAAuC;AACnD,WAAK,OAAO,YAAY;AACxB,WAAK,KAAK,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAG3C,UAAI,CAAC,KAAK,mBAAmB;AAC3B,aAAK,KAAK,eAAe;AAAA,MAC3B;AAAA,IACF,CAAC;AAED,SAAK,YAAY,GAAG,SAAS,CAAC,QAAQ;AACpC,cAAQ,MAAM,mCAAmC,GAAG;AACpD,WAAK,KAAK,SAAS,GAAG;AAAA,IACxB,CAAC;AAED,SAAK,YAAY,GAAG,WAAW,CAAC,YAAY;AAC1C,WAAK,KAAK,WAAW,OAAO;AAAA,IAC9B,CAAC;AAED,SAAK,YAAY,GAAG,QAAQ,CAAC,SAAS;AACpC,WAAK,KAAK,QAAQ,IAAI;AAAA,IACxB,CAAC;AAGD,eAAW,CAAC,QAAQ,OAAO,KAAK,KAAK,oBAAoB;AACvD,WAAK,YAAY,mBAAmB,QAAQ,OAAO;AAAA,IACrD;AAEA,UAAM,KAAK,YAAY,QAAQ;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,cAA6B;AACzC,YAAQ,IAAI,yCAAyC;AAErD,SAAK,OAAO,YAAY;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,YAAY,MAAqC;AAC7D,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,cAAM,KAAK,WAAW;AACtB;AAAA,MACF,KAAK;AACH,cAAM,KAAK,aAAa;AACxB;AAAA,MACF,KAAK;AACH,cAAM,KAAK,YAAY;AACvB;AAAA,IACJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAY,MAAuB;AACzC,QAAI,CAAC,KAAK,aAAa;AACrB,cAAQ,MAAM,0DAA0D;AACxE,aAAO;AAAA,IACT;AAGA,UAAM,YAAY,KAAK,YAAY,UAC/B,KAAK,YAAY,UACjB;AAIJ,SAAK,KAAK,QAAQ,SAAS;AAC3B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,MAAuB;AAC3C,QAAI,CAAC,KAAK,aAAa;AACrB,cAAQ,MAAM,4DAA4D;AAC1E,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,YAAY,YAAY,IAAI;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,MAAuB;AAE1C,YAAQ,KAAK,0DAA0D;AACvE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAA0B;AAChC,SAAK,mBAAmB,YAAY,YAAY;AAC9C,UAAI,KAAK,kBAAmB;AAE5B,YAAM,KAAK,mBAAmB;AAAA,IAChC,GAAG,KAAK,qBAAqB;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,qBAAoC;AAChD,UAAM,cAAc,KAAK,OAAO;AAChC,QAAI,CAAC,YAAa;AAElB,QAAI;AACF,YAAM,YAAY,KAAK,IAAI;AAE3B,cAAQ,aAAa;AAAA,QACnB,KAAK;AACH,gBAAM,KAAK,eAAe;AAC1B;AAAA,QAEF,KAAK;AACH,gBAAM,KAAK,iBAAiB;AAC5B;AAAA,QAEF,KAAK;AACH,gBAAM,KAAK,gBAAgB;AAC3B;AAAA,MACJ;AAEA,YAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,WAAK,OAAO,YAAY;AACxB,WAAK,OAAO,kBAAkB,KAAK,IAAI;AAGvC,UAAI,UAAU,KAAK,0BAA0B;AAC3C,gBAAQ;AAAA,UACN,4CAA4C,OAAO;AAAA,QACrD;AACA,aAAK,KAAK,eAAe;AAAA,MAC3B;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,2CAA2C,GAAG;AAC5D,WAAK,OAAO,YAAY;AAGxB,UAAI,CAAC,KAAK,mBAAmB;AAC3B,aAAK,KAAK,eAAe;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBAAgC;AAG5C,QAAI,CAAC,KAAK,OAAO,WAAW;AAC1B,YAAM,IAAI,MAAM,mBAAmB;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,mBAAkC;AAC9C,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAEA,UAAM,SAAS,KAAK,YAAY,UAAU;AAC1C,QAAI,CAAC,OAAO,oBAAoB,CAAC,OAAO,eAAe;AACrD,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACvC;AAGA,QAAI,OAAO,iBAAiB,KAAK,IAAI,IAAI,OAAO,gBAAgB,KAAO;AACrE,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,kBAAiC;AAAA,EAG/C;AAAA;AAAA;AAAA;AAAA,EAKQ,uBAA6B;AACnC,SAAK,aAAa,YAAY,YAAY;AACxC,UAAI,KAAK,qBAAqB,KAAK,YAAa;AAEhD,cAAQ,IAAI,sCAAsC;AAClD,YAAM,KAAK,eAAe;AAAA,IAC5B,GAAG,KAAK,eAAe;AAAA,EACzB;AACF;;;AM/wBA,YAAYC,aAAY;;;ACAxB,YAAYC,aAAY;AACxB,YAAYC,SAAQ;AACpB,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB,OAAOC,eAAc;;;ACcrB,YAAYC,aAAY;AACxB,YAAYC,SAAQ;AAEpB,IAAM,kBAAkB;AACxB,IAAM,YAAY;AAClB,IAAM,cAAc;AAQpB,SAAS,YAAY,OAAwB;AAC3C,SAAO,OAAO,UAAU,YAAY,MAAM,WAAW,eAAe;AACtE;AAEA,SAAS,UAAyB;AAChC,QAAM,MAAM,QAAQ,IAAI,gBAAgB;AACxC,MAAI,KAAK;AACP,UAAM,MAAM,OAAO,KAAK,KAAK,QAAQ;AACrC,QAAI,IAAI,WAAW,IAAI;AACrB,YAAM,IAAI,MAAM,+CAA+C,IAAI,MAAM,EAAE;AAAA,IAC7E;AACA,WAAO;AAAA,EACT;AACA,QAAM,UAAU,QAAQ,IAAI,qBAAqB;AACjD,MAAI,SAAS;AACX,UAAM,WAAc,iBAAa,SAAS,OAAO,EAAE,KAAK;AACxD,UAAM,MAAM,OAAO,KAAK,UAAU,QAAQ;AAC1C,QAAI,IAAI,WAAW,IAAI;AACrB,YAAM,IAAI,MAAM,oDAAoD,IAAI,MAAM,EAAE;AAAA,IAClF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,sBAAqC;AACnD,QAAM,OAAO,QAAQ,IAAI,uBAAuB,MAAM;AACtD,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS,CAAC,MAAM;AAAA,MAChB,SAAS,CAAC,MAAM;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,MAAM,QAAQ;AACpB,MAAI,CAAC,KAAK;AAER,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,QAAMC,WAAU,CAAC,cAA8B;AAC7C,QAAI,OAAO,cAAc,SAAU,QAAO;AAC1C,QAAI,YAAY,SAAS,EAAG,QAAO;AACnC,UAAM,QAAe,oBAAY,SAAS;AAC1C,UAAM,SAAgB,uBAAe,eAAe,KAAK,KAAK;AAC9D,UAAM,KAAK,OAAO,OAAO,CAAC,OAAO,OAAO,WAAW,MAAM,GAAG,OAAO,MAAM,CAAC,CAAC;AAC3E,UAAM,UAAU,OAAO,WAAW;AAClC,WAAO;AAAA,MACL,gBAAgB,MAAM,GAAG,EAAE;AAAA;AAAA,MAC3B,MAAM,SAAS,QAAQ;AAAA,MACvB,QAAQ,SAAS,QAAQ;AAAA,MACzB,GAAG,SAAS,QAAQ;AAAA,IACtB,EAAE,KAAK,GAAG;AAAA,EACZ;AAEA,QAAMC,WAAU,CAAC,UAA0B;AACzC,QAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAI,CAAC,YAAY,KAAK,EAAG,QAAO;AAChC,UAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,QAAI,MAAM,WAAW,GAAG;AACtB,YAAM,IAAI,MAAM,kDAAkD;AAAA,IACpE;AACA,UAAM,CAAC,EAAE,EAAE,UAAU,YAAY,KAAK,IAAI;AAC1C,UAAM,QAAQ,OAAO,KAAK,UAAU,QAAQ;AAC5C,UAAM,UAAU,OAAO,KAAK,YAAY,QAAQ;AAChD,UAAM,KAAK,OAAO,KAAK,OAAO,QAAQ;AACtC,QAAI,MAAM,WAAW,aAAa,QAAQ,WAAW,aAAa;AAChE,YAAM,IAAI,MAAM,qDAAqD;AAAA,IACvE;AACA,UAAM,WAAkB,yBAAiB,eAAe,KAAK,KAAK;AAClE,aAAS,WAAW,OAAO;AAC3B,UAAM,KAAK,OAAO,OAAO,CAAC,SAAS,OAAO,EAAE,GAAG,SAAS,MAAM,CAAC,CAAC;AAChE,WAAO,GAAG,SAAS,MAAM;AAAA,EAC3B;AAEA,SAAO,EAAE,SAAS,MAAM,SAAAD,UAAS,SAAAC,SAAQ;AAC3C;;;ADhCA,SAAS,mBAA2B;AAClC,SAAY,WAAQ,YAAQ,GAAG,YAAY,WAAW;AACxD;AAEA,SAAS,SAAiB;AACxB,UAAO,oBAAI,KAAK,GAAE,YAAY;AAChC;AAEA,SAAS,YAAY,SAAyB;AAC5C,SAAc,mBAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AACjE;AAKA,SAAS,gBACP,KACA,iBAAwC,CAAC,MAAM,GACnC;AACZ,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,SAAS,IAAI;AAAA,IACb,WAAW,IAAI;AAAA,IACf,OAAO,IAAI;AAAA,IACX,MAAM,IAAI;AAAA,IACV,SAAS,eAAe,IAAI,OAAiB;AAAA,IAC7C,SAAS,IAAI;AAAA,IACb,YAAa,IAAI,cAAyB;AAAA,IAC1C,aAAc,IAAI,eAA0B;AAAA,IAC5C,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,IACf,OAAQ,IAAI,UAAqB;AAAA,EACnC;AACF;AAMA,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuEnB,SAAS,gBAAgB,UAAkB,IAAkC;AAC3E,MAAI;AACJ,MAAI;AACF,UAAS,iBAAa,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,QAAQ;AACN;AAAA,EACF;AAEA,QAAM,QAAQ,MAAM,QAAQ,OAAO,KAAK,IAAI,OAAO,QAAQ,CAAC;AAC5D,QAAM,WAAW,MAAM,QAAQ,OAAO,QAAQ,IAAI,OAAO,WAAW,CAAC;AACrE,QAAM,SAAS,MAAM,QAAQ,OAAO,MAAM,IAAI,OAAO,SAAS,CAAC;AAE/D,MAAI,MAAM,WAAW,KAAK,SAAS,WAAW,KAAK,OAAO,WAAW,GAAG;AACtE;AAAA,EACF;AAEA,QAAM,aAAa,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,GAK7B;AAED,QAAM,gBAAgB,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,GAKhC;AAED,QAAM,cAAc,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,GAK9B;AAED,QAAM,YAAY,GAAG,YAAY,MAAM;AACrC,eAAW,KAAK,OAAO;AACrB,iBAAW,IAAI;AAAA,QACb,IAAI,EAAE;AAAA,QACN,SAAS,EAAE;AAAA,QACX,WAAW,EAAE;AAAA,QACb,OAAO,EAAE;AAAA,QACT,MAAM,EAAE;AAAA,QACR,SAAS,EAAE;AAAA,QACX,SAAS,EAAE;AAAA,QACX,YAAY,EAAE,cAAc;AAAA,QAC5B,aAAa,EAAE,eAAe;AAAA,QAC9B,aAAa,EAAE;AAAA,QACf,WAAW,EAAE;AAAA,QACb,WAAW,EAAE;AAAA,QACb,OAAO,EAAE,QAAQ,IAAI;AAAA,MACvB,CAAC;AAAA,IACH;AACA,eAAW,KAAK,UAAU;AACxB,oBAAc,IAAI;AAAA,QAChB,IAAI,EAAE;AAAA,QACN,QAAQ,EAAE;AAAA,QACV,SAAS,EAAE;AAAA,QACX,SAAS,EAAE;AAAA,QACX,WAAW,EAAE;AAAA,MACf,CAAC;AAAA,IACH;AACA,eAAW,KAAK,QAAQ;AACtB,kBAAY,IAAI;AAAA,QACd,IAAI,EAAE;AAAA,QACN,SAAS,EAAE;AAAA,QACX,OAAO,EAAE;AAAA,QACT,SAAS,EAAE;AAAA,QACX,WAAW,EAAE;AAAA,MACf,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,YAAU;AAGV,MAAI;AACF,IAAG,eAAW,UAAU,WAAW,WAAW;AAAA,EAChD,QAAQ;AAAA,EAER;AACF;AAMO,IAAM,WAAN,MAAe;AAAA,EACH;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,oBAAsC,EAAE,SAAS,MAAM,GAAG,MAA8B;AAClG,SAAK,WAAW,MAAM,YAAY,iBAAiB;AAKnD,SAAK,SAAS,oBAAoB;AAGlC,IAAG,cAAe,cAAQ,KAAK,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAE7D,SAAK,KAAK,IAAIC,UAAS,KAAK,QAAQ;AACpC,SAAK,GAAG,OAAO,oBAAoB;AACnC,SAAK,GAAG,OAAO,mBAAmB;AAGlC,SAAK,GAAG,KAAK,UAAU;AAGvB,UAAM,WAAW,KAAK,SAAS,QAAQ,SAAS,OAAO;AACvD,QAAI,aAAa,KAAK,YAAe,eAAW,QAAQ,GAAG;AACzD,YAAM,QAAS,KAAK,GAAG,QAAQ,0CAA0C,EAAE,IAAI,EAAsB;AACrG,UAAI,UAAU,GAAG;AACf,wBAAgB,UAAU,KAAK,EAAE;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,gBAAgB,OAAyC;AACvD,UAAM,QAAQ,MAAM,SAAS;AAC7B,UAAM,YAAY,OAAO;AAEzB,UAAM,WAAW,KAAK,GAAG;AAAA,MACvB;AAAA,IACF,EAAE,IAAI,MAAM,SAAS,OAAO,MAAM,IAAI;AAEtC,QAAI,UAAU;AACZ,YAAM,aAAc,SAAS,UAAqB;AAClD,YAAM,UAAU,YAAY,MAAM,OAAO;AACzC,YAAM,mBAAmB,KAAK,OAAO,QAAQ,MAAM,OAAO;AAI1D,YAAM,WAAW,KAAK,GAAG,YAAY,MAAM;AAIzC,aAAK,GAAG,QAAQ;AAAA;AAAA;AAAA,SAGf,EAAE;AAAA,UACM,mBAAW;AAAA,UAClB,SAAS;AAAA,UACT,SAAS;AAAA,UACT,SAAS;AAAA,UACT;AAAA,QACF;AAGA,aAAK,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,SAKf,EAAE;AAAA,UACD;AAAA,UACA;AAAA,UACA,MAAM,cAAc;AAAA,UACpB,MAAM,eAAe;AAAA,UACrB;AAAA,UACA;AAAA,UACA,SAAS;AAAA,QACX;AAAA,MACF,CAAC;AACD,eAAS;AAET,aAAO;AAAA,QACL,IAAI,SAAS;AAAA,QACb,SAAS,SAAS;AAAA,QAClB,WAAW,SAAS;AAAA,QACpB,OAAO,SAAS;AAAA,QAChB,MAAM,SAAS;AAAA,QACf,SAAS,MAAM;AAAA,QACf,SAAS;AAAA,QACT,YAAY,MAAM;AAAA,QAClB,aAAa,MAAM;AAAA,QACnB,aAAa;AAAA,QACb,WAAW,SAAS;AAAA,QACpB,WAAW;AAAA,QACX,OAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,KAAY,mBAAW;AAC7B,UAAM,cAAc,YAAY,MAAM,OAAO;AAC7C,SAAK,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA,KAIf,EAAE;AAAA,MACD;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,MACA,MAAM;AAAA,MACN,KAAK,OAAO,QAAQ,MAAM,OAAO;AAAA,MACjC,MAAM,cAAc;AAAA,MACpB,MAAM,eAAe;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA,SAAS,MAAM;AAAA,MACf,WAAW,MAAM;AAAA,MACjB;AAAA,MACA,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,MACf,SAAS;AAAA,MACT,YAAY,MAAM;AAAA,MAClB,aAAa,MAAM;AAAA,MACnB;AAAA,MACA,WAAW;AAAA,MACX,WAAW;AAAA,MACX,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,kBAAkB,IAA+B;AAC/C,UAAM,MAAM,KAAK,GAAG,QAAQ,yCAAyC,EAAE,IAAI,EAAE;AAC7E,WAAO,MAAM,gBAAgB,KAAK,KAAK,OAAO,OAAO,IAAI;AAAA,EAC3D;AAAA,EAEA,iBAAiB,IAAqB;AAEpC,UAAM,SAAS,KAAK,GAAG,QAAQ,uCAAuC,EAAE,IAAI,EAAE;AAC9E,WAAO,OAAO,UAAU;AAAA,EAC1B;AAAA,EAEA,gBAAgB,UAA6B,CAAC,GAAiB;AAC7D,UAAM,aAAuB,CAAC;AAC9B,UAAM,SAAoB,CAAC;AAE3B,QAAI,QAAQ,SAAS;AACnB,iBAAW,KAAK,aAAa;AAC7B,aAAO,KAAK,QAAQ,OAAO;AAAA,IAC7B;AACA,QAAI,QAAQ,OAAO;AACjB,iBAAW,KAAK,WAAW;AAC3B,aAAO,KAAK,QAAQ,KAAK;AAAA,IAC3B;AACA,QAAI,QAAQ,MAAM;AAChB,iBAAW,KAAK,UAAU;AAC1B,aAAO,KAAK,QAAQ,IAAI;AAAA,IAC1B;AACA,QAAI,QAAQ,YAAY;AACtB,iBAAW,KAAK,gBAAgB;AAChC,aAAO,KAAK,QAAQ,UAAU;AAAA,IAChC;AACA,QAAI,QAAQ,UAAU,QAAW;AAC/B,iBAAW,KAAK,WAAW;AAC3B,aAAO,KAAK,QAAQ,QAAQ,IAAI,CAAC;AAAA,IACnC;AAEA,UAAM,QAAQ,WAAW,SAAS,IAAI,WAAW,WAAW,KAAK,OAAO,IAAI;AAC5E,UAAM,QAAQ,QAAQ,SAAS;AAC/B,UAAM,SAAS,QAAQ,UAAU;AAEjC,UAAM,MAAM,8BAA8B,KAAK;AAC/C,WAAO,KAAK,OAAO,MAAM;AAEzB,UAAM,OAAO,KAAK,GAAG,QAAQ,GAAG,EAAE,IAAI,GAAG,MAAM;AAC/C,WAAO,KAAK,IAAI,CAAC,MAAM,gBAAgB,GAAG,KAAK,OAAO,OAAO,CAAC;AAAA,EAChE;AAAA,EAEA,kBAAkB,SAAiB,UAA6B,CAAC,GAAyB;AACxF,UAAM,QAAQ,QACX,YAAY,EACZ,MAAM,KAAK,EACX,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,OAAO;AAEjB,QAAI,MAAM,WAAW,EAAG,QAAO,CAAC;AAGhC,UAAM,WAAW,MAAM,IAAI,CAAC,MAAM,MAAM,EAAE,QAAQ,MAAM,IAAI,IAAI,GAAG,EAAE,KAAK,GAAG;AAE7E,UAAM,aAAuB,CAAC;AAC9B,UAAM,SAAoB,CAAC,QAAQ;AAEnC,QAAI,QAAQ,SAAS;AACnB,iBAAW,KAAK,eAAe;AAC/B,aAAO,KAAK,QAAQ,OAAO;AAAA,IAC7B;AACA,QAAI,QAAQ,OAAO;AACjB,iBAAW,KAAK,aAAa;AAC7B,aAAO,KAAK,QAAQ,KAAK;AAAA,IAC3B;AACA,QAAI,QAAQ,MAAM;AAChB,iBAAW,KAAK,YAAY;AAC5B,aAAO,KAAK,QAAQ,IAAI;AAAA,IAC1B;AACA,QAAI,QAAQ,YAAY;AACtB,iBAAW,KAAK,kBAAkB;AAClC,aAAO,KAAK,QAAQ,UAAU;AAAA,IAChC;AACA,QAAI,QAAQ,UAAU,QAAW;AAC/B,iBAAW,KAAK,aAAa;AAC7B,aAAO,KAAK,QAAQ,QAAQ,IAAI,CAAC;AAAA,IACnC;AAEA,UAAM,aAAa,WAAW,SAAS,IAAI,SAAS,WAAW,KAAK,OAAO,IAAI;AAC/E,UAAM,QAAQ,QAAQ,SAAS;AAC/B,WAAO,KAAK,KAAK;AAEjB,UAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMR,UAAU;AAAA;AAAA;AAAA;AAKd,UAAM,OAAO,KAAK,GAAG,QAAQ,GAAG,EAAE,IAAI,GAAG,MAAM;AAE/C,WAAO,KAAK,IAAI,CAAC,QAAQ;AACvB,YAAM,OAAO,gBAAgB,KAAK,KAAK,OAAO,OAAO;AAGrD,YAAM,UAAU,IAAI;AACpB,YAAM,YAAY,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;AACxD,aAAO;AAAA,QACL,GAAG;AAAA,QACH,WAAW,aAAa;AAAA;AAAA,QACxB,SAAU,IAAI,eAA0B;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,SAAS,SAA+B;AACtC,QAAI,SAAS;AACX,YAAMC,OAAM,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAM3B,EAAE,IAAI,OAAO;AAEd,YAAMC,YAAY,KAAK,GAAG;AAAA,QACxB;AAAA,MACF,EAAE,IAAI,OAAO,EAAsB;AAEnC,aAAO;AAAA,QACL,WAAWD,KAAI;AAAA,QACf,WAAWA,KAAI;AAAA,QACf,YAAYA,KAAI;AAAA,QAChB,YAAYA,KAAI;AAAA,QAChB,YAAYC;AAAA,QACZ,WAAW;AAAA,MACb;AAAA,IACF;AAEA,UAAM,MAAM,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,KAK3B,EAAE,IAAI;AAEP,UAAM,WAAY,KAAK,GAAG,QAAQ,wCAAwC,EAAE,IAAI,EAAsB;AAEtG,WAAO;AAAA,MACL,WAAW,IAAI;AAAA,MACf,WAAW,IAAI;AAAA,MACf,YAAY,IAAI;AAAA,MAChB,YAAY,IAAI;AAAA,MAChB,YAAY;AAAA,MACZ,WAAW;AAAA,IACb;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,SAAK,GAAG,MAAM;AAAA,EAChB;AACF;AAMA,IAAI,mBAAoC;AAEjC,SAAS,cAAwB;AACtC,MAAI,qBAAqB,MAAM;AAC7B,uBAAmB,IAAI,SAAS;AAAA,EAClC;AACA,SAAO;AACT;AAEO,SAAS,gBAAsB;AACpC,MAAI,qBAAqB,MAAM;AAC7B,qBAAiB,MAAM;AACvB,uBAAmB;AAAA,EACrB;AACF;AAMO,SAAS,eAAuB;AACrC,SAAc,oBAAY,EAAE;AAC9B;AAEO,SAASC,WAAU,UAAkB,MAAsB;AAChE,SAAc,mBAAW,UAAU,MAAM,KAAS,IAAI,QAAQ;AAChE;AAEO,SAASC,SAAQ,WAAmB,KAAqB;AAC9D,QAAM,KAAY,oBAAY,EAAE;AAChC,QAAM,SAAgB,uBAAe,eAAe,KAAK,EAAE;AAC3D,QAAM,aAAa,OAAO,OAAO,CAAC,OAAO,OAAO,WAAW,MAAM,GAAG,OAAO,MAAM,CAAC,CAAC;AACnF,QAAM,MAAM,OAAO,WAAW;AAC9B,SAAO,OAAO,OAAO,CAAC,IAAI,KAAK,UAAU,CAAC,EAAE,SAAS,QAAQ;AAC/D;AAEO,SAASC,SAAQ,SAAiB,KAAqB;AAC5D,QAAM,SAAS,OAAO,KAAK,SAAS,QAAQ;AAC5C,QAAM,KAAK,OAAO,SAAS,GAAG,EAAE;AAChC,QAAM,MAAM,OAAO,SAAS,IAAI,EAAE;AAClC,QAAM,aAAa,OAAO,SAAS,EAAE;AACrC,QAAM,WAAkB,yBAAiB,eAAe,KAAK,EAAE;AAC/D,WAAS,WAAW,GAAG;AACvB,SAAO,OAAO,OAAO,CAAC,SAAS,OAAO,UAAU,GAAG,SAAS,MAAM,CAAC,CAAC,EAAE,SAAS,MAAM;AACvF;;;ADnnBA,IAAM,MAAM;AAwCZ,SAAS,cAAiB,KAAgB;AACxC,MAAI,IAAI,WAAW,EAAG,QAAO,CAAC;AAC9B,SAAO,KAAK,MAAM,IAAI,SAAS,MAAM,CAAC;AACxC;AAEA,SAAS,WAAW,QAA6C;AAC/D,SAAO,IAAI,IAAI,UAAU,KAAK,kBAAkB,EAAE;AACpD;AAEA,SAAS,UAAU,QAA2C;AAC5D,QAAM,WAAW,IAAI,IAAI,UAAU,KAAK,kBAAkB,EAAE;AAC5D,QAAM,QAAQ,SAAS,MAAM,oBAAoB;AACjD,SAAO,QAAQ,mBAAmB,MAAM,CAAC,CAAC,IAAI;AAChD;AAMO,IAAM,mBAAN,MAAuB;AAAA,EACX;AAAA,EAEjB,YACE,mBAAqC,EAAE,SAAS,MAAM,GACtD,OAAgC,CAAC,GACjC;AACA,SAAK,KAAK,IAAI,SAAS,kBAAkB,EAAE,UAAU,KAAK,SAAS,CAAC;AAAA,EACtE;AAAA,EAEA,cAA4B,OAAO,MAAM,KAAK,QAAQ;AACpD,QAAI;AACF,YAAM,OAAO,cAAkC,IAAI,IAAI;AACvD,UAAI,CAAC,KAAK,WAAW,CAAC,KAAK,aAAa,CAAC,KAAK,QAAQ,KAAK,YAAY,QAAW;AAChF,eAAO,SAAS,KAAK,KAAK;AAAA,UACxB,SAAS;AAAA,UACT,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SAAS;AAAA,UACX;AAAA,QACF,CAAC;AAAA,MACH;AAEA,YAAM,OAAO,KAAK,GAAG,gBAAgB;AAAA,QACnC,SAAS,KAAK;AAAA,QACd,WAAW,KAAK;AAAA,QAChB,OAAO,KAAK;AAAA,QACZ,MAAM,KAAK;AAAA,QACX,SAAS,KAAK;AAAA,QACd,YAAY,KAAK;AAAA,QACjB,aAAa,KAAK;AAAA,MACpB,CAAC;AAED,cAAQ,IAAI,GAAG,GAAG,WAAW,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,EAAE,GAAG;AACnE,eAAS,KAAK,KAAK;AAAA,QACjB,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,MAAM;AAAA,MACR,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,cAAQ,MAAM,GAAG,GAAG,iBAAiB,GAAG;AACxC,eAAS,KAAK,KAAK;AAAA,QACjB,SAAS;AAAA,QACT,OAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,eAA6B,OAAO,MAAM,KAAK,QAAQ;AACrD,QAAI;AACF,YAAM,OAAO,cAA6B,IAAI,IAAI;AAClD,UAAI,CAAC,KAAK,SAAS;AACjB,eAAO,SAAS,KAAK,KAAK;AAAA,UACxB,SAAS;AAAA,UACT,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SAAS;AAAA,UACX;AAAA,QACF,CAAC;AAAA,MACH;AAEA,YAAM,YAAY,KAAK,IAAI;AAC3B,YAAM,UAAU,KAAK,GAAG,kBAAkB,KAAK,SAAS;AAAA,QACtD,SAAS,KAAK;AAAA,QACd,OAAO,KAAK;AAAA,QACZ,OAAO,KAAK,SAAS;AAAA,MACvB,CAAC;AACD,YAAM,aAAa,KAAK,IAAI,IAAI;AAEhC,eAAS,KAAK,KAAK;AAAA,QACjB,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,MAAM;AAAA,UACJ;AAAA,UACA,OAAO,KAAK;AAAA,UACZ,OAAO,QAAQ;AAAA,UACf;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,cAAQ,MAAM,GAAG,GAAG,kBAAkB,GAAG;AACzC,eAAS,KAAK,KAAK;AAAA,QACjB,SAAS;AAAA,QACT,OAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,eAA6B,OAAO,KAAK,QAAQ;AAC/C,QAAI;AACF,YAAM,KAAK,UAAU,IAAI,GAAG;AAC5B,UAAI,CAAC,IAAI;AACP,eAAO,SAAS,KAAK,KAAK;AAAA,UACxB,SAAS;AAAA,UACT,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SAAS;AAAA,UACX;AAAA,QACF,CAAC;AAAA,MACH;AAEA,YAAM,UAAU,KAAK,GAAG,iBAAiB,EAAE;AAC3C,UAAI,CAAC,SAAS;AACZ,eAAO,SAAS,KAAK,KAAK;AAAA,UACxB,SAAS;AAAA,UACT,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SAAS,0BAA0B,EAAE;AAAA,UACvC;AAAA,QACF,CAAC;AAAA,MACH;AAEA,cAAQ,IAAI,GAAG,GAAG,YAAY,EAAE,EAAE;AAClC,eAAS,KAAK,KAAK;AAAA,QACjB,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,MAAM,EAAE,GAAG;AAAA,MACb,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,cAAQ,MAAM,GAAG,GAAG,kBAAkB,GAAG;AACzC,eAAS,KAAK,KAAK;AAAA,QACjB,SAAS;AAAA,QACT,OAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,aAA2B,OAAO,KAAK,QAAQ;AAC7C,QAAI;AACF,YAAM,QAAQ,WAAW,IAAI,GAAG;AAChC,YAAM,WAAW,MAAM,IAAI,OAAO;AAClC,YAAM,QAAQ,KAAK,GAAG,gBAAgB;AAAA,QACpC,SAAS,MAAM,IAAI,SAAS,KAAK;AAAA,QACjC,OAAO,MAAM,IAAI,OAAO,KAAK;AAAA,QAC7B,MAAM,MAAM,IAAI,MAAM,KAAK;AAAA,QAC3B,YAAY,MAAM,IAAI,YAAY,KAAK;AAAA,QACvC,OAAO,aAAa,OAAO,SAAY,aAAa;AAAA,QACpD,OAAO,MAAM,IAAI,OAAO,IAAI,SAAS,MAAM,IAAI,OAAO,KAAK,MAAM,EAAE,IAAI;AAAA,QACvE,QAAQ,MAAM,IAAI,QAAQ,IAAI,SAAS,MAAM,IAAI,QAAQ,KAAK,KAAK,EAAE,IAAI;AAAA,MAC3E,CAAC;AAED,eAAS,KAAK,KAAK;AAAA,QACjB,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,MAAM;AAAA,UACJ;AAAA,UACA,OAAO,MAAM;AAAA,QACf;AAAA,MACF,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,cAAQ,MAAM,GAAG,GAAG,gBAAgB,GAAG;AACvC,eAAS,KAAK,KAAK;AAAA,QACjB,SAAS;AAAA,QACT,OAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,cAA4B,OAAO,KAAK,QAAQ;AAC9C,QAAI;AACF,YAAM,QAAQ,WAAW,IAAI,GAAG;AAChC,YAAM,QAAQ,KAAK,GAAG,SAAS,MAAM,IAAI,SAAS,KAAK,MAAS;AAChE,eAAS,KAAK,KAAK;AAAA,QACjB,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,MAAM;AAAA,MACR,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,cAAQ,MAAM,GAAG,GAAG,iBAAiB,GAAG;AACxC,eAAS,KAAK,KAAK;AAAA,QACjB,SAAS;AAAA,QACT,OAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS;AAAA,QACX;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,eAAe,QAMN;AACP,WAAO,cAAc,QAAQ,iBAAiB,KAAK,WAAW;AAC9D,WAAO,cAAc,QAAQ,kBAAkB,KAAK,YAAY;AAChE,WAAO,cAAc,UAAU,eAAe,KAAK,YAAY;AAC/D,WAAO,cAAc,OAAO,WAAW,KAAK,UAAU;AACtD,WAAO,cAAc,OAAO,iBAAiB,KAAK,WAAW;AAE7D,YAAQ,IAAI,GAAG,GAAG,2BAA2B;AAAA,EAC/C;AAAA,EAEA,WAAiB;AACf,SAAK,GAAG,MAAM;AACd,YAAQ,IAAI,GAAG,GAAG,oBAAoB;AAAA,EACxC;AACF;;;AGvQA,YAAYC,UAAQ;AACpB,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AA8Bf,IAAM,eAAN,MAAmB;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,QAA8C;AAAA,EAC9C,UAAU;AAAA,EACV,mBAAmB;AAAA,EACV,eAAe,CAAC,KAAM,KAAO,KAAO,GAAK;AAAA,EAE1D,YAAY,MAA2B;AACrC,UAAM,UAAe,WAAQ,YAAQ,GAAG,YAAY,MAAM;AAC1D,SAAK,iBAAiB,KAAK,kBAAuB,WAAK,SAAS,cAAc;AAC9E,SAAK,iBAAiB,KAAK,kBAAuB,WAAK,SAAS,oBAAoB;AACpF,SAAK,eAAe,KAAK,aAAa,QAAQ,OAAO,EAAE;AACvD,SAAK,SAAS,KAAK;AACnB,SAAK,iBAAiB,KAAK,kBAAkB;AAC7C,SAAK,eAAe,KAAK,gBAAgB;AACzC,SAAK,YAAY,KAAK,aAAa;AAAA,EACrC;AAAA;AAAA,EAIA,QAAc;AACZ,QAAI,KAAK,QAAS;AAClB,SAAK,UAAU;AACf,YAAQ,IAAI,0CAAqC,KAAK,cAAc;AACpE,SAAK,cAAc,CAAC;AAAA,EACtB;AAAA,EAEA,OAAa;AACX,SAAK,UAAU;AACf,QAAI,KAAK,UAAU,MAAM;AACvB,mBAAa,KAAK,KAAK;AACvB,WAAK,QAAQ;AAAA,IACf;AACA,YAAQ,IAAI,wBAAwB;AAAA,EACtC;AAAA;AAAA,EAGA,MAAM,QAAuB;AAC3B,QAAI,KAAK,UAAU,MAAM;AACvB,mBAAa,KAAK,KAAK;AACvB,WAAK,QAAQ;AAAA,IACf;AACA,UAAM,KAAK,MAAM;AAAA,EACnB;AAAA;AAAA,EAIQ,cAAc,SAAuB;AAC3C,QAAI,CAAC,KAAK,QAAS;AACnB,SAAK,QAAQ,WAAW,YAAY;AAClC,YAAM,KAAK,MAAM;AACjB,YAAM,YAAY,KAAK,mBAAmB,IAAI,KAAK,mBAAmB,KAAK;AAC3E,WAAK,cAAc,SAAS;AAAA,IAC9B,GAAG,OAAO;AAAA,EACZ;AAAA,EAEA,MAAc,QAAuB;AACnC,QAAI;AACF,UAAI,SAAS,KAAK,YAAY;AAI9B,YAAM,WAAW,KAAK,UAAU,KAAK,cAAc;AACnD,UAAI,aAAa,QAAQ,WAAW,QAAQ;AAC1C,gBAAQ,IAAI,0CAA0C,QAAQ,aAAa,MAAM,eAAe;AAChG,cAAM,UAAU,KAAK,iBAAiB;AACtC,cAAM,eAAe,KAAK,eAAe,SAAS,MAAM;AACxD,YAAI,aAAa,MAAM,SAAS,GAAG;AACjC,gBAAM,YAAY,MAAM,KAAK,eAAe,aAAa,KAAK;AAC9D,cAAI,CAAC,WAAW;AAId;AAAA,UACF;AAAA,QACF;AAEA,iBAAS;AACT,aAAK,eAAe,CAAC;AAAA,MACvB;AAGA,YAAM,OAAO,KAAK,eAAe,KAAK,gBAAgB,MAAM;AAC5D,UAAI,KAAK,MAAM,WAAW,EAAG;AAE7B,YAAM,UAAU,MAAM,KAAK,eAAe,KAAK,KAAK;AACpD,UAAI,SAAS;AACX,aAAK,eAAe,KAAK,WAAW;AACpC,aAAK,mBAAmB;AAAA,MAC1B;AAAA,IAKF,SAAS,KAAK;AACZ,cAAQ,MAAM,8BAA+B,IAAc,OAAO;AAAA,IACpE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,eAAe,OAAmC;AAC9D,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,KAAK,cAAc;AACxD,YAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,KAAK,YAAY;AAClD,YAAM,SAAS,KAAK,YAAY,KAAK;AAErC,YAAM,KAAK,MAAM,KAAK,WAAW,MAAM;AACvC,UAAI,CAAC,IAAI;AACP,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,WAAW,QAAqC;AAC5D,UAAM,MAAM,GAAG,KAAK,YAAY;AAChC,QAAI;AACF,YAAM,MAAM,MAAM,KAAK,UAAU,KAAK;AAAA,QACpC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,iBAAiB,UAAU,KAAK,MAAM;AAAA,UACtC,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;AAAA,MACjC,CAAC;AAED,UAAI,IAAI,UAAU,OAAO,IAAI,SAAS,KAAK;AACzC,eAAO;AAAA,MACT;AAEA,UAAI,IAAI,UAAU,OAAO,IAAI,SAAS,KAAK;AAEzC,cAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,gBAAQ,MAAM,kCAAkC,IAAI,MAAM,sBAAsB,KAAK,MAAM,GAAG,GAAG,CAAC,EAAE;AACpG,eAAO;AAAA,MACT;AAGA,cAAQ,MAAM,+BAA+B,IAAI,MAAM,eAAe;AACtE,WAAK,iBAAiB;AACtB,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,cAAQ,MAAM,iCAAkC,IAAc,OAAO,eAAe;AACpF,WAAK,iBAAiB;AACtB,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAIQ,UAAU,UAAiC;AACjD,QAAI;AACF,aAAU,cAAS,QAAQ,EAAE;AAAA,IAC/B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,eACN,UACA,QAC0C;AAC1C,QAAI;AACF,YAAM,OAAO,KAAK,UAAU,QAAQ;AACpC,UAAI,SAAS,QAAQ,QAAQ,OAAQ,QAAO,EAAE,OAAO,CAAC,GAAG,aAAa,OAAO;AAG7E,YAAM,cAAc,OAAO;AAC3B,YAAM,MAAM,OAAO,MAAM,WAAW;AACpC,YAAM,KAAQ,cAAS,UAAU,GAAG;AACpC,UAAI;AACF,QAAG,cAAS,IAAI,KAAK,GAAG,aAAa,MAAM;AAAA,MAC7C,UAAE;AACA,QAAG,eAAU,EAAE;AAAA,MACjB;AAEA,YAAM,QAAQ,IAAI,SAAS,OAAO;AAIlC,YAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,YAAM,gBAAgB,MAAM,MAAM,GAAG,EAAE;AACvC,YAAM,iBAAiB,MAAM,YAAY,IAAI;AAC7C,YAAM,gBAAgB,kBAAkB,IAAI,iBAAiB,IAAI;AACjE,YAAM,cAAc,SAAS;AAE7B,YAAM,WAAW,cAAc,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC;AAChE,aAAO,EAAE,OAAO,UAAU,YAAY;AAAA,IACxC,SAAS,KAAK;AACZ,cAAQ,KAAK,8BAA8B,QAAQ,KAAM,IAAc,OAAO,EAAE;AAChF,aAAO,EAAE,OAAO,CAAC,GAAG,aAAa,OAAO;AAAA,IAC1C;AAAA,EACF;AAAA,EAEQ,YAAY,OAA4B;AAC9C,UAAM,SAAoB,CAAC;AAC3B,eAAW,QAAQ,OAAO;AACxB,UAAI;AACF,eAAO,KAAK,KAAK,MAAM,IAAI,CAAC;AAAA,MAC9B,QAAQ;AACN,gBAAQ,KAAK,gDAAgD,KAAK,MAAM,GAAG,EAAE,CAAC,EAAE;AAAA,MAElF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAIQ,cAAsB;AAC5B,QAAI;AACF,YAAM,MAAS,kBAAa,KAAK,gBAAgB,OAAO;AACxD,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,aAAO,OAAO,OAAO,aAAa,WAAW,OAAO,WAAW;AAAA,IACjE,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,eAAe,UAAwB;AAC7C,QAAI;AACF,YAAM,MAAW,cAAQ,KAAK,cAAc;AAC5C,MAAG,eAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AACrC,YAAM,MAAM,KAAK,iBAAiB;AAClC,MAAG,mBAAc,KAAK,KAAK,UAAU,EAAE,SAAS,CAAC,GAAG,EAAE,UAAU,SAAS,MAAM,IAAM,CAAC;AACtF,MAAG,gBAAW,KAAK,KAAK,cAAc;AAAA,IACxC,SAAS,KAAK;AACZ,cAAQ,MAAM,4CAA6C,IAAc,OAAO;AAAA,IAClF;AAAA,EACF;AAAA;AAAA,EAIQ,mBAAyB;AAC/B,UAAM,MAAM,KAAK,aAAa,QAAQ,KAAK,gBAAgB;AAC3D,QAAI,MAAM,KAAK,OAAO,KAAK,aAAa,SAAS,GAAG;AAClD,WAAK,mBAAmB,KAAK,aAAa,KAAK,aAAa,SAAS,CAAC;AAAA,IACxE,OAAO;AACL,WAAK,mBAAmB,KAAK,aAAa,MAAM,CAAC;AAAA,IACnD;AAAA,EACF;AACF;;;AXtPA,eAAsB,kBAAkB,MAAyD;AAC/F,QAAM,OAAU,aAAQ;AACxB,QAAM,UAAU,MAAM,WAAgB,YAAK,MAAM,YAAY,YAAY;AACzE,QAAM,UAAU,MAAM,WAAgB,YAAK,MAAM,UAAU;AAC3D,QAAM,OAAO,MAAM,QAAQ;AAC3B,QAAM,OAAO,MAAM,QAAQ;AAC3B,QAAM,UAAU,wBAAwB,IAAI;AAC5C,QAAM,kBAAkB,MAAM,mBAAmB;AACjD,QAAM,aAAa,MAAM,cAAc;AAGvC,QAAM,gBAAgB,IAAI,cAAc;AAAA,IACtC;AAAA,IACA;AAAA,IACA,uBAAuB,MAAM,yBAAyB;AAAA,EACxD,CAAC;AACD,QAAM,cAAc,MAAM;AAG1B,QAAM,WAAW,IAAI,SAAS;AAK9B,QAAM,eAAe,IAAI,mBAAmB,EAAE,UAAe,YAAK,SAAS,OAAO,EAAE,CAAC;AACrF,WAAS,UAAU,KAAK,aAAa,MAAM;AAG3C,QAAM,aAAa,IAAI,gBAAgB,EAAE,SAAS,CAAC;AAQnD,QAAM,EAAE,iBAAAC,iBAAgB,IAAI,MAAM,OAAO,iCAAwB;AACjE,QAAM,EAAE,aAAAC,aAAY,IAAI,MAAM,OAAO,6BAAoB;AACzD,QAAM,kBAAkB,IAAID,iBAAgB;AAC5C,QAAM,cAAc,IAAIC,aAAY,eAAe;AAEnD,EAAC,WAAmB,2BAA2B;AAC/C,EAAC,WAAmB,uBAAuB;AAK3C,MAAI;AACF,UAAM,EAAE,qBAAqB,IAAI,MAAM,OAAO,8BAA8B;AAC5E,UAAM,OAAO,MAAM,qBAAqB,eAAe;AACvD,QAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,cAAQ;AAAA,QACN;AAAA,QACA,KAAK,WAAW,IAAI,CAAC,MAAM,GAAG,EAAE,IAAI,IAAI,EAAE,MAAM,GAAG,EAAE,KAAK,IAAI;AAAA,MAChE;AAAA,IACF;AACA,QAAI,KAAK,QAAQ,SAAS,GAAG;AAC3B,YAAM,eAAe,KAAK,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,eAAe,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAC/F,UAAI,aAAa,SAAS,GAAG;AAC3B,gBAAQ,IAAI,oDAAoD,aAAa,KAAK,IAAI,CAAC;AAAA,MACzF;AACA,YAAM,SAAS,KAAK,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,mBAAmB,EAAE,WAAW,oBAAoB;AAC3G,iBAAW,KAAK,QAAQ;AACtB,gBAAQ,KAAK,mCAAmC,EAAE,IAAI,MAAM,EAAE,MAAM,EAAE;AAAA,MACxE;AAAA,IACF;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ,KAAK,gDAAgD,GAAG;AAAA,EAClE;AAIA,QAAM,cAAmB,YAAK,SAAS,mBAAmB;AAC1D,MAAI;AACJ,MAAI;AACF,IAAG,eAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AACzC,QAAO,gBAAW,WAAW,GAAG;AAC9B,YAAM,cAAc,KAAK,MAAS,kBAAa,aAAa,OAAO,CAAC;AACpE,qBAAe;AAAA,QACb,WAAW,OAAO,KAAK,YAAY,WAAW,QAAQ;AAAA,QACtD,YAAY,OAAO,KAAK,YAAY,YAAY,QAAQ;AAAA,MAC1D;AACA,cAAQ,IAAI,6CAA6C;AAAA,IAC3D,OAAO;AACL,qBAAe,gBAAgB;AAC/B,YAAM,aAAa,iBAAiB,YAAY;AAChD,MAAG,mBAAc,aAAa,KAAK,UAAU,YAAY,MAAM,CAAC,GAAG;AAAA,QACjE,UAAU;AAAA,QACV,MAAM;AAAA,MACR,CAAC;AACD,cAAQ,IAAI,2CAA2C;AAAA,IACzD;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ,KAAK,wDAAwD,GAAG;AAAA,EAC1E;AAGA,MAAI;AACJ,MAAI,mBAAmB,MAAM,UAAU,MAAM,YAAY,MAAM,UAAU,MAAM,cAAc;AAC3F,YAAQ,IAAI,kDAAkD;AAE9D,QAAI,cAAc;AAChB,yBAAmB,IAAI,iBAAiB;AAAA,QACtC,QAAQ,KAAK;AAAA,QACb,UAAU,KAAK;AAAA,QACf,QAAQ,KAAK;AAAA,QACb,cAAc,KAAK;AAAA,QACnB;AAAA,QACA;AAAA,QACA,SAAS;AAAA,QACT;AAAA,MACF,CAAC;AAOD,MAAC,WAAmB,qBAAqB;AAGzC,uBAAiB,GAAG,aAAa,CAAC,SAAS;AACzC,gBAAQ,IAAI,uCAAuC,IAAI;AAAA,MACzD,CAAC;AAED,uBAAiB,GAAG,gBAAgB,CAAC,SAAS;AAC5C,gBAAQ,IAAI,0CAA0C,IAAI;AAAA,MAC5D,CAAC;AAED,uBAAiB,GAAG,YAAY,CAAC,SAAS;AACxC,gBAAQ,IAAI,sCAAsC,IAAI;AAAA,MACxD,CAAC;AAED,uBAAiB,GAAG,SAAS,CAAC,QAAQ;AACpC,gBAAQ,MAAM,mCAAmC,GAAG;AAAA,MACtD,CAAC;AAED,uBAAiB,GAAG,WAAW,OAAO,YAAY;AAChD,gBAAQ,IAAI,2CAA2C,OAAO;AAC9D,iBAAS,QAAQ,kBAAkB,OAAO;AAM1C,YAAI;AACJ,YAAI;AACF,gBAAM,UAAW,QAAQ,WAAY,QAAQ,QAAgB;AAC7D,kBAAQ,QAAQ,MAAM;AAAA,YACpB,KAAK,iBAAiB;AACpB,kBAAI,CAAC,SAAS;AACZ,yBAAS,EAAE,IAAI,OAAO,OAAO,iDAAiD;AAC9E;AAAA,cACF;AAIA,kBAAI;AACJ,kBAAI;AACF,wBAAQ,sBAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,iBAAiB,OAAO;AAAA,cACxE,SAAS,KAAK;AAEZ,wBAAQ,KAAK,yDAA0D,IAAc,OAAO;AAAA,cAC9F;AACA,kBAAI,CAAC,OAAO;AACV,yBAAS;AAAA,kBACP,IAAI;AAAA,kBACJ,OAAO,oCAAoC,OAAO;AAAA,gBACpD;AACA;AAAA,cACF;AAGA,oBAAM,cAAc,MAAM,WAAW,MAAM;AAC3C,oBAAM,UAAU,gBAAgB,IAAI,WAAW;AAC/C,kBAAI,CAAC,SAAS;AACZ,yBAAS;AAAA,kBACP,IAAI;AAAA,kBACJ,OAAO,2BAA2B,WAAW;AAAA,kBAC7C;AAAA,kBACA,SAAS;AAAA,gBACX;AACA;AAAA,cACF;AACA,kBAAI,OAAO,QAAQ,UAAU,YAAY;AAIvC,yBAAS;AAAA,kBACP,IAAI;AAAA,kBACJ,OAAO;AAAA,kBACP;AAAA,kBACA,SAAS;AAAA,gBACX;AACA;AAAA,cACF;AACA,oBAAM,cAAc,MAAM,QAAQ,MAAM,MAAM,IAAI;AAClD,uBAAS;AAAA,gBACP,GAAG;AAAA,gBACH,IAAI,YAAY;AAAA,gBAChB;AAAA,gBACA,SAAS;AAAA,cACX;AACA;AAAA,YACF;AAAA;AAAA,YAEA;AACE,sBAAQ,KAAK,iDAAiD,QAAQ,IAAI;AAC1E,uBAAS,EAAE,IAAI,OAAO,OAAO,6BAA6B,QAAQ,IAAI,GAAG;AAAA,UAC7E;AAAA,QACF,SAAS,KAAK;AACZ,kBAAQ,MAAM,kDAAkD,GAAG;AACnE,mBAAS,EAAE,IAAI,OAAO,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE;AAAA,QAChF;AAGA,YAAI;AACF,gBAAM,KAAK;AAGX,aAAG,cAAc,EAAE,MAAM,kBAAkB,WAAW,QAAQ,IAAI,OAAO,CAAC;AAAA,QAC5E,SAAS,QAAQ;AACf,kBAAQ,KAAK,gDAAgD,MAAM;AAAA,QACrE;AAAA,MACF,CAAC;AAMD,UAAI;AACF,cAAM,EAAE,4BAA4B,IAAI,MAAM,OAAO,6BAAoB;AACzE,cAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,mCAA0B;AACpE,cAAM,mBACJ,MAAM,UAAU,MAAM,eAClB,IAAI,iBAAiB,EAAE,QAAQ,KAAK,QAAQ,cAAc,KAAK,aAAa,CAAC,IAC7E;AACN,oCAA4B,kBAAyB;AAAA,UACnD,KAAK;AAAA,UACL,UAAU;AAAA,UACV,GAAI,mBAAmB,EAAE,iBAAiB,IAAI,CAAC;AAAA,QACjD,CAAC;AACD,gBAAQ;AAAA,UACN,mFACE,mBAAmB,yBAAyB,EAC9C;AAAA,QACF;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,KAAK,4DAA4D,GAAG;AAAA,MAC9E;AAaA,WAAK,iBAAiB,MAAM,EAAE,KAAK,YAAY;AAC7C,YAAI,YAAY;AACd,kBAAQ,IAAI,iDAAiD;AAC7D,gBAAM,iBAAkB,aAAa;AAAA,QACvC;AAAA,MACF,CAAC,EAAE,MAAM,CAAC,QAAQ;AAChB,gBAAQ,MAAM,kDAAkD,GAAG;AAAA,MACrE,CAAC;AAGD,oBAAc,WAAW;AAAA,QACvB,MAAM;AAAA,QACN,SAAS,YAAY;AACnB,cAAI,kBAAkB;AACpB,kBAAM,iBAAiB,KAAK;AAAA,UAC9B;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,WAAW,iBAAiB;AAC1B,YAAQ,IAAI,4FAA4F;AAAA,EAC1G;AAOA,MAAI,MAAM,UAAU,MAAM,YAAY,MAAM,cAAc;AACxD,UAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,+BAA6B;AACzE,UAAM,gBAAgB,mBAAmB;AAAA,MACvC,QAAQ,KAAK;AAAA,MACb,UAAU,KAAK;AAAA,MACf,cAAc,KAAK;AAAA,IACrB,CAAC;AACD,kBAAc,WAAW;AAAA,MACvB,MAAM;AAAA,MACN,SAAS,YAAY,cAAc,KAAK;AAAA,IAC1C,CAAC;AACD,YAAQ,IAAI,sDAAsD;AAAA,EACpE,OAAO;AACL,YAAQ,IAAI,+EAA+E;AAAA,EAC7F;AAUA,QAAM,wBACJ,MAAM,eAAe,SACV,mBAAW,QAAQ,EAAE,OAAO,KAAK,UAAU,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE,IAC7E;AACN,QAAM,eAAe,MAAM,eAAe,SACtC,CAAC,UAA4D;AAC3D,QAAI,UAAU,KAAK,WAAY,QAAO;AACtC,UAAM,iBAAiB,KAAK,UAAU,UAAU,yBAAyB,MAAM;AAC/E,WAAO,EAAE,SAAS,eAAe;AAAA,EACnC,IACA;AAIJ,QAAM,mBAAwB,eAAQ,MAAM,aAAa,QAAQ,IAAI,CAAC;AACtE,QAAM,oBAAoB,CAAC,QAAwE;AACjG,UAAM,qBAA0B,eAAQ,IAAI,aAAa,gBAAgB;AACzE,UAAM,YAAY,uBAAuB,oBAAoB,mBAAmB,WAAW,mBAAwB,UAAG,IAClH,qBACA;AACJ,WAAO;AAAA,MACL,SAAS,IAAI;AAAA,MACb;AAAA,MACA,MAAM;AAAA,MACN,OAAO,CAAC;AAAA,IACV;AAAA,EACF;AAKA,MAAI,kBAAkB;AACpB,UAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,uBAAmB;AAClE,0BAAsB,kBAAkB,EAAE,kBAAkB,CAAC;AAAA,EAC/D;AAGA,QAAM,aAAa,IAAI,iBAAiB;AAAA,IACtC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,gBAAgB,IAAI,iBAAiB,EAAE,SAAS,MAAM,GAAG;AAAA,IAC7D,UAAe,YAAK,SAAS,aAAa;AAAA,EAC5C,CAAC;AACD,gBAAc,eAAe,UAAU;AAEvC,QAAM,aAAa,IAAI,WAAW;AAAA,IAChC;AAAA,IACA;AAAA,IACA,UAAU,MAAM;AAAA,EAClB,CAAC;AACD,aAAW,eAAe,UAAU;AAEpC,QAAM,mBAAmB,IAAI,4BAA4B;AAAA,IACvD;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA,IAGA,aAAa,MAAM;AAAA,IACnB,cAAc,MAAM;AAAA,EACtB,CAAC;AACD,aAAW,CAAC,KAAK,OAAO,KAAK,iBAAiB,UAAU,GAAG;AACzD,UAAMC,OAAM,IAAI,QAAQ,GAAG;AAC3B,QAAIA,OAAM,EAAG;AACb,UAAM,SAAS,IAAI,MAAM,GAAGA,IAAG;AAC/B,UAAM,YAAY,IAAI,MAAMA,OAAM,CAAC;AACnC,eAAW,cAAc,QAAQ,WAAW,OAAO;AAAA,EACrD;AAKA,MAAI;AACJ,MAAI,MAAM,UAAU,MAAM,cAAc;AACtC,mBAAe,IAAI,aAAa;AAAA,MAC9B,QAAQ,KAAK;AAAA,MACb,cAAc,KAAK;AAAA,IACrB,CAAC;AACD,iBAAa,MAAM;AACnB,kBAAc,WAAW;AAAA,MACvB,MAAM;AAAA,MACN,SAAS,YAAY,cAAc,KAAK;AAAA,IAC1C,CAAC;AAAA,EACH,OAAO;AACL,YAAQ,IAAI,0EAA0E;AAAA,EACxF;AAEA,QAAM,gBAAgB,oBAAI,IAAwD;AAClF,aAAW,cAAc,QAAQ,eAAe,CAAC,MAAM,KAAK,QAAQ;AAClE,QAAI,SAAS;AACb,QAAI;AACF,UAAI,IAAI,KAAK,SAAS,GAAG;AACvB,cAAM,SAAS,KAAK,MAAM,IAAI,KAAK,SAAS,MAAM,CAAC;AACnD,YAAI,OAAO,OAAO,WAAW,YAAY,OAAO,SAAS,GAAG;AAC1D,mBAAS,KAAK,IAAI,OAAO,QAAQ,KAAK,EAAE;AAAA,QAC1C;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AACA,UAAM,QAAQ,kBAAkB;AAChC,UAAM,YAAY,KAAK,IAAI,IAAI,SAAS;AACxC,kBAAc,IAAI,OAAO,EAAE,UAAU,CAAC;AACtC,UAAM,eAAe,eACjB,iBAAiB,YAAY,EAAE,YAC/B;AACJ,UAAM,UAAU,KAAK,UAAU;AAAA,MAC7B;AAAA,MACA,KAAK,wBAAwB,mBAAmB,KAAK,CAAC;AAAA,MACtD;AAAA,MACA,UAAU,MAAM;AAAA,MAChB;AAAA,MACA,UAAU,MAAM,SAAS,iBAAiB,MAAM,YAAY,IAAI;AAAA,MAChE;AAAA,MACA,SAAS,kBAAkB,UAAU;AAAA,IACvC,CAAC;AACD,QAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,OAAO,EAAE,CAAC;AACvG,QAAI,IAAI,OAAO;AAAA,EACjB,CAAC;AAID,aAAW,cAAc,OAAO,aAAa,CAAC,MAAM,QAAQ;AAC1D,UAAM,OAAO,gBAAgB,KAAK;AAClC,UAAM,UAAU,KAAK,UAAU,EAAE,IAAI,MAAM,UAAU,KAAK,CAAC;AAC3D,QAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,OAAO,EAAE,CAAC;AACvG,QAAI,IAAI,OAAO;AAAA,EACjB,CAAC;AASD,aAAW,cAAc,QAAQ,6BAA6B,OAAO,MAAM,KAAK,QAAQ;AACtF,QAAI;AACJ,QAAI;AACF,aAAO,IAAI,KAAK,SAAS,IAAI,KAAK,MAAM,IAAI,KAAK,SAAS,MAAM,CAAC,IAAI,CAAC;AAAA,IACxE,QAAQ;AACN,YAAM,MAAM,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,eAAe,CAAC;AAC/D,UAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,GAAG,EAAE,CAAC;AACnG,UAAI,IAAI,GAAG;AACX;AAAA,IACF;AACA,QAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,YAAM,MAAM,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,yBAAyB,CAAC;AACzE,UAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,GAAG,EAAE,CAAC;AACnG,UAAI,IAAI,GAAG;AACX;AAAA,IACF;AACA,QAAI,OAAO,KAAK,SAAS,YAAY,KAAK,KAAK,WAAW,GAAG;AAC3D,YAAM,MAAM,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,yBAAyB,CAAC;AACzE,UAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,GAAG,EAAE,CAAC;AACnG,UAAI,IAAI,GAAG;AACX;AAAA,IACF;AACA,QAAI,OAAO,KAAK,gBAAgB,YAAY,KAAK,YAAY,WAAW,GAAG;AACzE,YAAM,MAAM,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,gCAAgC,CAAC;AAChF,UAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,GAAG,EAAE,CAAC;AACnG,UAAI,IAAI,GAAG;AACX;AAAA,IACF;AAEA,UAAM,EAAE,UAAAC,UAAS,IAAI,MAAM,OAAO,yBAAuB;AACzD,UAAM,eAAeA,UAAS,KAAK,IAAI;AACvC,QAAI,CAAC,cAAc;AACjB,YAAM,MAAM,KAAK,UAAU;AAAA,QACzB,IAAI;AAAA,QACJ,OAAO,mBAAmB,KAAK,IAAI;AAAA,MACrC,CAAC;AACD,UAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,GAAG,EAAE,CAAC;AACnG,UAAI,IAAI,GAAG;AACX;AAAA,IACF;AACA,QAAI;AACJ,QAAI;AACF,YAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,uBAAuB;AAClE,qBAAe,kBAAkB;AAAA,QAC/B,MAAM,KAAK;AAAA,QACX,aAAa,KAAK;AAAA,QAClB,gBAAgB,aAAa;AAAA,QAC7B,gBAAgB,aAAa;AAAA,MAC/B,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,UAAU,KAAK,UAAU;AAAA,QAC7B,IAAI;AAAA,QACJ,OAAO,oBAAqB,IAAc,OAAO;AAAA,MACnD,CAAC;AACD,UAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,OAAO,EAAE,CAAC;AACvG,UAAI,IAAI,OAAO;AACf;AAAA,IACF;AACA,UAAM,WAAW,gBAAgB,IAAI,KAAK,IAAI;AAC9C,QAAI;AACF,sBAAgB,SAAS,YAAY;AAAA,IACvC,SAAS,KAAK;AACZ,YAAM,UAAU,KAAK,UAAU;AAAA,QAC7B,IAAI;AAAA,QACJ,OAAO,mBAAoB,IAAc,OAAO;AAAA,MAClD,CAAC;AACD,UAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,OAAO,EAAE,CAAC;AACvG,UAAI,IAAI,OAAO;AACf;AAAA,IACF;AACA,YAAQ;AAAA,MACN,6CAA6C,KAAK,IAAI,WAAM,KAAK,WAAW,MAC3E,WAAW,kCAAkC;AAAA,IAChD;AACA,UAAM,KAAK,KAAK,UAAU,EAAE,IAAI,MAAM,SAAS,CAAC;AAChD,QAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,EAAE,EAAE,CAAC;AAClG,QAAI,IAAI,EAAE;AAAA,EACZ,CAAC;AAED,aAAW,cAAc,QAAQ,sBAAsB,OAAO,MAAM,KAAK,QAAQ;AAC/E,QAAI;AACJ,QAAI;AACF,aAAO,IAAI,KAAK,SAAS,IAAI,KAAK,MAAM,IAAI,KAAK,SAAS,MAAM,CAAC,IAAI,CAAC;AAAA,IACxE,QAAQ;AACN,YAAM,MAAM,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,eAAe,CAAC;AAC/D,UAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,GAAG,EAAE,CAAC;AACnG,UAAI,IAAI,GAAG;AACX;AAAA,IACF;AACA,QAAI,OAAO,KAAK,WAAW,YAAY,OAAO,KAAK,eAAe,YAAY,OAAO,KAAK,WAAW,UAAU;AAC7G,YAAM,MAAM,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,sCAAsC,CAAC;AACtF,UAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,GAAG,EAAE,CAAC;AACnG,UAAI,IAAI,GAAG;AACX;AAAA,IACF;AACA,UAAM,SAAS,MAAM,YAAY,SAAS;AAAA,MACxC,QAAQ,KAAK;AAAA,MACb,SAAS,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;AAAA,MAC3D,YAAY,KAAK;AAAA,MACjB,QAAQ,KAAK;AAAA,MACb,UAAU,KAAK;AAAA,MACf,eAAe,OAAO,KAAK,kBAAkB,WAAW,KAAK,gBAAgB;AAAA,MAC7E,YAAY,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;AAAA,IACtE,CAAC;AACD,UAAM,SAAS,OAAO,KAAK,MAAM;AACjC,UAAM,UAAU,KAAK,UAAU,EAAE,IAAI,OAAO,IAAI,OAAO,CAAC;AACxD,QAAI,UAAU,QAAQ,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,OAAO,EAAE,CAAC;AAC1G,QAAI,IAAI,OAAO;AAAA,EACjB,CAAC;AAED,aAAW,cAAc,OAAO,gBAAgB,CAAC,KAAK,QAAQ;AAC5D,UAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB;AACtD,UAAM,QAAQ,IAAI,aAAa,IAAI,OAAO,KAAK;AAC/C,UAAM,SAAS,cAAc,IAAI,KAAK;AACtC,UAAM,SAAS;AACf,QAAI,UAAU,OAAO,aAAa,KAAK,IAAI,GAAG;AAC5C,oBAAc,OAAO,KAAK;AAAA,IAC5B;AACA,UAAM,UAAU,KAAK,UAAU;AAAA,MAC7B;AAAA,MACA,WAAW,QAAQ;AAAA,IACrB,CAAC;AACD,QAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,kBAAkB,OAAO,WAAW,OAAO,EAAE,CAAC;AACvG,QAAI,IAAI,OAAO;AAAA,EACjB,CAAC;AAED,QAAM,WAAgB,YAAK,SAAS,aAAa;AAEjD,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,UAAM,QAAQ,MAAM,WAAW,MAAM;AACrC,gBAAY,UAAU,MAAM,IAAI,IAAI,MAAM,IAAI;AAC9C,gBAAY,MAAM;AAAA,EACpB,SAAS,KAAK;AAEZ,UAAM,cAAc,SAAS,QAAQ;AACrC,UAAM;AAAA,EACR;AAIA,MAAI;AACF,IAAG,eAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AACzC,UAAM,MAAM,WAAW;AACvB,IAAG,mBAAc,KAAK,OAAO,SAAS,IAAI,MAAM,EAAE,UAAU,SAAS,MAAM,IAAM,CAAC;AAClF,IAAG,gBAAW,KAAK,QAAQ;AAAA,EAC7B,SAAS,KAAK;AAGZ,YAAQ,KAAK,kCAAkC,QAAQ,KAAK,GAAG;AAAA,EACjE;AAIA,gBAAc,WAAW;AAAA,IACvB,MAAM;AAAA,IACN,SAAS,YAAY;AACnB,oBAAc,SAAS;AACvB,YAAM,WAAW,KAAK,GAAI;AAAA,IAC5B;AAAA,EACF,CAAC;AAED,gBAAc,WAAW;AAAA,IACvB,MAAM;AAAA,IACN,SAAS,YAAY;AACnB,YAAM,WAAW,SAAS;AAAA,IAC5B;AAAA,EACF,CAAC;AAED,gBAAc,WAAW;AAAA,IACvB,MAAM;AAAA,IACN,SAAS,YAAY;AACnB,mBAAa,SAAS;AAAA,IACxB;AAAA,EACF,CAAC;AAGD,gBAAc,WAAW;AAAA,IACvB,MAAM;AAAA,IACN,SAAS,YAAY;AACnB,UAAI;AAAE,QAAG,YAAO,UAAU,EAAE,OAAO,KAAK,CAAC;AAAA,MAAG,QAAQ;AAAA,MAAe;AAAA,IACrE;AAAA,EACF,CAAC;AAGD,QAAM,SAA6B;AAAA,IACjC,IAAI,MAAM;AAAE,aAAO;AAAA,IAAW;AAAA,IAC9B,IAAI,MAAM;AAAE,aAAO,QAAQ;AAAA,IAAK;AAAA,IAChC,IAAI,UAAU;AAAE,aAAO;AAAA,IAAS;AAAA,IAChC,MAAM,OAAO;AACX,YAAM,cAAc,SAAS,QAAQ;AAAA,IACvC;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,oBAA4B;AACnC,SAAc,oBAAY,EAAE,EAAE,SAAS,WAAW;AACpD;AAEA,SAAS,kBAAkB,YAAkD;AAC3E,QAAM,MAAM,WAAW;AACvB,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,OAAO,OAAO,IAAI,IAAI,GAAG,EAAE,IAAI;AACrC,SAAO,OAAO,SAAS,IAAI,KAAK,OAAO,IAAI,OAAO;AACpD;AAEA,SAAS,wBAAwB,MAAkC;AACjE,MAAI,SAAS,aAAa,SAAS,MAAM;AACvC,WAAOC,aAAY;AAAA,EACrB;AACA,MAAI,SAAS,eAAe,SAAS,SAAS,KAAK,WAAW,MAAM,KAAK,KAAK,WAAW,UAAU,GAAG;AACpG,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAASA,eAAkC;AACzC,QAAM,OAAU,uBAAkB;AAClC,aAAW,WAAW,OAAO,OAAO,IAAI,GAAG;AACzC,eAAW,SAAS,WAAW,CAAC,GAAG;AACjC,UAAI,MAAM,WAAW,UAAU,MAAM,SAAU;AAC/C,UAAI,MAAM,QAAQ,WAAW,MAAM,KAAK,MAAM,QAAQ,WAAW,UAAU,EAAG;AAC9E,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AACA,SAAO;AACT;;;AYruBA,YAAYC,UAAQ;AACpB,YAAYC,YAAU;AAMtB,OAAO,SAAS;;;ACHhB,IAAM,uBAAuB,CAAC,SAAS,iBAAiB,MAAM;AAC9D,IAAM,kBAAkB,CAAC,QAAQ;AAE1B,SAAS,iBAAiB,MAAc,QAAQ,QAAc;AACnE,MAAI,CAAC,QAAQ,IAAI,4BAA4B,EAAG;AAChD,aAAW,OAAO,sBAAsB;AACtC,QAAI,KAAK,SAAS,GAAG,GAAG;AACtB,YAAM,IAAI,MAAM,sCAAsC,GAAG,YAAY,KAAK,KAAK,IAAI,EAAE;AAAA,IACvF;AAAA,EACF;AACA,aAAW,QAAQ,iBAAiB;AAClC,UAAM,KAAK,IAAI,OAAO,MAAM,IAAI,KAAK;AACrC,QAAI,GAAG,KAAK,IAAI,GAAG;AACjB,YAAM,IAAI,MAAM,iCAAiC,IAAI,YAAY,KAAK,KAAK,IAAI,EAAE;AAAA,IACnF;AAAA,EACF;AACA,QAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,aAAW,QAAQ,OAAO;AACxB,UAAM,WAAW,KAAK,QAAQ,YAAY,EAAE,EAAE,QAAQ,YAAY,EAAE;AACpE,QAAI,SAAS,QAAQ,EAAE,SAAS,GAAG,GAAG;AACpC,YAAM,IAAI,MAAM,qCAAqC,KAAK,KAAK,IAAI,EAAE;AAAA,IACvE;AAAA,EACF;AACF;;;ADsBA,IAAM,iBAAiB,CAAC,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,QAAG;AACxE,IAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AACF;AAEA,SAAS,aAAa,OAAwB,OAAsB;AAClE,QAAM,OAAO,SAAS,QAAQ,SAAS;AACvC,QAAM,aAAa;AAAA,IACZ,eAAQ,WAAW,MAAM,IAAI,EAAE;AAAA;AAAA,IAC/B,eAAQ,WAAW,SAAS,IAAI,EAAE;AAAA;AAAA,IAClC,eAAQ,WAAW,YAAY,IAAI,EAAE;AAAA;AAAA,IACrC,eAAQ,QAAQ,IAAI,GAAG,MAAM,IAAI,EAAE;AAAA,EAC1C;AAEA,aAAW,aAAa,YAAY;AAClC,QAAO,gBAAW,SAAS,EAAG,QAAO;AAAA,EACvC;AACA,SAAO;AACT;AAWO,IAAM,KAAN,MAAS;AAAA,EACL;AAAA,EACA;AAAA,EACQ;AAAA,EACA;AAAA,EAEjB,YAAY,MAAkB;AAC5B,SAAK,OAAO,MAAM,QAAQ;AAC1B,SAAK,SAAS,MAAM,UAAU,QAAQ;AACtC,SAAK,YAAY,MAAM,aAAa,QAAQ;AAE5C,QAAI,MAAM,UAAU,QAAW;AAC7B,WAAK,eAAe,KAAK;AAAA,IAC3B,OAAO;AACL,YAAM,QAAS,KAAK,OAA8B,UAAU;AAC5D,YAAM,UAAU,QAAQ,QAAQ,IAAI,UAAU,CAAC;AAC/C,WAAK,eAAe,SAAS,CAAC;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,KAAK,MAAc,OAAe,MAAsB;AAC9D,QAAI,CAAC,KAAK,aAAc,QAAO;AAC/B,WAAO,QAAU,IAAI,IAAI,IAAI,QAAU,KAAK;AAAA,EAC9C;AAAA,EAEQ,MAAM,GAAmB;AAAE,WAAO,KAAK,KAAK,IAAI,IAAI,CAAC;AAAA,EAAG;AAAA,EACxD,IAAI,GAAmB;AAAE,WAAO,KAAK,KAAK,IAAI,IAAI,CAAC;AAAA,EAAG;AAAA,EACtD,OAAO,GAAmB;AAAE,WAAO,KAAK,KAAK,IAAI,IAAI,CAAC;AAAA,EAAG;AAAA,EACzD,KAAK,GAAmB;AAAE,WAAO,KAAK,KAAK,IAAI,IAAI,CAAC;AAAA,EAAG;AAAA,EACvD,IAAI,GAAmB;AAAE,WAAO,KAAK,KAAK,GAAG,IAAI,CAAC;AAAA,EAAG;AAAA,EACrD,KAAK,GAAmB;AAAE,WAAO,KAAK,KAAK,GAAG,IAAI,CAAC;AAAA,EAAG;AAAA,EACtD,KAAK,GAAmB;AAAE,WAAO,KAAK,KAAK,IAAI,IAAI,CAAC;AAAA,EAAG;AAAA,EACvD,YAAoB;AAAE,WAAO,KAAK,KAAK,QAAG;AAAA,EAAG;AAAA,EAE7C,eAAe,MAAsB;AAC3C,QAAI,MAAM;AACV,eAAW,MAAM,MAAM;AACrB,UAAI,OAAO,UAAK;AACd,eAAO,KAAK,KAAK,EAAE;AAAA,MACrB,WAAW,OAAO,UAAK;AACrB,eAAO,KAAK,IAAI,EAAE;AAAA,MACpB,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,MAAM,MAAoB;AACxB,SAAK,OAAO,MAAM,IAAI;AAAA,EACxB;AAAA,EAEA,SAAS,MAAoB;AAC3B,SAAK,UAAU,MAAM,IAAI;AAAA,EAC3B;AAAA;AAAA,EAIA,OAAO,MAAoB;AACzB,QAAI,KAAK,SAAS,OAAQ;AAC1B,UAAM,SAAS,KAAK,WAAW,SAAS,IAAI,KAAK,UAAU,IAAI,MAAM;AACrE,SAAK,MAAM,SAAS,KAAK,KAAK,IAAI,IAAI,IAAI;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,UAAyB;AAGnC,QAAI,KAAK,SAAS,UAAU,KAAK,SAAS,QAAS;AACnD,UAAM,WAAW,aAAa,OAAO;AACrC,QAAI,aAAa,MAAM;AACrB,UAAI;AACF,cAAM,MAAS,kBAAa,UAAU,OAAO,EAAE,QAAQ,QAAQ,EAAE;AACjE,mBAAW,QAAQ,IAAI,MAAM,IAAI,GAAG;AAClC,eAAK,MAAM,KAAK,KAAK,IAAI,IAAI,IAAI;AAAA,QACnC;AAAA,MACF,QAAQ;AACN,aAAK,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,KAAK,SAAS,IAAI,IAAI;AAAA,MACjE;AAAA,IACF,OAAO;AACL,WAAK,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,KAAK,SAAS,IAAI,IAAI;AAAA,IACjE;AACA,QAAI,aAAa,UAAa,SAAS,SAAS,GAAG;AACjD,WAAK,MAAM,KAAK,IAAI,OAAO,QAAQ,IAAI,IAAI;AAAA,IAC7C;AACA,SAAK,MAAM;AAAA,EACb;AAAA,EAEA,OAAO,UAAmB,MAAiC;AAIzD,QAAI,KAAK,SAAS,UAAU,KAAK,SAAS,QAAS;AAEnD,UAAM,aAAa,QAAQ,IAAI,SAAS,MAAM,SAC1C,SAAS,QAAQ,IAAI,SAAS,GAAG,EAAE,IACnC;AACJ,UAAM,QAAS,KAAK,OAA8B,WAChD,QAAQ,OAAO,YACd,OAAO,SAAS,UAAU,IAAI,aAAa;AAC9C,UAAM,WAAW,aAAa,KAAK;AACnC,UAAM,gBAAgB,MAAM,SAAS,QAAQ,SAAS;AAEtD,QAAI,iBAAiB,aAAa,MAAM;AACtC,YAAM,MAAS,kBAAa,UAAU,OAAO;AAC7C,YAAM,QAAQ,IAAI,MAAM,IAAI;AAC5B,iBAAW,QAAQ,OAAO;AACxB,cAAM,cAAc,KAAK,QAAQ,qBAAqB,qBAAqB;AAC3E,cAAM,WAAW,YAAY,QAAQ;AACrC,YAAI,SAAS,WAAW,GAAG;AACzB,eAAK,MAAM,IAAI;AACf;AAAA,QACF;AACA,cAAM,UAAU,SAAS,UAAU,QAAQ,SAAS,MAAM,GAAG,KAAK,IAAI,QAAQ,GAAG,CAAC,CAAC,IAAI;AACvF,aAAK,MAAM,KAAK,eAAe,OAAO,IAAI,IAAI;AAAA,MAChD;AAAA,IACF,OAAO;AACL,WAAK,MAAM,KAAK,KAAK,eAAe,CAAC,CAAC,IAAI,IAAI;AAC9C,WAAK,MAAM,KAAK,IAAI,eAAe,CAAC,CAAC,IAAI,IAAI;AAAA,IAC/C;AAEA,QAAI,aAAa,UAAa,SAAS,SAAS,GAAG;AACjD,WAAK,MAAM,KAAK,IAAI,OAAO,QAAQ,IAAI,IAAI;AAAA,IAC7C;AACA,SAAK,MAAM;AAAA,EACb;AAAA;AAAA,EAIA,QAAc;AACZ,QAAI,KAAK,SAAS,OAAQ;AAC1B,SAAK,MAAM,IAAI;AAAA,EACjB;AAAA,EAEA,KAAK,MAAoB;AACvB,QAAI,KAAK,SAAS,OAAQ;AAC1B,SAAK,MAAM,OAAO,IAAI;AAAA,EACxB;AAAA,EAEA,KAAK,MAAoB;AACvB,SAAK,KAAK,IAAI;AAAA,EAChB;AAAA;AAAA,EAIA,UAAU,MAAc,SAAS,GAAS;AACxC,QAAI,KAAK,SAAS,OAAQ;AAC1B,SAAK,MAAM,IAAI,OAAO,MAAM,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI;AAAA,EACvD;AAAA;AAAA,EAIA,IAAI,MAAoB;AACtB,QAAI,KAAK,SAAS,OAAQ;AAC1B,SAAK,MAAM,KAAK,KAAK,MAAM,IAAI,MAAM,OAAO,IAAI;AAAA,EAClD;AAAA,EAEA,KAAK,MAAoB;AACvB,QAAI,KAAK,SAAS,OAAQ;AAC1B,SAAK,MAAM,KAAK,KAAK,OAAO,IAAI,MAAM,OAAO,IAAI;AAAA,EACnD;AAAA;AAAA,EAIA,GAAG,MAAc,QAAuB;AACtC,QAAI,KAAK,SAAS,OAAQ;AAC1B,UAAM,SAAS,SAAS,OAAO,KAAK,IAAI,MAAM,IAAI;AAClD,SAAK,MAAM,OAAO,KAAK,MAAM,QAAG,IAAI,MAAM,OAAO,SAAS,IAAI;AAAA,EAChE;AAAA,EAEA,QAAQ,MAAc,QAAuB;AAC3C,SAAK,GAAG,MAAM,MAAM;AAAA,EACtB;AAAA,EAEA,KAAK,MAAc,QAAuB;AACxC,QAAI,KAAK,SAAS,OAAQ;AAC1B,UAAM,SAAS,SAAS,OAAO,KAAK,IAAI,MAAM,IAAI;AAClD,SAAK,MAAM,OAAO,KAAK,IAAI,QAAG,IAAI,MAAM,OAAO,SAAS,IAAI;AAAA,EAC9D;AAAA,EAEA,OAAO,MAAoB;AACzB,QAAI,KAAK,SAAS,OAAQ;AAC1B,SAAK,MAAM,OAAO,KAAK,MAAM,QAAG,IAAI,MAAM,OAAO,IAAI;AAAA,EACvD;AAAA,EAEA,QAAQ,MAAoB;AAC1B,QAAI,KAAK,SAAS,OAAQ;AAC1B,SAAK,MAAM,OAAO,KAAK,KAAK,QAAG,IAAI,MAAM,OAAO,IAAI;AAAA,EACtD;AAAA,EAEA,aAAa,MAAoB;AAC/B,QAAI,KAAK,SAAS,OAAQ;AAC1B,SAAK,MAAM,OAAO,KAAK,IAAI,MAAG,IAAI,MAAM,KAAK,IAAI,IAAI,IAAI,IAAI;AAAA,EAC/D;AAAA,EAEA,QAAQ,MAAoB;AAC1B,QAAI,KAAK,SAAS,OAAQ;AAC1B,SAAK,MAAM,OAAO,KAAK,OAAO,QAAG,IAAI,MAAM,OAAO,IAAI;AAAA,EACxD;AAAA,EAEA,KAAK,MAAc,QAAuB;AACxC,QAAI,KAAK,SAAS,OAAQ;AAC1B,UAAM,SAAS,SAAS,OAAO,KAAK,IAAI,MAAM,IAAI;AAClD,SAAK,MAAM,OAAO,KAAK,OAAO,GAAG,IAAI,MAAM,OAAO,SAAS,IAAI;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,MAAc,OAAgB,KAAoB;AACtD,QAAI,KAAK,SAAS,OAAQ;AAC1B,SAAK,SAAS,KAAK,IAAI,QAAG,IAAI,MAAM,OAAO,IAAI;AAC/C,QAAI,UAAU,QAAW;AACvB,WAAK,SAAS,OAAO,KAAK,IAAI,QAAQ,IAAI,MAAM,KAAK,IAAI,KAAK,IAAI,IAAI;AAAA,IACxE;AACA,QAAI,QAAQ,QAAW;AACrB,WAAK,SAAS,OAAO,KAAK,KAAK,MAAM,IAAI,MAAM,MAAM,IAAI;AAAA,IAC3D;AAAA,EACF;AAAA,EAMA,MAAM,YAA6C,WAAgC;AACjF,QAAI,KAAK,SAAS,OAAQ;AAC1B,UAAM,OAAO,MAAM,QAAQ,UAAU,IAAI,aAAa,WAAW;AACjE,UAAM,OAAO,MAAM,QAAQ,UAAU,IACjC,YACA;AAAA,MACE,SAAS,WAAW;AAAA,MACpB,UAAU,WAAW;AAAA,IACvB;AAEJ,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAEA,UAAM,WAAW,KAAK,aAAa,QAAQ,OAAO,WAAW;AAC7D,UAAM,OAAO,KAAK;AAGlB,UAAM,SAAmB,KAAK,IAAI,CAAC,QAAQ,IAAI,MAAM;AACrD,eAAW,OAAO,MAAM;AACtB,WAAK,QAAQ,CAAC,KAAK,MAAM;AACvB,cAAM,MAAM,IAAI,GAAG,KAAK;AACxB,YAAI,IAAI,SAAS,OAAO,CAAC,EAAG,QAAO,CAAC,IAAI,IAAI;AAAA,MAC9C,CAAC;AAAA,IACH;AAEA,UAAM,aAAa,OAAO,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,KAAK,IAAI;AAE/E,QAAI,aAAa,UAAU;AAEzB,eAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,cAAM,MAAM,KAAK,CAAC;AAClB,mBAAW,OAAO,MAAM;AACtB,gBAAM,MAAM,IAAI,GAAG,KAAK;AACxB,eAAK,MAAM,OAAO,KAAK,KAAK,MAAM,GAAG,IAAI,MAAM,MAAM,IAAI;AAAA,QAC3D;AACA,YAAI,IAAI,KAAK,SAAS,EAAG,MAAK,MAAM,IAAI;AAAA,MAC1C;AACA;AAAA,IACF;AAGA,UAAM,SAAS,KAAK,IAAI,CAAC,KAAK,MAAM,IAAI,YAAY,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAClF,SAAK,MAAM,OAAO,KAAK,IAAI,MAAM,IAAI,IAAI;AAGzC,eAAW,OAAO,MAAM;AACtB,YAAM,OAAO,KAAK,IAAI,CAAC,KAAK,OAAO,IAAI,GAAG,KAAK,IAAI,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AAC/E,WAAK,MAAM,OAAO,OAAO,IAAI;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA,EAIA,QAAQ,MAAuE;AAC7E,QAAI,KAAK,SAAS,WAAW,KAAK,SAAS,QAAQ;AACjD,aAAO;AAAA,QACL,SAAe;AAAA,QAAc;AAAA,QAC7B,OAAa;AAAA,QAAc;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,QAAS,KAAK,OAA8B,UAAU;AAE5D,QAAI,CAAC,SAAS,CAAC,KAAK,cAAc;AAEhC,WAAK,MAAM,OAAO,KAAK,OAAO,QAAG,IAAI,MAAM,OAAO,IAAI;AACtD,aAAO;AAAA,QACL,QAAQ,CAAC,MAAc;AACrB,eAAK,MAAM,OAAO,KAAK,OAAO,QAAG,IAAI,MAAM,IAAI,IAAI;AAAA,QACrD;AAAA,QACA,MAAM,CAAC,UAAmB;AACxB,cAAI,MAAO,MAAK,MAAM,OAAO,KAAK,MAAM,QAAG,IAAI,MAAM,QAAQ,IAAI;AAAA,QACnE;AAAA,MACF;AAAA,IACF;AAGA,QAAI,UAAU;AACd,QAAI,WAAW;AACf,QAAI,UAAU;AAEd,UAAM,QAAQ,KAAK,MAAM,KAAK,IAAI;AAClC,UAAM,UAAU,KAAK,OAAO,KAAK,IAAI;AACrC,UAAM,UAAU,KAAK,MAAM,KAAK,IAAI;AAEpC,aAAS,cAAoB;AAC3B,YAAM,QAAQ,eAAe,WAAW,eAAe,MAAM;AAC7D,YAAM,OAAO,OAAO,QAAQ,KAAK,IAAI,MAAM;AAE3C,YAAM,OAAO,IAAI;AACjB;AAAA,IACF;AAEA,gBAAY;AACZ,UAAM,QAAQ,YAAY,aAAa,EAAE;AAEzC,WAAO;AAAA,MACL,OAAO,GAAiB;AACtB,YAAI,QAAS;AACb,kBAAU;AAAA,MACZ;AAAA,MACA,KAAK,OAAsB;AACzB,YAAI,QAAS;AACb,kBAAU;AACV,sBAAc,KAAK;AAEnB,cAAM,WAAW;AACjB,YAAI,MAAO,OAAM,OAAO,QAAQ,QAAG,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,SACE,MACA,OACgF;AAChF,QAAI,KAAK,SAAS,WAAW,KAAK,SAAS,QAAQ;AACjD,aAAO;AAAA,QACL,SAAe;AAAA,QAEf;AAAA,QACA,OAAa;AAAA,QAEb;AAAA,MACF;AAAA,IACF;AAEA,UAAM,QAAS,KAAK,OAA8B,UAAU;AAC5D,UAAM,QAAQ,KAAK,IAAI;AACvB,UAAM,QAAQ,KAAK,MAAM,KAAK,IAAI;AAClC,UAAM,UAAU,KAAK,KAAK,KAAK,IAAI;AACnC,UAAM,QAAQ,KAAK,IAAI,KAAK,IAAI;AAChC,UAAM,UAAU,KAAK,MAAM,KAAK,IAAI;AAEpC,QAAI,OAAO;AACX,QAAI,aAAa;AACjB,QAAI,UAAU;AAEd,UAAM,SAAS,MAAY;AACzB,UAAI,QAAS;AACb,YAAM,OAAO,QAAQ,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,OAAO,KAAK,CAAC,IAAI;AAClE,YAAM,MAAM,KAAK,MAAM,OAAO,GAAG;AACjC,YAAM,QAAQ;AACd,YAAM,SAAS,KAAK,MAAM,OAAO,KAAK;AACtC,YAAM,MAAM,SAAI,OAAO,MAAM,IAAI,SAAI,OAAO,QAAQ,MAAM;AAC1D,YAAM,WAAW,KAAK,IAAI,IAAI,SAAS;AACvC,YAAM,MAAM,OAAO,OAAO,KAAK,IAAI,GAAG,UAAU,OAAO,OAAO,IAAI;AAClE,YAAM,SAAS,QAAQ,IAAI,KAAK,SAAM,MAAM,IAAI,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG;AAC7E,YAAM,YAAY,aAAa,SAAM,UAAU,KAAK;AACpD,YAAM,OAAO,KAAK,IAAI,KAAK,QAAQ,GAAG,CAAC,KAAK,OAAO,GAAG,EAAE,SAAS,CAAC,CAAC,IAAI,SAAS,GAAG,MAAM,MAAM,CAAC;AAChG,UAAI,SAAS,KAAK,cAAc;AAC9B,cAAM,cAAc,IAAI;AAAA,MAC1B,OAAO;AACL,cAAM,OAAO,IAAI;AAAA,MACnB;AAAA,IACF;AAEA,WAAO;AAEP,WAAO;AAAA,MACL,QAAQ,CAAC,SAAiB,WAA0B;AAClD,YAAI,QAAS;AACb,eAAO;AACP,YAAI,WAAW,OAAW,cAAa;AACvC,eAAO;AAAA,MACT;AAAA,MACA,MAAM,CAAC,UAAyB;AAC9B,YAAI,QAAS;AACb,kBAAU;AACV,YAAI,SAAS,KAAK,aAAc,OAAM,WAAW;AACjD,YAAI,MAAO,OAAM,OAAO,QAAQ,QAAG,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,KAAK,SAAkB,MAAmC;AACxD,UAAM,SAAS,MAAM,SAAS,IAAI;AAClC,SAAK,MAAM,KAAK,UAAU,SAAS,MAAM,MAAM,IAAI,IAAI;AAAA,EACzD;AAAA;AAAA,EAIA,OAAU,QAAoB,aAAsB;AAClD,QAAI,KAAK,SAAS,UAAU;AAC1B,aAAO;AAAA,IACT,OAAO;AACL,WAAK,KAAK,WAAW;AAAA,IACvB;AAAA,EACF;AACF;AAMA,IAAI,MAAiB;AAEd,SAAS,QAAY;AAC1B,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,GAAG;AAAA,EACf;AACA,SAAO;AACT;AAEO,SAAS,MAAM,IAAc;AAClC,QAAM;AACR;AAUO,SAAS,iBAAiB,MAI/B;AACA,MAAI,OAAmB;AAEvB,QAAM,QAAQ,QAAQ,OAAO,UAAU;AACvC,QAAM,aAAa,QAAQ,QAAQ,IAAI,UAAU,CAAC;AAClD,MAAI,QAAQ,SAAS,CAAC;AAEtB,QAAM,OAAiB,CAAC;AAExB,aAAW,OAAO,MAAM;AACtB,YAAQ,KAAK;AAAA,MACX,KAAK;AACH,gBAAQ;AACR;AAAA,MACF,KAAK;AACH,gBAAQ;AACR;AAAA,MACF,KAAK;AACH,eAAO;AACP;AAAA,MACF,KAAK;AAKH,eAAO;AACP;AAAA,MACF,KAAK;AACH,eAAO;AACP;AAAA,MACF;AACE,aAAK,KAAK,GAAG;AAAA,IACjB;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,OAAO,UAAU,KAAK;AACvC;;;AEtjBA,eAAsB,iBAAiB,MAGf;AACtB,QAAM,OAAO,MAAM,QAAQ,QAAQ;AAEnC,MAAI;AACJ,MAAI,MAAM,IAAI;AACZ,SAAK,KAAK;AAAA,EACZ,OAAO;AACL,UAAM,EAAE,MAAM,MAAM,IAAI,iBAAiB,IAAI;AAC7C,SAAK,IAAI,GAAG,EAAE,MAAM,MAAM,CAAC;AAAA,EAC7B;AAEA,QAAM,WAAW,IAAI,SAAS;AAE9B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,KAAK,QAAQ,IAAI;AAAA,IACjB;AAAA,EACF;AACF;;;ACtCA,YAAYC,UAAQ;AACpB,YAAYC,YAAU;AAwCtB,IAAM,qBAAqB;AAG3B,IAAM,8BAA8B;AAGpC,IAAM,mBAAmB;AAGzB,IAAM,sBAAsB;AAa5B,IAAM,mBAAmB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQA,SAAS,eAAe,YAAiD;AACvE,QAAM,QAAqC,CAAC;AAC5C,aAAW,SAAS,kBAAkB;AACpC,UAAM,KAAK,IAAI;AAAA,MACb;AAAA,QACE,SAAS;AAAA,QACT,OAAO;AAAA,UACL;AAAA,YACE,MAAM;AAAA,YACN,SAAS,SAAS,UAAU,yBAAyB,KAAK;AAAA,UAC5D;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAaO,SAAS,oBAA4B;AAE1C,MAAI,QAAQ,IAAI,qBAAqB,GAAG;AACtC,WAAO,QAAQ,IAAI,qBAAqB;AAAA,EAC1C;AAKA,QAAM,cAAmB,eAAQ,WAAW,MAAM,MAAM,MAAM,oBAAoB;AAClF,MAAO,gBAAgB,YAAK,aAAa,SAAS,eAAe,CAAC,GAAG;AACnE,WAAO;AAAA,EACT;AAGA,MAAI;AACF,UAAM,EAAE,aAAa,IAAI,UAAQ,eAAoB;AACrD,UAAM,SAAS,aAAa,OAAO,CAAC,UAAU,IAAI,GAAG,EAAE,UAAU,QAAQ,CAAC,EAAE,KAAK;AACjF,UAAM,aAAkB,YAAK,QAAQ,OAAO,gBAAgB,YAAY,oBAAoB;AAC5F,QAAO,gBAAgB,YAAK,YAAY,SAAS,eAAe,CAAC,GAAG;AAClE,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,SAAO;AACT;AAWA,SAAS,gBAAgB,OAA4B;AACnD,QAAM,OAAiB,CAAC;AACxB,MAAI,OAAO,MAAM,YAAY,UAAU;AACrC,SAAK,KAAK,MAAM,OAAO;AAAA,EACzB;AACA,MAAI,OAAO,MAAM,YAAY,UAAU;AACrC,SAAK,KAAK,MAAM,OAAO;AAAA,EACzB;AAEA,QAAM,SAAS,MAAM,OAAO;AAC5B,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,eAAW,OAAO,QAAQ;AACxB,UAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU;AAC3C,cAAM,SAAU,IAA8B,SAAS;AACvD,YAAI,OAAO,WAAW,UAAU;AAC9B,eAAK,KAAK,MAAM;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,qBAAqB,OAA2B;AACvD,QAAM,OAAO,gBAAgB,KAAK;AAClC,SAAO,KAAK;AAAA,IACV,CAAC,MAAM,EAAE,SAAS,kBAAkB,KAAK,EAAE,SAAS,2BAA2B;AAAA,EACjF;AACF;AAGA,SAAS,YAAY,OAA2B;AAC9C,QAAM,OAAO,gBAAgB,KAAK;AAClC,SAAO,KAAK,KAAK,CAAC,MAAM,EAAE,SAAS,gBAAgB,KAAK,EAAE,SAAS,mBAAmB,CAAC;AACzF;AAUA,SAAS,UAAU,OAA6C;AAC9D,SAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAC9C;AAMO,SAAS,WAAW,UAA6B,MAAiC;AAEvF,QAAM,aAAa,KAAK,cAAc,kBAAkB;AACxD,QAAM,YAAY,eAAe,UAAU;AAG3C,QAAM,gBAA6C,CAAC;AAEpD,MAAI,UAAU,OAAO;AACnB,eAAW,CAAC,OAAO,GAAG,KAAK,OAAO,QAAQ,SAAS,KAAK,GAAG;AACzD,oBAAc,KAAK,IAAI,UAAU,GAA8B;AAAA,IACjE;AAAA,EACF;AAEA,QAAM,QAAkB,CAAC;AACzB,QAAM,YAAsB,CAAC;AAC7B,QAAM,WAAqB,CAAC;AAE5B,QAAM,cAA2C,CAAC;AAGlD,aAAW,CAAC,OAAO,OAAO,KAAK,OAAO,QAAQ,aAAa,GAAG;AAC5D,gBAAY,KAAK,IAAI,CAAC;AACtB,eAAW,SAAS,SAAS;AAC3B,UAAI,qBAAqB,KAAK,GAAG;AAE/B,iBAAS,KAAK,KAAK;AAAA,MACrB,WAAW,YAAY,KAAK,GAAG;AAE7B,oBAAY,KAAK,EAAE,KAAK,KAAK;AAAA,MAC/B,OAAO;AAEL,oBAAY,KAAK,EAAE,KAAK,KAAK;AAC7B,kBAAU,KAAK,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAGA,aAAW,CAAC,OAAO,WAAW,KAAK,OAAO,QAAQ,SAAS,GAAG;AAC5D,QAAI,CAAC,YAAY,KAAK,EAAG,aAAY,KAAK,IAAI,CAAC;AAC/C,UAAM,UAAU,YAAY,KAAK,EAAE,KAAK,CAAC,MAAM,YAAY,CAAC,CAAC;AAC7D,QAAI,CAAC,SAAS;AACZ,kBAAY,KAAK,EAAE,KAAK,GAAG,WAAW;AACtC,YAAM,KAAK,KAAK;AAAA,IAClB;AAAA,EACF;AAGA,aAAW,SAAS,OAAO,KAAK,WAAW,GAAG;AAC5C,QAAI,YAAY,KAAK,EAAE,WAAW,GAAG;AACnC,aAAO,YAAY,KAAK;AAAA,IAC1B;AAAA,EACF;AAGA,QAAM,SAAqB;AAAA,IACzB,GAAI,YAAY,CAAC;AAAA,IACjB,OAAO;AAAA,EACT;AAEA,SAAO,EAAE,QAAQ,OAAO,WAAW,SAAS;AAC9C;AAMA,eAAsB,eAAe,UAA8C;AACjF,MAAI,CAAI,gBAAW,QAAQ,EAAG,QAAO;AAErC,MAAI;AACJ,MAAI;AACF,UAAS,kBAAa,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,GAAG;AAC3E,YAAM,MAAM;AACZ,UAAI,CAAC,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,MAAM,YAAY,MAAM,QAAQ,IAAI,OAAO,CAAC,GAAG;AAEpF,eAAO,EAAE,OAAO,CAAC,EAAE;AAAA,MACrB;AACA,aAAO;AAAA,IACT;AACA,WAAO,EAAE,OAAO,CAAC,EAAE;AAAA,EACrB,QAAQ;AAEN,WAAO,EAAE,OAAO,CAAC,EAAE;AAAA,EACrB;AACF;AAMA,eAAsB,gBAAgB,UAAkB,KAAgC;AACtF,QAAM,MAAW,eAAQ,QAAQ;AACjC,MAAI,CAAI,gBAAW,GAAG,GAAG;AACvB,IAAG,eAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,EACvC;AACA,EAAG,mBAAc,UAAU,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI,MAAM,OAAO;AACzE;AAMA,eAAsB,aACpB,YACA,UACA,MACsB;AACtB,QAAM,SAAS,WAAW,UAAU,IAAI;AAExC,MAAI,KAAK,QAAQ;AACf,WAAO;AAAA,EACT;AAGA,MAAI;AACJ,MAAI,aAAa,QAAW,gBAAW,UAAU,GAAG;AAClD,iBAAa,GAAG,UAAU,gBAAgB,KAAK,IAAI,CAAC;AACpD,IAAG,kBAAa,YAAY,UAAU;AACtC,WAAO,aAAa;AAAA,EACtB;AAEA,QAAM,gBAAgB,YAAY,OAAO,MAAM;AAE/C,SAAO;AACT;AAMA,eAAsB,cACpB,YAC2D;AAC3D,QAAM,MAAW,eAAQ,UAAU;AACnC,QAAM,OAAY,gBAAS,UAAU;AAErC,MAAI,cAAwB,CAAC;AAC7B,MAAI;AACF,UAAM,UAAa,iBAAY,GAAG;AAClC,kBAAc,QACX,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,eAAe,CAAC,EAClD,KAAK;AAAA,EACV,QAAQ;AACN,WAAO,EAAE,UAAU,OAAO,YAAY,KAAK;AAAA,EAC7C;AAEA,MAAI,YAAY,WAAW,GAAG;AAC5B,WAAO,EAAE,UAAU,OAAO,YAAY,KAAK;AAAA,EAC7C;AAGA,QAAM,eAAoB,YAAK,KAAK,YAAY,YAAY,SAAS,CAAC,CAAC;AAEvE,MAAI;AACF,IAAG,kBAAa,cAAc,UAAU;AACxC,IAAG,gBAAW,YAAY;AAC1B,WAAO,EAAE,UAAU,MAAM,YAAY,aAAa;AAAA,EACpD,QAAQ;AACN,WAAO,EAAE,UAAU,OAAO,YAAY,aAAa;AAAA,EACrD;AACF;;;ACzXO,IAAM,iBAAN,MAAqB;AAAA,EAG1B,YAA6B,OAA8B,CAAC,GAAG;AAAlC;AAAA,EAAmC;AAAA,EAFxD,QAA+B;AAAA,EAIvC,QAAc;AACZ,QAAI,KAAK,UAAU,KAAM;AACzB,UAAM,aAAa,KAAK,KAAK,cAAc,KAAK,KAAK,KAAK;AAC1D,SAAK,QAAQ,YAAY,MAAM;AAC7B,WAAK,SAAS,KAAK,IAAI,EAAE,MAAM,MAAM,MAAS;AAAA,IAChD,GAAG,UAAU;AACb,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA,EAEA,OAAa;AACX,QAAI,KAAK,UAAU,KAAM;AACzB,kBAAc,KAAK,KAAK;AACxB,SAAK,QAAQ;AAAA,EACf;AACF;AAEO,SAAS,qBAAqB,MAA8C;AACjF,SAAO,IAAI,eAAe,IAAI;AAChC;AAEA,eAAsB,SAAS,OAA8B,CAAC,GAAyB;AACrF,QAAM,KAAK,YAAY;AACvB,QAAM,QAAQ,GAAG,gBAAgB;AAAA,IAC/B,SAAS,KAAK;AAAA,IACd,OAAO,KAAK;AAAA,IACZ,OAAO;AAAA,EACT,CAAC;AAED,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,gBAAgB,MAAM;AAAA,EACxB;AACF;;;AChCA,YAAYC,aAAY;AACxB,YAAYC,UAAQ;AACpB,YAAYC,UAAQ;AACpB,YAAYC,YAAU;AA0CtB,IAAM,eAAoB,YAAQ,aAAQ,GAAG,YAAY,gBAAgB;AACzE,IAAM,kBAAkB;AACxB,IAAM,sBAAsB,KAAK;AACjC,IAAM,iBAAiB;AAMhB,IAAM,iBAAN,MAAqB;AAAA,EAClB;AAAA,EACA,mBAA4B;AAAA,EAC5B;AAAA,EACA;AAAA,EAER,YAAY,SAAyC;AACnD,SAAK,WAAW,IAAI,SAAS,EAAE,kBAAkB,SAAS,iBAAiB,CAAC;AAC5E,SAAK,mBAAmB,SAAS;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA4B;AAChC,QAAI;AAEF,YAAM,UAAU,MAAM,KAAK,SAAS,QAAQ;AAC5C,YAAM,YAAY,MAAM,QAAQ,UAAU;AAC1C,UAAI,WAAW;AACb,aAAK,mBAAmB;AACxB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AAAA,IAEd;AAGA,QAAI,CAAC,KAAK,kBAAkB;AAC1B,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AAEA,SAAK,mBAAmB;AACxB,UAAM,KAAK,kBAAkB;AAG7B,SAAK,kBAAkB,YAAY,MAAM;AACvC,WAAK,KAAK,mBAAmB,EAAE,MAAM,CAAC,QAAQ;AAC5C,gBAAQ,MAAM,oCAAoC,GAAG;AAAA,MACvD,CAAC;AAAA,IACH,GAAG,IAAI,KAAK,GAAI;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,OAAoC;AACjD,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,YAAY,MAAM,sBAAsB;AAE9C,UAAM,WAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,WAAW;AAAA,MACX;AAAA,IACF;AAEA,QAAI,KAAK,kBAAkB;AACzB,YAAM,KAAK,qBAAqB,QAAQ;AAAA,IAC1C,OAAO;AACL,YAAM,KAAK,gBAAgB,QAAQ;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,WAAiD;AAC5D,QAAI;AAEJ,QAAI,KAAK,kBAAkB;AACzB,cAAQ,MAAM,KAAK,qBAAqB,SAAS;AAAA,IACnD,OAAO;AACL,cAAQ,MAAM,KAAK,gBAAgB,SAAS;AAAA,IAC9C;AAEA,QAAI,CAAC,MAAO,QAAO;AAGnB,QAAI,KAAK,IAAI,IAAI,MAAM,WAAW;AAChC,YAAM,KAAK,UAAU,SAAS;AAC9B,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,WAAkC;AAChD,QAAI,KAAK,kBAAkB;AACzB,YAAM,KAAK,wBAAwB,SAAS;AAAA,IAC9C,OAAO;AACL,YAAM,KAAK,mBAAmB,SAAS;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,QAAyC;AAC/D,QAAI,KAAK,kBAAkB;AACzB,aAAO,MAAM,KAAK,wBAAwB,MAAM;AAAA,IAClD,OAAO;AACL,aAAO,MAAM,KAAK,mBAAmB,MAAM;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,QAA4C;AACzD,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI;AAEJ,QAAI,QAAQ;AACV,aAAO,MAAM,KAAK,kBAAkB,MAAM;AAAA,IAC5C,OAAO;AAEL,UAAI,KAAK,kBAAkB;AACzB,cAAM,OAAO,MAAM,KAAK,kBAAkB;AAC1C,eAAO,OAAO,OAAO,IAAI;AAAA,MAC3B,OAAO;AAEL,eAAO,CAAC;AAAA,MACV;AAAA,IACF;AAEA,UAAM,aAAa,KAAK,OAAO,CAAC,MAAM,EAAE,YAAY,GAAG;AACvD,UAAM,cAAc,KAAK,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG;AAEzD,UAAM,OAAO,WAAW,IAAI,CAAC,OAAO,MAAM,EAAE,aAAa,GAAI;AAC7D,UAAM,eAAe,KAAK,IAAI,GAAG,MAAM,CAAC;AACxC,UAAM,eAAe,KAAK,IAAI,GAAG,MAAM,CAAC;AAExC,WAAO;AAAA,MACL,WAAW,KAAK;AAAA,MAChB,YAAY,WAAW;AAAA,MACvB,aAAa,YAAY;AAAA,MACzB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,qBAAoC;AACxC,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,UAAU;AAEd,QAAI,KAAK,kBAAkB;AACzB,YAAM,OAAO,MAAM,KAAK,kBAAkB;AAC1C,iBAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AACrD,YAAI,MAAM,aAAa,KAAK;AAC1B,iBAAO,KAAK,SAAS;AACrB;AAAA,QACF;AAAA,MACF;AACA,UAAI,UAAU,GAAG;AACf,cAAM,KAAK,mBAAmB,IAAI;AAAA,MACpC;AAAA,IACF,OAAO;AAEL,YAAM,WAAW,MAAM,KAAK,SAAS,KAAK,eAAe;AACzD,iBAAW,WAAW,UAAU;AAC9B,cAAM,YAAY,MAAM,KAAK,SAAS,IAAI,iBAAiB,OAAO;AAClE,YAAI,WAAW;AACb,gBAAM,QAAQ,KAAK,MAAM,SAAS;AAClC,cAAI,MAAM,aAAa,KAAK;AAC1B,kBAAM,KAAK,SAAS,OAAO,iBAAiB,OAAO;AACnD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,UAAU,GAAG;AACf,cAAQ,IAAI,+BAA+B,OAAO,eAAe;AAAA,IACnE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACd,QAAI,KAAK,iBAAiB;AACxB,oBAAc,KAAK,eAAe;AAClC,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,oBAAmC;AAC/C,UAAM,MAAW,eAAQ,YAAY;AACrC,QAAI,CAAI,gBAAW,GAAG,GAAG;AACvB,MAAG,eAAU,KAAK,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAAA,IACpD;AAEA,QAAI,CAAI,gBAAW,YAAY,GAAG;AAChC,YAAM,QAAQ,CAAC;AACf,YAAM,KAAK,mBAAmB,KAAK;AAEnC,MAAG,eAAU,cAAc,GAAK;AAAA,IAClC;AAAA,EACF;AAAA,EAEA,MAAc,oBAA2D;AACvE,QAAI;AACF,YAAM,YAAe,kBAAa,cAAc,OAAO;AACvD,UAAI,CAAC,UAAU,KAAK,EAAG,QAAO,CAAC;AAE/B,YAAM,YAAY,KAAK,YAAY,SAAS;AAC5C,aAAO,KAAK,MAAM,SAAS;AAAA,IAC7B,SAAS,KAAK;AACZ,cAAQ,MAAM,mDAAmD,GAAG;AACpE,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAc,mBAAmB,MAAmD;AAClF,UAAM,OAAO,KAAK,UAAU,MAAM,MAAM,CAAC;AACzC,UAAM,YAAY,KAAK,YAAY,IAAI;AAEvC,UAAM,UAAU,eAAe;AAC/B,IAAG,mBAAc,SAAS,WAAW,OAAO;AAC5C,IAAG,eAAU,SAAS,GAAK;AAC3B,IAAG,gBAAW,SAAS,YAAY;AAAA,EACrC;AAAA,EAEQ,YAAY,WAA2B;AAC7C,QAAI,CAAC,KAAK,kBAAkB;AAC1B,YAAM,IAAI,MAAM,gDAAgD;AAAA,IAClE;AAEA,UAAM,OAAc,oBAAY,EAAE;AAClC,UAAM,KAAY,oBAAY,EAAE;AAChC,UAAM,MAAa;AAAA,MACjB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,SAAgB,uBAAe,eAAe,KAAK,EAAE;AAC3D,QAAI,YAAY,OAAO,OAAO,WAAW,OAAO;AAChD,gBAAY,OAAO,OAAO,CAAC,WAAW,OAAO,MAAM,CAAC,CAAC;AAErD,UAAM,UAAU,OAAO,WAAW;AAElC,UAAM,SAAS,OAAO,OAAO,CAAC,MAAM,IAAI,WAAW,OAAO,CAAC;AAC3D,WAAO,OAAO,SAAS,QAAQ;AAAA,EACjC;AAAA,EAEQ,YAAY,WAA2B;AAC7C,QAAI,CAAC,KAAK,kBAAkB;AAC1B,YAAM,IAAI,MAAM,gDAAgD;AAAA,IAClE;AAEA,UAAM,OAAO,OAAO,KAAK,WAAW,QAAQ;AAC5C,UAAM,OAAO,KAAK,MAAM,GAAG,EAAE;AAC7B,UAAM,KAAK,KAAK,MAAM,IAAI,EAAE;AAC5B,UAAM,aAAa,KAAK,MAAM,IAAI,KAAK,SAAS,EAAE;AAClD,UAAM,UAAU,KAAK,MAAM,KAAK,SAAS,EAAE;AAE3C,UAAM,MAAa;AAAA,MACjB,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,WAAkB,yBAAiB,eAAe,KAAK,EAAE;AAC/D,aAAS,WAAW,OAAO;AAE3B,QAAI,YAAY,SAAS,OAAO,UAAU;AAC1C,gBAAY,OAAO,OAAO,CAAC,WAAW,SAAS,MAAM,CAAC,CAAC;AAEvD,WAAO,UAAU,SAAS,OAAO;AAAA,EACnC;AAAA,EAEA,MAAc,qBAAqB,OAAoC;AACrE,UAAM,OAAO,MAAM,KAAK,kBAAkB;AAC1C,SAAK,MAAM,SAAS,IAAI;AACxB,UAAM,KAAK,mBAAmB,IAAI;AAAA,EACpC;AAAA,EAEA,MAAc,qBAAqB,WAAiD;AAClF,UAAM,OAAO,MAAM,KAAK,kBAAkB;AAC1C,WAAO,KAAK,SAAS,KAAK;AAAA,EAC5B;AAAA,EAEA,MAAc,wBAAwB,WAAkC;AACtE,UAAM,OAAO,MAAM,KAAK,kBAAkB;AAC1C,WAAO,KAAK,SAAS;AACrB,UAAM,KAAK,mBAAmB,IAAI;AAAA,EACpC;AAAA,EAEA,MAAc,wBAAwB,QAAyC;AAC7E,UAAM,OAAO,MAAM,KAAK,kBAAkB;AAC1C,WAAO,OAAO,OAAO,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,gBAAgB,OAAoC;AAChE,UAAM,QAAQ,KAAK,UAAU,KAAK;AAClC,UAAM,KAAK,SAAS,IAAI,iBAAiB,MAAM,WAAW,KAAK;AAAA,EACjE;AAAA,EAEA,MAAc,gBAAgB,WAAiD;AAC7E,UAAM,QAAQ,MAAM,KAAK,SAAS,IAAI,iBAAiB,SAAS;AAChE,QAAI,CAAC,MAAO,QAAO;AAEnB,QAAI;AACF,aAAO,KAAK,MAAM,KAAK;AAAA,IACzB,SAAS,KAAK;AACZ,cAAQ,MAAM,oDAAoD,GAAG;AACrE,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,mBAAmB,WAAkC;AACjE,UAAM,KAAK,SAAS,OAAO,iBAAiB,SAAS;AAAA,EACvD;AAAA,EAEA,MAAc,mBAAmB,QAAyC;AACxE,UAAM,WAAW,MAAM,KAAK,SAAS,KAAK,eAAe;AACzD,UAAM,OAAuB,CAAC;AAE9B,eAAW,WAAW,UAAU;AAC9B,YAAM,QAAQ,MAAM,KAAK,gBAAgB,OAAO;AAChD,UAAI,SAAS,MAAM,WAAW,QAAQ;AACpC,aAAK,KAAK,KAAK;AAAA,MACjB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;AAUO,SAAS,kBAAkB,QAAgB,YAA4B;AAC5E,SAAO,GAAG,MAAM,IAAI,UAAU;AAChC;AAKO,SAAS,eAAe,WAA2D;AACxF,QAAM,WAAW,UAAU,QAAQ,GAAG;AACtC,MAAI,aAAa,IAAI;AACnB,UAAM,IAAI,MAAM,8BAA8B,SAAS,EAAE;AAAA,EAC3D;AACA,SAAO;AAAA,IACL,QAAQ,UAAU,MAAM,GAAG,QAAQ;AAAA,IACnC,YAAY,UAAU,MAAM,WAAW,CAAC;AAAA,EAC1C;AACF;AAKO,SAAS,eACd,QACA,YACA,SACA,iBACA,MAAc,GACA;AACd,SAAO;AAAA,IACL,WAAW,kBAAkB,QAAQ,UAAU;AAAA,IAC/C;AAAA,IACA;AAAA,IACA,SAAS;AAAA,MACP,WAAW,QAAQ,UAAU,SAAS,QAAQ;AAAA,MAC9C,YAAY,QAAQ,WAAW,SAAS,QAAQ;AAAA,IAClD;AAAA,IACA;AAAA,IACA,WAAW,KAAK,IAAI;AAAA,IACpB,WAAW,KAAK,IAAI,IAAI,sBAAsB;AAAA,IAC9C;AAAA,EACF;AACF;;;ACxbA,IAAM,WAA4C;AAAA,EAChD,EAAE,MAAM,kBAAkB,IAAI,oBAAoB;AAAA;AAAA;AAAA,EAGlD,EAAE,MAAM,mBAAmB,IAAI,iCAAiC;AAAA,EAChE,EAAE,MAAM,mBAAmB,IAAI,4BAA4B;AAAA,EAC3D,EAAE,MAAM,mBAAmB,IAAI,4BAA4B;AAAA,EAC3D,EAAE,MAAM,sBAAsB,IAAI,8BAA8B;AAAA;AAAA;AAAA,EAGhE,EAAE,MAAM,kBAAkB,IAAI,yCAAyC;AAAA,EACvE,EAAE,MAAM,oBAAoB,IAAI,uBAAuB;AAAA,EACvD,EAAE,MAAM,sBAAsB,IAAI,uBAAuB;AAAA,EACzD,EAAE,MAAM,qBAAqB,IAAI,uBAAuB;AAAA,EACxD,EAAE,MAAM,uBAAuB,IAAI,uBAAuB;AAAA,EAC1D,EAAE,MAAM,wBAAwB,IAAI,uBAAuB;AAAA,EAC3D,EAAE,MAAM,eAAe,IAAI,gCAAgC;AAAA,EAC3D,EAAE,MAAM,qBAAqB,IAAI,0DAA0D;AAAA,EAC3F,EAAE,MAAM,OAAO,IAAI,sDAAsD,UAAU,KAAK;AAC1F;AAGO,SAAS,eAAe,SAA8B;AAC3D,QAAM,OAAoB,CAAC;AAC3B,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,cAAwB,CAAC,CAAC;AAChC,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,QAAI,QAAQ,WAAW,CAAC,MAAM,GAAI,aAAY,KAAK,IAAI,CAAC;AAAA,EAC1D;AAEA,QAAM,eAAe,CAAC,QAAwB;AAC5C,aAAS,IAAI,YAAY,SAAS,GAAG,KAAK,GAAG,KAAK;AAChD,UAAI,YAAY,CAAC,KAAK,IAAK,QAAO,IAAI;AAAA,IACxC;AACA,WAAO;AAAA,EACT;AAEA,aAAW,EAAE,MAAM,IAAI,SAAS,KAAK,UAAU;AAC7C,OAAG,YAAY;AACf,QAAI;AACJ,YAAQ,IAAI,GAAG,KAAK,OAAO,OAAO,MAAM;AACtC,WAAK,KAAK;AAAA,QACR,SAAS;AAAA,QACT,OAAO,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE;AAAA,QACvB,MAAM,aAAa,EAAE,KAAK;AAAA,QAC1B,UAAU,aAAa;AAAA,MACzB,CAAC;AACD,UAAI,EAAE,UAAU,GAAG,UAAW,IAAG;AAAA,IACnC;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,kBAAkB,SAA0B;AAC1D,SAAO,eAAe,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ;AACxD;;;AC/EA,SAAS,cAAAC,mBAAkB;AAC3B;AAAA,EACE,cAAAC;AAAA,EACA,aAAAC;AAAA,EACA,eAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,YAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,cAAAC;AAAA,OACK;AACP,SAAS,WAAAC,UAAS,QAAAC,QAAM,UAAU,OAAAC,YAAW;AAKtC,IAAM,6BAA6B,MAAM;AAGzC,IAAM,iBAAiB;AAG9B,IAAM,YAAY,oBAAI,IAAY;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAuDD,SAAS,UAAU,GAAmB;AACpC,SAAOC,YAAW,QAAQ,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK;AACpD;AAEA,SAAS,aAAa,SAAgC;AACpD,QAAM,IAAIC,OAAK,SAAS,cAAc;AACtC,MAAI,CAACC,aAAW,CAAC,GAAG;AAClB,WAAO,EAAE,QAAQ,CAAC,GAAG,YAAY,MAAM,MAAM,GAAG;AAAA,EAClD;AACA,MAAI;AACF,UAAM,MAAMC,eAAa,GAAG,MAAM;AAClC,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,WAAO;AAAA,MACL,QAAQ,OAAO,UAAU,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS,CAAC;AAAA,MAC9E,YAAY,OAAO,OAAO,eAAe,WAAW,OAAO,aAAa;AAAA,MACxE,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;AAAA,IACxD;AAAA,EACF,QAAQ;AACN,WAAO,EAAE,QAAQ,CAAC,GAAG,YAAY,MAAM,MAAM,GAAG;AAAA,EAClD;AACF;AAEA,SAAS,cAAc,SAAiB,OAA4B;AAClE,QAAM,IAAIF,OAAK,SAAS,cAAc;AACtC,EAAAG,YAAUC,SAAQ,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;AACzC,EAAAC,eAAc,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,MAAM;AACzD;AAGO,SAAS,kBAAkB,SAA2B;AAC3D,QAAM,MAAgB,CAAC;AACvB,WAAS,KAAK,KAAa;AACzB,QAAI;AACJ,QAAI;AACF,gBAAUC,aAAY,GAAG;AAAA,IAC3B,QAAQ;AACN;AAAA,IACF;AACA,eAAW,SAAS,SAAS;AAC3B,UAAI,UAAU,IAAI,KAAK,EAAG;AAC1B,UAAI,UAAU,eAAgB;AAC9B,YAAM,OAAON,OAAK,KAAK,KAAK;AAC5B,UAAI;AACJ,UAAI;AACF,aAAKO,UAAS,IAAI;AAAA,MACpB,QAAQ;AACN;AAAA,MACF;AACA,UAAI,GAAG,YAAY,EAAG,MAAK,IAAI;AAAA,eACtB,GAAG,OAAO,KAAK,SAAS,KAAK,KAAK,EAAG,KAAI,KAAK,IAAI;AAAA,IAC7D;AAAA,EACF;AACA,OAAK,OAAO;AACZ,SAAO,IAAI,IAAI,CAAC,QAAQ,SAAS,SAAS,GAAG,EAAE,MAAMC,IAAG,EAAE,KAAK,GAAG,CAAC;AACrE;AAMA,SAAS,gBAAgB,SAAiB,SAAiB,SAAuB;AAChF,MAAI,QAAQ,SAAS,IAAI,KAAK,QAAQ,WAAW,GAAG,GAAG;AACrD,UAAM,IAAI,MAAM,sCAAsC,OAAO,EAAE;AAAA,EACjE;AACA,QAAM,SAASR,OAAK,SAAS,OAAO;AACpC,QAAM,OAAOA,OAAK,SAAS,GAAG;AAE9B,MAAI,CAAC,OAAO,WAAW,IAAI,GAAG;AAC5B,UAAM,IAAI,MAAM,sCAAsC,OAAO,EAAE;AAAA,EACjE;AACA,EAAAG,YAAUC,SAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,EAAAC,eAAc,QAAQ,SAAS,MAAM;AACvC;AAgBA,eAAsB,eAAe,MAA4D;AAC/F,QAAM,EAAE,MAAM,SAAS,QAAQ,SAAS,WAAW,OAAO,IAAI;AAC9D,QAAM,UAAU,aAAa;AAE7B,MAAI,CAACJ,aAAW,OAAO,GAAG;AACxB,IAAAE,YAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,EACxC;AAEA,QAAM,WAAW,aAAa,OAAO;AACrC,QAAM,QAAQ,KAAK,UAAU,SAAS,SAAS,OAAO,SAAS,cAAc,SAAY;AAGzF,QAAM,QAAQ,kBAAkB,OAAO;AACvC,QAAM,cAA6E,CAAC;AACpF,QAAM,sBAAmE,CAAC;AAC1E,QAAM,YAAoC,CAAC;AAE3C,aAAW,OAAO,OAAO;AACvB,UAAM,MAAMH,OAAK,SAAS,GAAG;AAC7B,QAAI;AACJ,QAAI;AACF,YAAME,eAAa,KAAK,MAAM;AAAA,IAChC,QAAQ;AACN;AAAA,IACF;AAEA,UAAM,UAAU,OAAO,WAAW,KAAK,MAAM;AAC7C,QAAI,UAAU,4BAA4B;AAExC;AAAA,IACF;AAEA,UAAM,OAAO,UAAU,GAAG;AAC1B,cAAU,GAAG,IAAI;AAGjB,QAAI,SAAS,SAAS,QAAQ,SAAS,OAAO,GAAG,MAAM,KAAM;AAE7D,QAAI,kBAAkB,GAAG,GAAG;AAC1B,YAAM,MAAM,eAAe,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ;AACvD,0BAAoB,KAAK,EAAE,MAAM,KAAK,SAAS,IAAI,SAAS,MAAM,IAAI,KAAK,CAAC;AAC5E;AAAA,IACF;AAEA,gBAAY,KAAK,EAAE,MAAM,KAAK,SAAS,KAAK,aAAa,KAAK,CAAC;AAAA,EACjE;AAGA,QAAM,MAAM,GAAG,QAAQ,QAAQ,OAAO,EAAE,CAAC;AACzC,QAAM,MAAM,MAAM,QAAQ,KAAK;AAAA,IAC7B,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,eAAe,UAAU,MAAM;AAAA,IACjC;AAAA,IACA,MAAM,KAAK,UAAU,EAAE,MAAM,OAAO,MAAM,YAAY,CAAC;AAAA,EACzD,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,UAAM,IAAI,MAAM,0BAA0B,IAAI,MAAM,IAAI,IAAI,EAAE;AAAA,EAChE;AAEA,QAAM,OAAQ,MAAM,IAAI,KAAK;AAiB7B,MAAI,CAAC,KAAK,MAAM,CAAC,KAAK,MAAM;AAC1B,UAAM,IAAI,MAAM,uBAAuB,KAAK,SAAS,SAAS,EAAE;AAAA,EAClE;AAEA,QAAM,OAAO,KAAK;AAGlB,MAAI,CAAC,QAAQ;AACX,eAAW,OAAO,KAAK,QAAQ;AAC7B,UAAI;AACF,wBAAgB,SAAS,IAAI,MAAM,IAAI,OAAO;AAC9C,kBAAU,IAAI,IAAI,IAAI,IAAI;AAAA,MAC5B,SAAS,KAAK;AAEZ,aAAK,OAAO,SAAS,KAAK;AAAA,UACxB,MAAM,IAAI;AAAA,UACV,QAAQ;AAAA,UACR,QAAS,IAAc;AAAA,QACzB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAIA,QAAM,cAAsC,CAAC;AAC7C,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,SAAS,GAAG;AAC9C,gBAAY,CAAC,IAAI;AAAA,EACnB;AAEA,MAAI,CAAC,QAAQ;AACX,kBAAc,SAAS;AAAA,MACrB;AAAA,MACA,QAAQ;AAAA,MACR,YAAY,KAAK;AAAA,IACnB,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,QAAQ,KAAK,OAAO;AAAA,IACpB,QAAQ,KAAK,OAAO;AAAA,IACpB,UAAU,KAAK,OAAO;AAAA,IACtB;AAAA,IACA,YAAY,KAAK;AAAA,EACnB;AACF;AAMO,SAAS,mBAAmB,SAAuB;AACxD,QAAM,IAAIF,OAAK,SAAS,cAAc;AACtC,MAAIC,aAAW,CAAC,GAAG;AACjB,QAAI;AACF,MAAAQ,YAAW,CAAC;AAAA,IACd,QAAQ;AAAA,IAER;AAAA,EACF;AACF;;;AClTA,YAAYC,aAAY;AAqCjB,SAAS,oBAAoB,KAA0B;AAC5D,SAAO;AACT;AASA,IAAM,SAAmB,IAAI,MAAM,GAAG,EAAE,KAAK,CAAC;AAC9C,IAAM,SAAmB,IAAI,MAAM,GAAG,EAAE,KAAK,CAAC;AAAA,CAE7C,SAAS,eAAqB;AAC7B,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,WAAO,CAAC,IAAI;AACZ,WAAO,CAAC,IAAI;AAGZ,QAAI,OAAQ,KAAK,IAAK;AACtB,QAAI,OAAO,IAAO,SAAQ;AAC1B,QAAI,OAAO;AAAA,EACb;AACA,SAAO,GAAG,IAAI,OAAO,CAAC;AACxB,GAAG;AAGH,SAAS,MAAM,GAAW,GAAmB;AAC3C,MAAI,MAAM,KAAK,MAAM,EAAG,QAAO;AAC/B,SAAO,QAAQ,OAAO,CAAC,IAAI,OAAO,CAAC,KAAK,GAAG;AAC7C;AAGA,SAAS,MAAM,GAAW,GAAmB;AAC3C,MAAI,MAAM,EAAG,OAAM,IAAI,MAAM,0BAA0B;AACvD,MAAI,MAAM,EAAG,QAAO;AACpB,SAAO,QAAQ,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,OAAO,GAAG;AACnD;AAGA,SAAS,OAAO,QAAkB,GAAmB;AACnD,MAAI,SAAS;AACb,WAAS,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,KAAK;AAC3C,aAAS,MAAM,QAAQ,CAAC,IAAI,OAAO,CAAC;AAAA,EACtC;AACA,SAAO;AACT;AAOA,SAAS,oBAAoB,IAAc,IAAsB;AAC/D,MAAI,SAAS;AACb,QAAM,IAAI,GAAG;AACb,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,QAAI,MAAM;AACV,QAAI,MAAM;AACV,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAI,MAAM,EAAG;AACb,YAAM,MAAM,KAAK,GAAG,CAAC,CAAC;AACtB,YAAM,MAAM,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;AAAA,IAChC;AACA,UAAM,OAAO,MAAM,GAAG,CAAC,GAAG,MAAM,KAAK,GAAG,CAAC;AACzC,cAAU;AAAA,EACZ;AACA,SAAO;AACT;AAgBO,SAAS,YAAY,QAAgB,GAAW,GAA0B;AAC/E,MAAI,CAAC,OAAO,UAAU,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,GAAG;AAChD,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AACA,MAAI,IAAI,GAAG;AACT,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AACA,MAAI,IAAI,GAAG;AACT,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AACA,MAAI,IAAI,KAAK;AACX,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AACA,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD;AAEA,QAAM,YAAY,OAAO;AAGzB,QAAM,eACJ,IAAI,IAAW,oBAAY,aAAa,IAAI,EAAE,IAAI,OAAO,MAAM,CAAC;AAGlE,QAAM,SAAmB,CAAC;AAC1B,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,MAAM,OAAO,MAAM,YAAY,CAAC;AACtC,QAAI,CAAC,IAAI,IAAI;AACb,WAAO,KAAK,GAAG;AAAA,EACjB;AAGA,QAAM,SAAS,IAAI,MAAM,CAAC,EAAE,KAAK,CAAC;AAClC,WAAS,UAAU,GAAG,UAAU,WAAW,WAAW;AACpD,WAAO,CAAC,IAAI,OAAO,OAAO;AAC1B,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,aAAO,CAAC,IAAI,aAAa,WAAW,IAAI,MAAM,IAAI,EAAE;AAAA,IACtD;AACA,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAM,OAAO,IAAI;AACjB,aAAO,CAAC,EAAE,UAAU,CAAC,IAAI,OAAO,QAAQ,IAAI;AAAA,IAC9C;AAAA,EACF;AAKA,SAAO;AACT;AASO,SAAS,cAAc,QAA+B;AAC3D,MAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,OAAO,WAAW,GAAG;AACjD,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AACA,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAEA,QAAM,cAAc,OAAO,CAAC,EAAE;AAC9B,MAAI,cAAc,GAAG;AACnB,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AAEA,QAAM,KAAe,CAAC;AACtB,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,KAAK,QAAQ;AACtB,QAAI,CAAC,OAAO,SAAS,CAAC,GAAG;AACvB,YAAM,IAAI,MAAM,2CAA2C;AAAA,IAC7D;AACA,QAAI,EAAE,WAAW,aAAa;AAC5B,YAAM,IAAI;AAAA,QACR,uDAAuD,WAAW,SAAS,EAAE,MAAM;AAAA,MACrF;AAAA,IACF;AACA,UAAM,IAAI,EAAE,CAAC;AACb,QAAI,MAAM,GAAG;AACX,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,QAAI,KAAK,IAAI,CAAC,GAAG;AACf,YAAM,IAAI,MAAM,qCAAqC,CAAC,EAAE;AAAA,IAC1D;AACA,SAAK,IAAI,CAAC;AACV,OAAG,KAAK,CAAC;AAAA,EACX;AAEA,QAAM,YAAY,cAAc;AAChC,QAAM,SAAS,OAAO,MAAM,SAAS;AAErC,QAAM,KAAK,IAAI,MAAM,OAAO,MAAM,EAAE,KAAK,CAAC;AAC1C,WAAS,UAAU,GAAG,UAAU,WAAW,WAAW;AACpD,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,SAAG,CAAC,IAAI,OAAO,CAAC,EAAE,UAAU,CAAC;AAAA,IAC/B;AACA,WAAO,OAAO,IAAI,oBAAoB,IAAI,EAAE;AAAA,EAC9C;AAEA,SAAO;AACT;AAMA,IAAM,qBAAqB;AAC3B,IAAM,oBAA4C,MAAM;AACtD,QAAM,MAA8B,CAAC;AACrC,WAAS,IAAI,GAAG,IAAI,mBAAmB,QAAQ,KAAK;AAClD,QAAI,mBAAmB,CAAC,CAAC,IAAI;AAAA,EAC/B;AAEA,MAAI,GAAG,IAAI;AACX,MAAI,GAAG,IAAI;AACX,MAAI,GAAG,IAAI;AACX,SAAO;AACT,GAAG;AAEH,IAAM,mBAAmB;AAGzB,SAAS,MAAM,KAAqB;AAClC,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,WAAO,IAAI,CAAC,KAAK;AACjB,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAI,MAAM,OAAQ;AAChB,eAAQ,OAAO,IAAK,QAAU;AAAA,MAChC,OAAO;AACL,cAAO,OAAO,IAAK;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AACA,SAAO,MAAM;AACf;AAGA,SAAS,aAAa,KAAqB;AACzC,MAAI,OAAO;AACX,MAAI,QAAQ;AACZ,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,YAAS,SAAS,IAAK,IAAI,CAAC;AAC5B,YAAQ;AACR,WAAO,QAAQ,GAAG;AAChB,aAAO,mBAAoB,UAAW,OAAO,IAAM,EAAI;AACvD,cAAQ;AAAA,IACV;AAAA,EACF;AACA,MAAI,OAAO,GAAG;AACZ,WAAO,mBAAoB,SAAU,IAAI,OAAS,EAAI;AAAA,EACxD;AACA,SAAO;AACT;AAMA,SAAS,aAAa,GAAW,iBAAiC;AAChE,QAAM,aAAa,EAAE,YAAY;AACjC,MAAI,OAAO;AACX,MAAI,QAAQ;AACZ,QAAM,MAAM,OAAO,MAAM,eAAe;AACxC,MAAI,SAAS;AACb,aAAW,MAAM,YAAY;AAC3B,UAAM,IAAI,iBAAiB,EAAE;AAC7B,QAAI,MAAM,QAAW;AACnB,YAAM,IAAI,MAAM,oCAAoC,EAAE,GAAG;AAAA,IAC3D;AACA,YAAS,SAAS,IAAK;AACvB,YAAQ;AACR,QAAI,QAAQ,GAAG;AACb,UAAI,UAAU,iBAAiB;AAE7B,gBAAQ;AACR,kBAAU,KAAK,QAAQ;AACvB;AAAA,MACF;AACA,UAAI,QAAQ,IAAK,UAAW,OAAO,IAAM;AACzC,cAAQ;AAAA,IACV;AAAA,EACF;AACA,MAAI,WAAW,iBAAiB;AAC9B,UAAM,IAAI;AAAA,MACR,yBAAyB,MAAM,oBAAoB,eAAe;AAAA,IACpE;AAAA,EACF;AACA,SAAO;AACT;AAWO,SAAS,sBAAsB,OAA4B;AAChE,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,MAAM,SAAS,GAAG;AAC/C,UAAM,IAAI,MAAM,8DAA8D;AAAA,EAChF;AACA,QAAM,YAAY,OAAO,OAAO,CAAC,OAAO,KAAK,CAAC,gBAAgB,CAAC,GAAG,KAAK,CAAC;AACxE,QAAM,MAAM,MAAM,SAAS;AAC3B,QAAM,SAAS,OAAO,KAAK,CAAE,OAAO,IAAK,KAAM,MAAM,GAAI,CAAC;AAC1D,QAAM,SAAS,OAAO,OAAO,CAAC,WAAW,MAAM,CAAC;AAChD,QAAM,MAAM,aAAa,MAAM;AAE/B,QAAM,SAAmB,CAAC;AAC1B,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK,GAAG;AACtC,WAAO,KAAK,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC;AAAA,EACjC;AACA,SAAO,OAAO,KAAK,GAAG;AACxB;AAMO,SAAS,wBAAwB,SAA8B;AACpE,MAAI,OAAO,YAAY,YAAY,QAAQ,WAAW,GAAG;AACvD,UAAM,IAAI,MAAM,2DAA2D;AAAA,EAC7E;AAEA,QAAM,WAAW,QAAQ,QAAQ,UAAU,EAAE,EAAE,YAAY;AAC3D,MAAI,SAAS,WAAW,GAAG;AACzB,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AAOA,QAAM,YAAY,SAAS,SAAS;AACpC,QAAM,WAAW,KAAK,MAAM,YAAY,CAAC;AACzC,MAAI,WAAW,GAAG;AAEhB,UAAM,IAAI,MAAM,2EAA2E;AAAA,EAC7F;AAEA,QAAM,UAAU,aAAa,UAAU,QAAQ;AAG/C,MAAI,QAAQ,CAAC,MAAM,kBAAkB;AACnC,UAAM,IAAI;AAAA,MACR,kDAAkD,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC,gBAAgB,iBAAiB,SAAS,EAAE,CAAC;AAAA,IACxH;AAAA,EACF;AACA,QAAM,UAAW,QAAQ,QAAQ,SAAS,CAAC,KAAK,IAAK,QAAQ,QAAQ,SAAS,CAAC;AAC/E,QAAM,OAAO,QAAQ,SAAS,GAAG,QAAQ,SAAS,CAAC;AACnD,QAAM,UAAU,MAAM,IAAI;AAC1B,MAAI,YAAY,SAAS;AACvB,UAAM,IAAI;AAAA,MACR,gDAAgD,QAAQ,SAAS,EAAE,CAAC,gBAAgB,QAAQ,SAAS,EAAE,CAAC;AAAA,IAC1G;AAAA,EACF;AAKA,SAAO,OAAO,KAAK,QAAQ,SAAS,GAAG,QAAQ,SAAS,CAAC,CAAC;AAC5D;;;AC/ZO,IAAM,kBAAkB;","names":["resolve","t","resolve","path","sep","resolve","path","TaskRouteState","path","crypto","fs","os","path","resolve","fs","os","path","fs","path","os","TOML","basename","defaultConfigPath","TOML","fs","os","path","crypto","fs","os","path","writer","EventEmitter","fs","os","path","performance","resolve","WebSocket","fs","os","path","resolve","WebSocket","path","crypto","EventEmitter","path","crypto","crypto","fs","os","path","Database","crypto","fs","encrypt","decrypt","Database","row","ftsCount","deriveKey","encrypt","decrypt","fs","os","path","AdapterRegistry","DispatchMux","sep","getAgent","findLanIPv4","fs","path","fs","path","crypto","fs","os","path","createHash","existsSync","mkdirSync","readdirSync","readFileSync","statSync","writeFileSync","unlinkSync","dirname","join","sep","createHash","join","existsSync","readFileSync","mkdirSync","dirname","writeFileSync","readdirSync","statSync","sep","unlinkSync","crypto"]}
|