@condorinst/mobile-bridge 0.20.0 → 0.22.0
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/AGENTS.md +109 -42
- package/CHANGELOG.md +99 -0
- package/README.md +80 -14
- package/contract/bridge-contract.json +59 -14
- package/dist/cli.cjs +933 -3
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +932 -3
- package/dist/cli.js.map +1 -1
- package/dist/dev-harness.global.js +2110 -0
- package/dist/dev.cjs +1662 -0
- package/dist/dev.cjs.map +1 -0
- package/dist/dev.d.cts +683 -0
- package/dist/dev.d.ts +683 -0
- package/dist/dev.js +1611 -0
- package/dist/dev.js.map +1 -0
- package/dist/index.cjs +96 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +236 -14
- package/dist/index.d.ts +236 -14
- package/dist/index.js +94 -3
- package/dist/index.js.map +1 -1
- package/docs/agent-guide.md +75 -24
- package/docs/bridge-contract.md +121 -20
- package/docs/client-guide.md +42 -29
- package/docs/device-testing.md +114 -0
- package/docs/pilot-onboarding.md +31 -13
- package/docs/troubleshooting.md +79 -18
- package/examples/minimal-home/AGENTS.md +9 -6
- package/examples/minimal-home/README.md +10 -5
- package/examples/minimal-home/build.mjs +2 -1
- package/examples/minimal-home/index.html +2 -0
- package/examples/minimal-home/package.json +3 -2
- package/examples/minimal-home/src/main.ts +151 -73
- package/llms-full.txt +2086 -0
- package/llms.txt +15 -13
- package/package.json +9 -3
package/dist/dev.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dev/index.ts","../src/dev/fixtures.ts","../src/keys.ts","../src/internal/dev-panel.ts","../src/internal/mock.ts","../src/internal/native.ts","../src/internal/subscribers.ts","../src/bridge.ts","../src/bridge-shell.ts","../src/shell-messages.ts","../src/dev/policy.ts","../src/dev/scenarios.ts","../src/dev/harness.ts"],"sourcesContent":["/**\n * `@condorinst/mobile-bridge/dev` — the development harness.\n *\n * Runs your bundle in the browser inside the same sandbox, shell and policy as\n * the Condor Canvas app, against a simulated native side with device-like\n * scenarios. Import it in the **page that hosts** your bundle during\n * development, never in the bundle. The CLI wraps it:\n * `npx condor-mobile-bridge dev -i dist/index.html --scenario cold-start`.\n */\n\nexport {\n DEFAULT_LOG_PERIOD_S,\n formatLocalTimestamp,\n parseLocalTimestamp,\n sensorLogPage,\n sharedSerial,\n systemStatus,\n twoDevices,\n} from './fixtures';\nexport type { DevHarness, DevHarnessOptions, HarnessLogEntry } from './harness';\nexport { createDevHarness, createSimulatedNative, DEV_HARNESS_MARKER } from './harness';\nexport { CANVAS_CSP, CANVAS_POLICY } from './policy';\nexport type { Scenario, ScenarioName } from './scenarios';\nexport { HARNESS_NATIVE_VERSION, resolveScenario, SCENARIOS } from './scenarios';\n","/**\n * Realistic fixture data for the development harness.\n *\n * Shapes follow the typed payloads in `../payloads`, which mirror the Dart\n * `toMap()` of `condor_core`. Timestamps that the device produces (`log_time`)\n * are **device-local** wall-clock strings, built with local `Date` getters —\n * never `toISOString()`.\n */\n\nimport type {\n DeviceConfigItem,\n DeviceTelemetryItem,\n DeviceUserConfigItem,\n SensorLogItem,\n SensorLogPayload,\n SensorLogQueryPayload,\n SystemStatusPayload,\n UserDevicePayload,\n} from '../payloads';\n\n/** Default log period of an ActLumus, in seconds. Programmable per device. */\nexport const DEFAULT_LOG_PERIOD_S = 60;\n\nconst pad = (n: number): string => String(n).padStart(2, '0');\n\n/** `YYYY-MM-DD HH:MM:SS` in local time — the format of `log_time`. */\nexport function formatLocalTimestamp(date: Date): string {\n return (\n `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` +\n `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`\n );\n}\n\n/** Parses a local `YYYY-MM-DD HH:MM:SS` back to epoch ms. */\nexport function parseLocalTimestamp(value: string): number {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})$/.exec(value);\n if (!m) return Number.NaN;\n const [, y, mo, d, h, mi, s] = m.map(Number) as number[];\n return new Date(y ?? 0, (mo ?? 1) - 1, d ?? 1, h ?? 0, mi ?? 0, s ?? 0).getTime();\n}\n\ninterface DeviceSpec {\n deviceId: number;\n serialNo: number;\n modelId?: DeviceConfigItem['modelId'];\n bodyPart: DeviceConfigItem['deviceBodyPart'];\n name: string;\n battery: number;\n charging: boolean;\n syncedMinutesAgo: number;\n syncError?: string;\n}\n\nfunction config(spec: DeviceSpec): DeviceConfigItem {\n const item: DeviceConfigItem = {\n deviceId: spec.deviceId,\n serialNo: spec.serialNo,\n deviceBodyPart: spec.bodyPart,\n bleConnectionPeriod: 5,\n autosync: true,\n eraseDeviceMemory: false,\n autoEraseDeviceMemory: false,\n autoEraseDeviceMemoryThreshold: 80,\n readSensorsMemory: false,\n startDevice: false,\n readFullMemory: false,\n allowFirmwareUpdate: true,\n };\n if (spec.modelId) item.modelId = spec.modelId;\n return item;\n}\n\nfunction telemetry(spec: DeviceSpec, now: number): DeviceTelemetryItem {\n return {\n serialNo: spec.serialNo,\n deviceId: spec.deviceId,\n updataDateTime: now - spec.syncedMinutesAgo * 60_000,\n deviceName: spec.name,\n deviceVersion: spec.modelId === 'actlumus_plus' ? '3.0.2' : '2.1.0',\n hardwareVersion: spec.modelId === 'actlumus_plus' ? 'B' : 'A',\n deviceDateTime: now - spec.syncedMinutesAgo * 60_000,\n memoryDataUsage: 37.5,\n memorySystemUsage: 4.2,\n batteryLevel: spec.battery,\n batteryVoltage: 3.7 + spec.battery / 1000,\n isCharging: spec.charging,\n isOnDock: spec.charging,\n syncErrors: spec.syncError\n ? [\n {\n serialNo: spec.serialNo,\n attemptDate: now - 10 * 60_000,\n message: spec.syncError,\n messageCode: 'SYNC_FAILED',\n },\n ]\n : [],\n };\n}\n\nfunction userConfig(spec: DeviceSpec): DeviceUserConfigItem {\n return {\n serialNo: spec.serialNo,\n deviceId: spec.deviceId,\n syncTime: false,\n realTime: false,\n deleteMemory: false,\n readAllMemory: false,\n readAllSystemLog: false,\n };\n}\n\nfunction payloadOf(specs: DeviceSpec[], now = Date.now()): UserDevicePayload {\n return {\n lastUpdate: now,\n devicesConfig: specs.map(config),\n devicesTelemetry: specs.map((s) => telemetry(s, now)),\n devicesUserConfig: specs.map(userConfig),\n };\n}\n\n/** Two devices with distinct serial numbers: the common case. */\nexport function twoDevices(now = Date.now()): UserDevicePayload {\n return payloadOf(\n [\n {\n deviceId: 9001,\n serialNo: 4534,\n modelId: 'actlumus',\n bodyPart: 'wrist',\n name: 'ActLumus 4534',\n battery: 82,\n charging: false,\n syncedMinutesAgo: 12,\n },\n {\n deviceId: 9002,\n serialNo: 5120,\n modelId: 'actlumus_plus',\n bodyPart: 'necklace',\n name: 'ActLumus Plus 5120',\n battery: 41,\n charging: true,\n syncedMinutesAgo: 190,\n syncError: 'Could not read the device memory.',\n },\n ],\n now,\n );\n}\n\n/**\n * An ActLumus and an ActLumus Plus sharing serial number 7047 — real data\n * looked like this for the first pilot account. Only `deviceId` tells them\n * apart.\n */\nexport function sharedSerial(now = Date.now()): UserDevicePayload {\n return payloadOf(\n [\n {\n deviceId: 9101,\n serialNo: 7047,\n bodyPart: 'wrist',\n name: 'ActLumus 7047',\n battery: 67,\n charging: false,\n syncedMinutesAgo: 30,\n },\n {\n deviceId: 9102,\n serialNo: 7047,\n modelId: 'actlumus_plus',\n bodyPart: 'necklace',\n name: 'ActLumus Plus 7047',\n battery: 93,\n charging: false,\n syncedMinutesAgo: 8,\n },\n ],\n now,\n );\n}\n\nexport function systemStatus(overrides: Partial<SystemStatusPayload> = {}): SystemStatusPayload {\n return {\n bluetooth: true,\n internet: true,\n permission: true,\n hasDevices: true,\n missingOptionalPermissions: [],\n missingEssentialPermissions: [],\n deviceSyncError: {},\n deviceSyncErrorById: {},\n ...overrides,\n };\n}\n\n/** Light follows a daylight curve so charts look like real data. */\nfunction lightAt(epochMs: number, serialNo: number): { photopic: number; melanopic: number } {\n const d = new Date(epochMs);\n const hour = d.getHours() + d.getMinutes() / 60;\n const daylight = Math.max(0, Math.sin(((hour - 6) / 12) * Math.PI));\n const noise = ((epochMs / 60_000 + serialNo) % 7) / 7;\n const photopic = Math.round((daylight * 1800 + noise * 40) * 10) / 10;\n return { photopic, melanopic: Math.round(photopic * 0.62 * 10) / 10 };\n}\n\nfunction logAt(epochMs: number, serialNo: number, deviceId: number): SensorLogItem {\n const { photopic, melanopic } = lightAt(epochMs, serialNo);\n return {\n id: Math.floor(epochMs / 1000) * 10 + (serialNo % 10),\n log_time: formatLocalTimestamp(new Date(epochMs)),\n log_type: 1,\n body_part: 'wrist',\n temperature: 31.5,\n lux_photopic: photopic,\n lux_melanopic: melanopic,\n device_id: deviceId,\n act_data_pim: 120,\n };\n}\n\nconst HISTORY_DAYS = 14;\nconst encodeCursor = (epochMs: number): string => `mock:${epochMs}`;\nconst decodeCursor = (cursor: string): number => Number(cursor.slice('mock:'.length));\n\n/**\n * Answers a `sensorLog` query with the backend's paging semantics:\n * - no range: the most recent `limit` logs; older pages through `endingBefore`;\n * - with `startTime`: the oldest logs of the range first; newer pages through\n * `startingAfter` (with only `endTime`: the most recent before it);\n * - `logs` always chronological ascending; `hasMore` / `hasPrevious` computed\n * within the range.\n */\nexport function sensorLogPage(\n query: SensorLogQueryPayload,\n opts: { now?: number; periodS?: number; deviceId?: number } = {},\n): SensorLogPayload {\n const now = opts.now ?? Date.now();\n const periodMs = (opts.periodS ?? DEFAULT_LOG_PERIOD_S) * 1000;\n const limit = query.limit ?? 10;\n if (limit < 1 || limit > 1000) {\n return { requestId: query.requestId, success: false, error: 'INVALID_LIMIT' };\n }\n if (query.startingAfter && query.endingBefore) {\n return { requestId: query.requestId, success: false, error: 'CONFLICTING_CURSORS' };\n }\n\n const newest = Math.floor(now / periodMs) * periodMs;\n const oldest = newest - HISTORY_DAYS * 86_400_000;\n const rangeStart = query.startTime ? parseLocalTimestamp(query.startTime) : oldest;\n const rangeEnd = query.endTime ? parseLocalTimestamp(query.endTime) - 1 : newest;\n if (Number.isNaN(rangeStart) || Number.isNaN(rangeEnd) || rangeStart > rangeEnd + 1) {\n return { requestId: query.requestId, success: false, error: 'INVALID_TIME_RANGE' };\n }\n const first = Math.max(oldest, Math.ceil(rangeStart / periodMs) * periodMs);\n const last = Math.min(newest, Math.floor(rangeEnd / periodMs) * periodMs);\n\n let from: number;\n let to: number;\n if (query.endingBefore) {\n to = Math.min(last, decodeCursor(query.endingBefore) - periodMs);\n from = Math.max(first, to - (limit - 1) * periodMs);\n } else if (query.startingAfter) {\n from = Math.max(first, decodeCursor(query.startingAfter) + periodMs);\n to = Math.min(last, from + (limit - 1) * periodMs);\n } else if (query.startTime) {\n from = first;\n to = Math.min(last, from + (limit - 1) * periodMs);\n } else {\n to = last;\n from = Math.max(first, to - (limit - 1) * periodMs);\n }\n\n const logs: SensorLogItem[] = [];\n for (let t = from; t <= to; t += periodMs) {\n logs.push(logAt(t, query.serialNo, opts.deviceId ?? 0));\n }\n return {\n requestId: query.requestId,\n success: true,\n logs,\n startingAfter: logs.length ? encodeCursor(to) : null,\n endingBefore: logs.length ? encodeCursor(from) : null,\n hasMore: logs.length > 0 && to < last,\n hasPrevious: logs.length > 0 && from > first,\n };\n}\n","/**\n * Catalogue of the JS↔Native bridge keys.\n *\n * Mirrors the JS-facing side of `ForegroundComCoreKeys` in `condor_core`.\n * The strings here are what JavaScript receives through\n * `window.CondorBridge.emit(key, payload)`.\n *\n * Thirteen keys exist. A sandboxed client can subscribe to twelve of them:\n * `dfu` is denied by the shell policy and skipped natively. See\n * `docs/bridge-contract.md` for what each one carries and when it is emitted.\n */\nexport const BRIDGE_KEYS = {\n pingPong: 'pingPong',\n userDevice: 'userDevice',\n deviceLightSensors: 'deviceLightSensors',\n syncTime: 'syncTime',\n realTime: 'realTime',\n deleteMemory: 'deleteMemory',\n deviceNotification: 'deviceNotification',\n deviceConnection: 'deviceConnection',\n sensorLog: 'sensorLog',\n dfu: 'dfu',\n systemStatus: 'systemStatus',\n /**\n * Native → client: the OS back button was pressed and the client had\n * reported internal history via `reportNavigation(true)`. Go back exactly\n * ONE internal page. Emitted only when the native side decided to delegate\n * the back gesture. See `BridgeClient.onBack`.\n */\n navigationBack: 'navigationBack',\n /**\n * Native → client: the app's language state. Carries the raw device locale\n * AND the language explicitly chosen in the app Settings, so the client can\n * apply its own precedence rule — including rendering a language the native\n * chrome does not support. Emitted on attach, after `handshake-ack`, and on\n * every change in Settings. See `LanguagePayload`.\n */\n language: 'language',\n} as const;\n\nexport type BridgeKey = (typeof BRIDGE_KEYS)[keyof typeof BRIDGE_KEYS];\n","/**\n * Dev panel — a floating UI for inspecting the bridge in mock mode.\n *\n * **Opt-in:** call `Bridge.installDevPanel(opts?)` when you want it. It only\n * works in mock mode and throws in real mode. It injects into `document.body`\n * and is idempotent — re-installing removes the previous panel.\n *\n * Contents:\n * - a header with a \"MOCK\" badge, a send counter, and a minimise button;\n * - a sent log with the last N messages (timestamp, type, truncated payload);\n * - a trigger-emit control: a `BRIDGE_KEYS` dropdown, a payload textarea, and\n * a button.\n *\n * Styles are inline and classes are prefixed `condor-mock-panel-*`, to reduce\n * collisions with the client's own CSS.\n */\n\nimport { BRIDGE_KEYS } from '../keys';\nimport type { MockAdapter, MockMessage } from './mock';\n\nconst PANEL_ID = 'condor-mock-panel-root';\nconst REFRESH_INTERVAL_MS = 500;\n\n/**\n * A reply emitted automatically in reaction to a `Bridge.send`, returned by the\n * client's `onSendForAutoRespond` policy. `null` means \"do not answer this\n * send\".\n */\nexport interface AutoRespondResponse {\n key: string;\n payload: unknown;\n}\n\nexport interface DevPanelOptions {\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n maxMessages?: number;\n theme?: 'dark' | 'light';\n startCollapsed?: boolean;\n\n /**\n * Auto-respond policy: invoked on every `Bridge.send` while the panel's\n * \"Auto-respond\" toggle is on. Return `{ key, payload }` to fire\n * `Bridge.mockEmit(key, payload)` after the delay, or `null` to stay silent.\n *\n * Without this callback the \"Auto-respond\" checkbox does not appear.\n */\n onSendForAutoRespond?: (msg: MockMessage) => AutoRespondResponse | null;\n\n /**\n * Initial state of the \"Auto-respond\" toggle. Defaults to `false` — manual\n * stays the default, and the client decides when to turn it on.\n */\n startAutoRespondEnabled?: boolean;\n\n /**\n * Delay in milliseconds between the `send` and the auto-response `mockEmit`.\n * Defaults to `50`, which approximates the IPC latency of the real native\n * bridge.\n */\n autoRespondDelayMs?: number;\n}\n\ninterface InstallParams {\n adapter: MockAdapter;\n options?: DevPanelOptions;\n}\n\ninterface ResolvedOptions {\n position: NonNullable<DevPanelOptions['position']>;\n maxMessages: number;\n theme: NonNullable<DevPanelOptions['theme']>;\n startCollapsed: boolean;\n startAutoRespondEnabled: boolean;\n autoRespondDelayMs: number;\n}\n\nconst DEFAULTS: ResolvedOptions = {\n position: 'bottom-right',\n maxMessages: 20,\n theme: 'dark',\n startCollapsed: false,\n startAutoRespondEnabled: false,\n autoRespondDelayMs: 50,\n};\n\nfunction resolveOptions(opts?: DevPanelOptions): ResolvedOptions {\n return {\n position: opts?.position ?? DEFAULTS.position,\n maxMessages: opts?.maxMessages ?? DEFAULTS.maxMessages,\n theme: opts?.theme ?? DEFAULTS.theme,\n startCollapsed: opts?.startCollapsed ?? DEFAULTS.startCollapsed,\n startAutoRespondEnabled: opts?.startAutoRespondEnabled ?? DEFAULTS.startAutoRespondEnabled,\n autoRespondDelayMs: opts?.autoRespondDelayMs ?? DEFAULTS.autoRespondDelayMs,\n };\n}\n\nfunction applyPanelStyles(el: HTMLElement, opts: ResolvedOptions): void {\n const isDark = opts.theme === 'dark';\n const positions: Record<ResolvedOptions['position'], Partial<CSSStyleDeclaration>> = {\n 'bottom-right': { bottom: '12px', right: '12px' },\n 'bottom-left': { bottom: '12px', left: '12px' },\n 'top-right': { top: '12px', right: '12px' },\n 'top-left': { top: '12px', left: '12px' },\n };\n Object.assign(el.style, {\n position: 'fixed',\n width: '340px',\n maxHeight: '420px',\n zIndex: '2147483647',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: '12px',\n color: isDark ? '#e0e0e0' : '#222',\n background: isDark ? '#1a1a1aee' : '#ffffffee',\n border: isDark ? '1px solid #444' : '1px solid #ccc',\n borderRadius: '6px',\n boxShadow: '0 4px 12px rgba(0,0,0,0.3)',\n overflow: 'hidden',\n display: 'flex',\n flexDirection: 'column',\n ...positions[opts.position],\n });\n}\n\nfunction buildHeader(badge: HTMLElement, counter: HTMLElement, toggle: HTMLElement): HTMLElement {\n const header = document.createElement('div');\n header.className = 'condor-mock-panel-header';\n Object.assign(header.style, {\n padding: '6px 10px',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n background: '#0a84ff',\n color: '#fff',\n fontWeight: '600',\n cursor: 'pointer',\n });\n Object.assign(badge.style, {\n background: '#fff',\n color: '#0a84ff',\n padding: '1px 6px',\n borderRadius: '3px',\n fontSize: '10px',\n letterSpacing: '0.5px',\n });\n badge.textContent = 'MOCK';\n Object.assign(counter.style, {\n marginLeft: 'auto',\n fontSize: '11px',\n opacity: '0.9',\n });\n Object.assign(toggle.style, {\n background: 'transparent',\n border: '1px solid rgba(255,255,255,0.5)',\n color: '#fff',\n cursor: 'pointer',\n padding: '0 6px',\n borderRadius: '3px',\n fontFamily: 'inherit',\n });\n header.append(badge, document.createTextNode('condor-bridge'), counter, toggle);\n return header;\n}\n\nfunction buildSentSection(): { container: HTMLElement; list: HTMLElement } {\n const container = document.createElement('div');\n container.className = 'condor-mock-panel-sent';\n Object.assign(container.style, {\n padding: '6px 10px',\n borderBottom: '1px solid rgba(255,255,255,0.08)',\n maxHeight: '180px',\n overflowY: 'auto',\n });\n const title = document.createElement('div');\n title.textContent = 'Sent';\n Object.assign(title.style, { opacity: '0.7', marginBottom: '4px', fontSize: '11px' });\n const list = document.createElement('div');\n list.className = 'condor-mock-panel-sent-list';\n container.append(title, list);\n return { container, list };\n}\n\nfunction buildTriggerSection(\n bridgeKeys: readonly string[],\n onEmit: (key: string, payloadJson: string) => void,\n onClear: () => void,\n): HTMLElement {\n const container = document.createElement('div');\n container.className = 'condor-mock-panel-trigger';\n Object.assign(container.style, {\n padding: '6px 10px',\n display: 'flex',\n flexDirection: 'column',\n gap: '4px',\n });\n const title = document.createElement('div');\n title.textContent = 'Trigger emit';\n Object.assign(title.style, { opacity: '0.7', fontSize: '11px' });\n\n const select = document.createElement('select');\n select.className = 'condor-mock-panel-key-select';\n Object.assign(select.style, {\n background: 'transparent',\n color: 'inherit',\n border: '1px solid rgba(255,255,255,0.2)',\n padding: '4px',\n borderRadius: '3px',\n fontFamily: 'inherit',\n fontSize: '11px',\n });\n for (const key of bridgeKeys) {\n const opt = document.createElement('option');\n opt.value = key;\n opt.textContent = key;\n select.appendChild(opt);\n }\n const ackOpt = document.createElement('option');\n ackOpt.value = 'handshake-ack';\n ackOpt.textContent = 'handshake-ack';\n select.appendChild(ackOpt);\n\n const textarea = document.createElement('textarea');\n textarea.className = 'condor-mock-panel-payload';\n textarea.placeholder = '{ \"data\": \"pong\" }';\n Object.assign(textarea.style, {\n background: 'transparent',\n color: 'inherit',\n border: '1px solid rgba(255,255,255,0.2)',\n padding: '4px',\n borderRadius: '3px',\n fontFamily: 'inherit',\n fontSize: '11px',\n minHeight: '50px',\n resize: 'vertical',\n });\n\n const buttons = document.createElement('div');\n Object.assign(buttons.style, { display: 'flex', gap: '6px' });\n\n const emitBtn = document.createElement('button');\n emitBtn.type = 'button';\n emitBtn.textContent = 'Emit';\n emitBtn.className = 'condor-mock-panel-emit-btn';\n Object.assign(emitBtn.style, {\n background: '#0a84ff',\n color: '#fff',\n border: 'none',\n padding: '4px 10px',\n borderRadius: '3px',\n cursor: 'pointer',\n fontFamily: 'inherit',\n fontSize: '11px',\n flex: '1',\n });\n emitBtn.addEventListener('click', () => {\n onEmit(select.value, textarea.value);\n });\n\n const clearBtn = document.createElement('button');\n clearBtn.type = 'button';\n clearBtn.textContent = 'Clear sent';\n clearBtn.className = 'condor-mock-panel-clear-btn';\n Object.assign(clearBtn.style, {\n background: 'transparent',\n color: 'inherit',\n border: '1px solid rgba(255,255,255,0.3)',\n padding: '4px 10px',\n borderRadius: '3px',\n cursor: 'pointer',\n fontFamily: 'inherit',\n fontSize: '11px',\n });\n clearBtn.addEventListener('click', onClear);\n\n buttons.append(emitBtn, clearBtn);\n container.append(title, select, textarea, buttons);\n return container;\n}\n\nfunction buildAutoRespondSection(\n initialEnabled: boolean,\n onChange: (next: boolean) => void,\n): HTMLElement {\n const container = document.createElement('div');\n container.className = 'condor-mock-panel-auto-respond';\n Object.assign(container.style, {\n padding: '6px 10px',\n borderBottom: '1px solid rgba(255,255,255,0.08)',\n display: 'flex',\n flexDirection: 'column',\n gap: '2px',\n });\n\n const title = document.createElement('div');\n title.textContent = 'Auto-respond';\n Object.assign(title.style, { opacity: '0.7', fontSize: '11px' });\n\n const row = document.createElement('label');\n Object.assign(row.style, {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n cursor: 'pointer',\n fontSize: '12px',\n });\n\n const checkbox = document.createElement('input');\n checkbox.type = 'checkbox';\n checkbox.className = 'condor-mock-panel-auto-respond-toggle';\n checkbox.checked = initialEnabled;\n Object.assign(checkbox.style, {\n cursor: 'pointer',\n });\n\n const label = document.createElement('span');\n label.textContent = 'Enabled — mockEmit em resposta a cada send (policy do cliente)';\n\n checkbox.addEventListener('change', () => {\n onChange(checkbox.checked);\n });\n\n row.append(checkbox, label);\n container.append(title, row);\n return container;\n}\n\nfunction renderSentList(list: HTMLElement, adapter: MockAdapter, max: number): void {\n list.innerHTML = '';\n const all = adapter.getMessages();\n const tail = all.slice(-max).reverse();\n for (const msg of tail) {\n const row = document.createElement('div');\n Object.assign(row.style, {\n padding: '3px 0',\n borderBottom: '1px solid rgba(255,255,255,0.06)',\n wordBreak: 'break-all',\n });\n const ts = new Date(msg.timestamp).toLocaleTimeString();\n const payload = msg.payload as { type?: string };\n const type = payload?.type ?? '?';\n row.textContent = `${ts} → ${type} ${JSON.stringify(msg.payload).slice(0, 80)}`;\n list.appendChild(row);\n }\n}\n\ninterface InstalledPanel {\n uninstall(): void;\n refresh(): void;\n}\n\nlet currentPanel: InstalledPanel | null = null;\n\nexport function installDevPanel(params: InstallParams): InstalledPanel {\n if (typeof document === 'undefined') {\n throw new Error('condor-mobile-bridge dev panel: document is undefined (Node-only env).');\n }\n\n // Idempotente: remove painel anterior se existir.\n if (currentPanel) {\n currentPanel.uninstall();\n currentPanel = null;\n }\n\n const opts = resolveOptions(params.options);\n const root = document.createElement('div');\n root.id = PANEL_ID;\n applyPanelStyles(root, opts);\n\n const badge = document.createElement('span');\n const counter = document.createElement('span');\n const toggle = document.createElement('button');\n toggle.type = 'button';\n toggle.textContent = opts.startCollapsed ? '+' : '−';\n const header = buildHeader(badge, counter, toggle);\n\n const body = document.createElement('div');\n Object.assign(body.style, {\n display: opts.startCollapsed ? 'none' : 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n });\n\n const { container: sentContainer, list: sentList } = buildSentSection();\n\n // Auto-respond section — conditional render: só aparece se policy fornecida.\n const policy = params.options?.onSendForAutoRespond;\n let autoRespondEnabled = opts.startAutoRespondEnabled;\n let unsubscribeSendListener: (() => void) | null = null;\n\n let autoRespondSection: HTMLElement | null = null;\n if (policy) {\n autoRespondSection = buildAutoRespondSection(autoRespondEnabled, (next) => {\n autoRespondEnabled = next;\n });\n unsubscribeSendListener = params.adapter.onCallHandler((msg) => {\n if (!autoRespondEnabled) return;\n let response: AutoRespondResponse | null;\n try {\n response = policy(msg);\n } catch (err) {\n console.error('[condor-mobile-bridge dev-panel] onSendForAutoRespond threw:', err);\n return;\n }\n if (!response) return;\n setTimeout(() => {\n try {\n params.adapter.triggerEmit(response.key, response.payload);\n } catch (err) {\n console.error(\n '[condor-mobile-bridge dev-panel] triggerEmit failed in auto-respond:',\n err,\n );\n }\n }, opts.autoRespondDelayMs);\n });\n }\n\n const trigger = buildTriggerSection(\n Object.values(BRIDGE_KEYS),\n (key, payloadJson) => {\n let payload: unknown = {};\n const trimmed = payloadJson.trim();\n if (trimmed.length > 0) {\n try {\n payload = JSON.parse(trimmed);\n } catch (err) {\n console.error('[condor-mobile-bridge dev-panel] invalid JSON payload', err);\n return;\n }\n }\n params.adapter.triggerEmit(key, payload);\n },\n () => {\n params.adapter.clearMessages();\n renderSentList(sentList, params.adapter, opts.maxMessages);\n counter.textContent = '0 sent';\n },\n );\n\n if (autoRespondSection) {\n body.append(sentContainer, autoRespondSection, trigger);\n } else {\n body.append(sentContainer, trigger);\n }\n root.append(header, body);\n\n toggle.addEventListener('click', (e) => {\n e.stopPropagation();\n const collapsed = body.style.display === 'none';\n body.style.display = collapsed ? 'flex' : 'none';\n toggle.textContent = collapsed ? '−' : '+';\n });\n\n document.body.appendChild(root);\n\n const refresh = () => {\n const count = params.adapter.getMessages().length;\n counter.textContent = `${count} sent`;\n renderSentList(sentList, params.adapter, opts.maxMessages);\n };\n refresh();\n\n const interval = setInterval(refresh, REFRESH_INTERVAL_MS);\n\n const panel: InstalledPanel = {\n uninstall() {\n clearInterval(interval);\n unsubscribeSendListener?.();\n unsubscribeSendListener = null;\n root.remove();\n if (currentPanel === panel) currentPanel = null;\n },\n refresh,\n };\n currentPanel = panel;\n return panel;\n}\n\n/** Inspection helper, for tests and debugging. */\nexport function getInstalledDevPanel(): InstalledPanel | null {\n return currentPanel;\n}\n","/**\n * Mock adapter — active when no native host is detected: a plain browser,\n * jsdom without an installed host, Storybook, and so on.\n *\n * Behaviour:\n * - `callHandler` records `{ handlerName, payload, timestamp }` in an internal\n * buffer (capped at 100, FIFO), logs through `console.debug`, and dispatches\n * to listeners registered with `onCallHandler`.\n * - `triggerEmit` dispatches through `window.CondorBridge.emit`, so the real\n * bridge treats it as if it came from the native side: `handshake-ack`\n * resolves the handshake, every other key reaches its subscribers.\n * - `getMessages` returns a read-only snapshot of the buffer.\n * - `clearMessages` empties it, which is useful in tests.\n * - `onCallHandler(listener)` registers a listener invoked on every send and\n * returns an unsubscribe function — used by the dev panel's auto-respond\n * toggle, and for assertions in tests.\n */\n\nconst MAX_BUFFER = 100;\n\nexport interface MockMessage {\n handlerName: string;\n payload: unknown;\n timestamp: number;\n}\n\nexport interface MockAdapter {\n readonly isMock: true;\n callHandler(handlerName: string, payload: unknown): void;\n getMessages(): readonly MockMessage[];\n clearMessages(): void;\n triggerEmit(key: string, payload: unknown): void;\n /**\n * Registers a listener invoked on every `callHandler` (a JS → native\n * message). Returns an unsubscribe function.\n *\n * Errors thrown by a listener are caught and logged; they affect neither the\n * other listeners nor the bridge pipeline.\n */\n onCallHandler(listener: (msg: MockMessage) => void): () => void;\n}\n\nexport function createMockAdapter(): MockAdapter {\n const messages: MockMessage[] = [];\n const sendListeners = new Set<(msg: MockMessage) => void>();\n\n return {\n isMock: true,\n\n callHandler(handlerName, payload) {\n const msg: MockMessage = { handlerName, payload, timestamp: Date.now() };\n messages.push(msg);\n if (messages.length > MAX_BUFFER) {\n messages.shift();\n }\n console.debug('[condor-mobile-bridge mock] →', handlerName, payload);\n for (const listener of sendListeners) {\n try {\n listener(msg);\n } catch (err) {\n console.error('[condor-mobile-bridge mock] send listener threw:', err);\n }\n }\n },\n\n getMessages() {\n return messages;\n },\n\n clearMessages() {\n messages.length = 0;\n },\n\n triggerEmit(key, payload) {\n const bridge = typeof window !== 'undefined' ? window.CondorBridge : undefined;\n if (!bridge || typeof bridge.emit !== 'function') {\n throw new Error(\n 'condor-mobile-bridge mock: window.CondorBridge not bootstrapped; cannot emit.',\n );\n }\n bridge.emit(key, payload);\n },\n\n onCallHandler(listener) {\n sendListeners.add(listener);\n return () => {\n sendListeners.delete(listener);\n };\n },\n };\n}\n","/**\n * Native host detection, behind an adapter.\n *\n * Detection order: the `window.CondorNative` JavaScript channel\n * (`webview_flutter`) first, then the legacy `window.flutter_inappwebview`,\n * then the mock. The channel only accepts strings, so the message travels as\n * JSON. `setOutgoingStamp` lets the shell stamp every outgoing message — the\n * nonce — without monkey-patching the host.\n *\n * With no host at all the mock adapter activates, which is what makes browser\n * development possible without building an APK.\n *\n * The active adapter is cached on the first `getActiveAdapter()` call. Tests\n * should call `__resetAdapterForTests()` in `beforeEach` to force\n * re-detection, for instance after installing or removing\n * `window.CondorNative`.\n */\n\nimport { createMockAdapter, type MockAdapter } from './mock';\n\n/**\n * Name of the JavaScript channel the native side registers with\n * `WebViewController.addJavaScriptChannel`.\n *\n * It cannot be `CondorBridge`: the plugin publishes the channel as\n * `window.<name>`, which would collide with the `window.CondorBridge` emitter\n * this SDK installs.\n */\nexport const NATIVE_CHANNEL_NAME = 'CondorNative';\n\ninterface FlutterInAppWebView {\n callHandler(name: string, ...args: unknown[]): Promise<unknown>;\n}\n\ninterface NativeChannel {\n postMessage(message: string): void;\n}\n\ndeclare global {\n interface Window {\n flutter_inappwebview?: FlutterInAppWebView;\n CondorNative?: NativeChannel;\n }\n}\n\n/**\n * Transforma toda mensagem JS → Native imediatamente antes do envio.\n * Recebe e devolve o envelope `{type, version, payload}`.\n */\nexport type OutgoingStamp = (message: Record<string, unknown>) => Record<string, unknown>;\n\nlet outgoingStamp: OutgoingStamp | null = null;\n\nexport function setOutgoingStamp(stamp: OutgoingStamp | null): void {\n outgoingStamp = stamp;\n}\n\nexport interface RealAdapter {\n readonly isMock: false;\n callHandler(handlerName: string, payload: unknown): void;\n}\n\nexport type NativeAdapter = RealAdapter | MockAdapter;\n\nlet activeAdapter: NativeAdapter | null = null;\n\nfunction createChannelAdapter(channel: NativeChannel): RealAdapter {\n return {\n isMock: false,\n // Single channel: `handlerName` does not travel — the native side routes\n // on `type`.\n callHandler(_handlerName, payload) {\n channel.postMessage(JSON.stringify(payload));\n },\n };\n}\n\nfunction createLegacyAdapter(host: FlutterInAppWebView): RealAdapter {\n return {\n isMock: false,\n callHandler(handlerName, payload) {\n void host.callHandler(handlerName, payload);\n },\n };\n}\n\nfunction detectAdapter(): NativeAdapter {\n if (typeof window === 'undefined') {\n return createMockAdapter();\n }\n const channel = window.CondorNative;\n if (channel && typeof channel.postMessage === 'function') {\n return createChannelAdapter(channel);\n }\n const host = window.flutter_inappwebview;\n if (host && typeof host.callHandler === 'function') {\n return createLegacyAdapter(host);\n }\n return createMockAdapter();\n}\n\nexport function getActiveAdapter(): NativeAdapter {\n if (!activeAdapter) {\n activeAdapter = detectAdapter();\n }\n return activeAdapter;\n}\n\nexport function hasNativeHost(): boolean {\n return !getActiveAdapter().isMock;\n}\n\n/**\n * Sends a message to the native handler through the active adapter.\n *\n * Real mode: fire-and-forget over `CondorNative.postMessage` (JSON) or, on the\n * legacy host, `flutter_inappwebview.callHandler`.\n * Mock mode: recorded in the buffer and logged with `console.debug`.\n *\n * The `setOutgoingStamp` transform is applied on every adapter, so what the\n * mock records is exactly what the native side would have received.\n */\nexport function callNative(handlerName: string, payload: Record<string, unknown>): void {\n const stamped = outgoingStamp ? outgoingStamp(payload) : payload;\n getActiveAdapter().callHandler(handlerName, stamped);\n}\n\n/**\n * Resets the adapter cache. **Exported for tests only.**\n *\n * Client code must never call this: the adapter is detected once at startup\n * and kept for the lifetime of the page.\n */\nexport function __resetAdapterForTests(): void {\n activeAdapter = null;\n outgoingStamp = null;\n}\n","import type { BridgeKey } from '../keys';\nimport type { PayloadOf } from '../payloads';\n\ntype Callback = (payload: unknown) => void;\n\nconst subscribers = new Map<string, Set<Callback>>();\n\nexport function addSubscriber<K extends BridgeKey>(\n key: K,\n cb: (payload: PayloadOf<K>) => void,\n): () => void {\n let set = subscribers.get(key);\n if (!set) {\n set = new Set<Callback>();\n subscribers.set(key, set);\n }\n set.add(cb as Callback);\n return () => {\n const current = subscribers.get(key);\n if (!current) return;\n current.delete(cb as Callback);\n if (current.size === 0) {\n subscribers.delete(key);\n }\n };\n}\n\nexport function dispatchToSubscribers(key: string, payload: unknown): void {\n const set = subscribers.get(key);\n if (!set) return;\n for (const cb of set) {\n try {\n cb(payload);\n } catch (err) {\n // A buggy subscriber must not affect the others, or the bridge.\n console.error(`[condor-mobile-bridge] subscriber for \"${key}\" threw:`, err);\n }\n }\n}\n\n/**\n * Limpa todos os subscribers. Útil em testes para isolar casos.\n */\nexport function clearAllSubscribers(): void {\n subscribers.clear();\n}\n\n/**\n * Inspection helper, for tests and debugging.\n */\nexport function getSubscriberCount(key: string): number {\n return subscribers.get(key)?.size ?? 0;\n}\n\n/**\n * Lista das chaves com subscribers ativos (testes/debug/dev panel).\n */\nexport function getSubscriberKeys(): string[] {\n return Array.from(subscribers.keys());\n}\n","import type { DevPanelOptions } from './internal/dev-panel';\nimport { installDevPanel as installDevPanelInternal } from './internal/dev-panel';\nimport type { MockAdapter, MockMessage } from './internal/mock';\nimport {\n callNative,\n getActiveAdapter,\n type OutgoingStamp,\n setOutgoingStamp,\n} from './internal/native';\nimport { addSubscriber, dispatchToSubscribers, getSubscriberKeys } from './internal/subscribers';\nimport type { BridgeKey } from './keys';\nimport type { HandshakeAck, HandshakeOptions } from './messages';\nimport type { PayloadOf } from './payloads';\n\nconst HANDSHAKE_ACK_KEY = 'handshake-ack';\nconst NATIVE_HANDLER = 'CondorBridge';\nconst PROTOCOL_VERSION = '0.1.0';\n\ninterface PendingHandshake {\n resolve: (ack: HandshakeAck) => void;\n reject: (err: Error) => void;\n}\n\ninterface WindowCondorBridge {\n emit(key: string, payload: unknown): void;\n}\n\ndeclare global {\n interface Window {\n CondorBridge?: WindowCondorBridge;\n }\n}\n\nlet pendingHandshake: PendingHandshake | null = null;\nlet bridgeBootstrapped = false;\n\nfunction emit(key: string, payload: unknown): void {\n if (key === HANDSHAKE_ACK_KEY && pendingHandshake) {\n const ack = (payload ?? {}) as Partial<HandshakeAck>;\n const resolver = pendingHandshake;\n pendingHandshake = null;\n resolver.resolve({\n nativeVersion: ack.nativeVersion ?? 'unknown',\n accepted: ack.accepted ?? false,\n });\n return;\n }\n dispatchToSubscribers(key, payload);\n}\n\nfunction bootstrapWindowBridge(): void {\n if (bridgeBootstrapped) return;\n if (typeof window === 'undefined') return;\n bridgeBootstrapped = true;\n\n if (window.CondorBridge && typeof window.CondorBridge.emit === 'function') {\n // Already installed (HMR, double import, or a mock installed by tests).\n // Replace only `emit`, so the newest dispatcher is the one wired to the\n // subscribers of this module instance.\n window.CondorBridge.emit = emit;\n } else {\n window.CondorBridge = { emit };\n }\n}\n\nbootstrapWindowBridge();\n\nfunction requireMockAdapter(): MockAdapter {\n const adapter = getActiveAdapter();\n if (!adapter.isMock) {\n throw new Error(\n 'condor-mobile-bridge: this API is available only in mock mode (no native host detected).',\n );\n }\n return adapter;\n}\n\nexport interface MockState {\n readonly isMock: true;\n readonly messages: readonly MockMessage[];\n readonly subscriberKeys: readonly string[];\n}\n\nexport interface CondorBridge {\n /**\n * `true` when the active adapter is the mock — a plain browser, with neither\n * `window.CondorNative` nor `window.flutter_inappwebview`. `false` inside the\n * Flutter WebView.\n */\n readonly isMock: boolean;\n\n /**\n * Sends a versioned handshake to the native side and awaits `handshake-ack`.\n *\n * Only one handshake may be in flight; a parallel call before the first ack\n * arrives is rejected with an explicit error.\n *\n * **In mock mode it does not resolve on its own.** The caller must emit\n * `Bridge.mockEmit('handshake-ack', { nativeVersion, accepted })` to unblock\n * the promise. That is deliberate: it forces tests to be explicit about the\n * native state they are simulating.\n */\n handshake(opts: HandshakeOptions): Promise<HandshakeAck>;\n\n /**\n * Subscribes to an observable key. Returns an `unsubscribe` function.\n *\n * Multiple subscribers per key are allowed; a throw in one does not affect\n * the others (it is caught and logged with `console.error`).\n */\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void;\n\n /**\n * Sends a generic message to the native side, for commands without a\n * dedicated helper. `type` is the string the native side routes on.\n *\n * Fire-and-forget: no return value and no delivery confirmation. A payload\n * above 64 KB, or an unknown `type`, is dropped natively without a reply.\n *\n * In mock mode it is recorded in the internal buffer and logged with\n * `console.debug`.\n */\n send(type: string, payload?: Record<string, unknown>): void;\n\n /**\n * Opens the app's native Settings screen. Equivalent to\n * `Bridge.send('openSettings')`.\n */\n openSettings(): void;\n\n /**\n * Registers a transform applied to **every** JS → native message, the\n * handshake included, immediately before it is sent. Pass `null` to remove.\n *\n * It exists so the shell can stamp its nonce (`payload._shellNonce`) at a\n * single chokepoint. Wrapping `send` alone is not enough — `handshake` calls\n * the native layer directly, and a message without the nonce is dropped and\n * logged as a security event.\n *\n * **Client code must not use this.**\n */\n setOutgoingStamp(stamp: OutgoingStamp | null): void;\n\n /**\n * Fires `window.CondorBridge.emit(key, payload)` programmatically — useful to\n * simulate native events in tests and in browser development.\n *\n * **Throws** when the active adapter is not the mock.\n */\n mockEmit(key: string, payload?: unknown): void;\n\n /**\n * Snapshot of the mock adapter state: messages sent, and keys with active\n * subscribers. Useful for assertions in client tests.\n *\n * **Throws** when the active adapter is not the mock.\n */\n getMockState(): MockState;\n\n /**\n * Injects a floating HTML panel into `document.body` for inspecting the\n * bridge in mock mode. Idempotent — re-installing replaces the previous one.\n *\n * **Throws** when the active adapter is not the mock, or `document` does not\n * exist.\n */\n installDevPanel(options?: DevPanelOptions): void;\n}\n\nexport const Bridge: CondorBridge = {\n get isMock(): boolean {\n return getActiveAdapter().isMock;\n },\n\n handshake(opts: HandshakeOptions): Promise<HandshakeAck> {\n bootstrapWindowBridge();\n if (pendingHandshake) {\n return Promise.reject(\n new Error(\n 'condor-mobile-bridge: handshake already in flight. Await the previous call before issuing another.',\n ),\n );\n }\n return new Promise<HandshakeAck>((resolve, reject) => {\n pendingHandshake = { resolve, reject };\n try {\n callNative(NATIVE_HANDLER, {\n type: 'handshake',\n version: PROTOCOL_VERSION,\n payload: { clientVersion: opts.clientVersion },\n });\n } catch (err) {\n pendingHandshake = null;\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n });\n },\n\n on<K extends BridgeKey>(key: K, cb: (payload: PayloadOf<K>) => void): () => void {\n bootstrapWindowBridge();\n return addSubscriber(key, cb);\n },\n\n send(type: string, payload?: Record<string, unknown>): void {\n callNative(NATIVE_HANDLER, {\n type,\n version: PROTOCOL_VERSION,\n payload: payload ?? {},\n });\n },\n\n openSettings(): void {\n this.send('openSettings');\n },\n\n setOutgoingStamp(stamp: OutgoingStamp | null): void {\n setOutgoingStamp(stamp);\n },\n\n mockEmit(key: string, payload?: unknown): void {\n requireMockAdapter().triggerEmit(key, payload ?? {});\n },\n\n getMockState(): MockState {\n const adapter = requireMockAdapter();\n return {\n isMock: true,\n messages: adapter.getMessages(),\n subscriberKeys: getSubscriberKeys(),\n };\n },\n\n installDevPanel(options?: DevPanelOptions): void {\n const adapter = requireMockAdapter();\n installDevPanelInternal({ adapter, options });\n },\n};\n\n/**\n * Resets the bridge's internal state (the pending handshake).\n *\n * **Exported for tests only.** Do not call it from application code — it breaks\n * the \"only one handshake in flight\" invariant.\n */\nexport function __resetBridgeForTests(): void {\n pendingHandshake = null;\n}\n","/**\n * `BridgeShell` — the API for the **Condor-controlled shell** that wraps\n * external client content inside `<iframe sandbox=\"allow-scripts\">`.\n *\n * This is not client-facing. If you are writing the bundle that renders as the\n * app's Home, you want `BridgeClient`.\n *\n * Responsibilities:\n * 1. **Layer 1 — `bootstrapClientIframe(iframe, clientPath)`:** fetches the\n * client HTML, prepends an override script that removes the native globals\n * from the iframe, and sets it as `srcdoc`. The override runs at parse time,\n * before any other script.\n * 2. **Layer 2 — `verifySandbox(iframe)`:** a `postMessage` round trip asking\n * the iframe to attest that the native globals really are `undefined`.\n * 3. **Routing between iframe and native:** listens for `message` events from\n * the iframe, validates them with Valibot, applies the default-deny\n * `ShellPolicy`, and forwards to `Bridge`. Native events go back to the\n * iframe over `postMessage`.\n * 4. **Human confirmation for sensitive commands:** commands listed in\n * `policy.requiresConfirmation` fire the `onConfirmationRequest` callback\n * before touching the native side, so the shell can present UI.\n */\n\nimport * as v from 'valibot';\nimport { Bridge } from './bridge';\nimport type { BridgeKey } from './keys';\nimport {\n ClientToShellMessageSchema,\n type ConfirmationRequest,\n type SandboxVerifyResult,\n type ShellPolicy,\n type ShellToClientMessage,\n} from './shell-messages';\n\nconst SHELL_VERSION = '0.6.0';\n\n/**\n * How long the shell waits for the native handshake before answering the client\n * with `nativeVersion: null`. Deliberately short: the native channel is local,\n * and a fast `null` serves the client better than a slow answer.\n */\nconst NATIVE_HANDSHAKE_TIMEOUT_MS = 2000;\nconst VERIFY_TIMEOUT_MS = 2000;\n\n/**\n * **Layer 1 — the override prefix.**\n *\n * A script prepended to the iframe's `srcdoc` by `bootstrapClientIframe*`. It\n * runs at parse time, before any client script, inside the iframe's own\n * document (origin `null`, so there is no cross-origin block).\n *\n * It uses a **no-op getter/setter** with `configurable: false`, rather than\n * `value` with `writable: false`. Modern ESM bundles run in strict mode, where\n * any `window.X = …` on a non-writable property **throws** — which would break\n * legacy modules that register APIs on `window` at load time (this SDK itself\n * does `window.CondorBridge = { emit }` as an import side effect). With a no-op\n * getter/setter the assignment passes silently while the getter always returns\n * `undefined`: the native bridges stay unreachable without breaking legitimate\n * JavaScript.\n *\n * Validated empirically with an offensive pen test on a physical device.\n *\n * **Known limit.** The `webview_flutter` channel is injected into **every**\n * frame (iOS: a user script with `forMainFrameOnly: false`; Android:\n * `addJavascriptInterface`). Measured on an iPhone and a Xiaomi device: the\n * prefix does remove `window.CondorNative` from the iframe, but **a child\n * iframe created by the client receives the channel again**, and on iOS\n * `window.webkit.messageHandlers` cannot be locked (`defineProperty` throws).\n * This layer is defence in depth; the actual guarantee is Layer 3 — the nonce\n * validated natively, which discarded every message sent along those paths.\n */\nconst OVERRIDE_PREFIX = `<script>\n(function(){\n try { delete window.flutter_inappwebview; } catch (_) {}\n try { delete window.CondorBridge; } catch (_) {}\n try { delete window.CondorNative; } catch (_) {}\n try {\n Object.defineProperty(window, 'flutter_inappwebview', {\n get: function(){ return undefined; },\n set: function(_){ /* no-op: blocks the plugin injecting into the iframe */ },\n configurable: false,\n });\n } catch (_) {}\n try {\n Object.defineProperty(window, 'CondorNative', {\n get: function(){ return undefined; },\n set: function(_){ /* no-op: bloqueia o canal do webview_flutter no iframe */ },\n configurable: false,\n });\n } catch (_) {}\n try {\n Object.defineProperty(window, 'CondorBridge', {\n get: function(){ return undefined; },\n set: function(_){ /* no-op: bloqueia bootstrap do package legado */ },\n configurable: false,\n });\n } catch (_) {}\n try {\n // Neutralize navigator.sendBeacon: an exfiltration channel that CSP\n // connect-src does not reliably block in some WebViews (pen test PT-10).\n // The client communicates only through BridgeClient/postMessage, so it has\n // no legitimate use for sendBeacon. The no-op getter returns a function\n // that answers false; the no-op setter ignores attempts to restore it.\n Object.defineProperty(navigator, 'sendBeacon', {\n get: function(){ return function(){ return false; }; },\n set: function(_){ /* no-op */ },\n configurable: false,\n });\n } catch (_) {}\n})();\n</script>`;\n\nexport interface BridgeShellOptions {\n /**\n * The iframe hosting the client. It may be empty at construction time —\n * `bootstrapClientIframe` is called later to populate it.\n */\n iframe: HTMLIFrameElement;\n\n /**\n * The default-deny policy. Every key and command arriving from the iframe is\n * checked against these lists. See `ShellPolicy`.\n */\n policy: ShellPolicy;\n\n /**\n * Synchronous or asynchronous callback invoked when the client issues a\n * command listed in `policy.requiresConfirmation`. The shell presents its\n * confirmation UI and resolves `true` to approve or `false` to decline.\n *\n * If it is not provided, such commands are **denied** automatically —\n * fail-safe.\n */\n onConfirmationRequest?: (req: ConfirmationRequest) => boolean | Promise<boolean>;\n}\n\nexport class BridgeShell {\n private readonly iframe: HTMLIFrameElement;\n private readonly policy: ShellPolicy;\n private readonly onConfirm?: BridgeShellOptions['onConfirmationRequest'];\n private readonly subscriptions = new Map<BridgeKey, () => void>();\n private detached = false;\n\n /**\n * The native version, fetched once and cached. `null` until the native side\n * answers, and permanently `null` in a browser with no native host.\n */\n private nativeVersion: string | null = null;\n /** In-flight native handshake; guarantees a single call. */\n private nativeHandshake: Promise<void> | null = null;\n\n // Pending `verify-sandbox` round trips, keyed by a generated nonce.\n private pendingVerifies = new Map<\n string,\n {\n resolve: (r: SandboxVerifyResult) => void;\n reject: (e: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n }\n >();\n\n constructor(opts: BridgeShellOptions) {\n this.iframe = opts.iframe;\n this.policy = opts.policy;\n this.onConfirm = opts.onConfirmationRequest;\n if (typeof window !== 'undefined') {\n window.addEventListener('message', this.onMessage);\n }\n }\n\n /**\n * **Layer 1.** Bootstraps by fetching a URL.\n *\n * A shortcut for the common HTTP/HTTPS case: it runs `fetch(clientPath)` and\n * delegates to `bootstrapClientIframeWithHtml`.\n *\n * **It does not work on the `file://` scheme** — Android's Chromium WebView\n * blocks it with \"URL scheme 'file' is not supported\". For an asset bundled\n * in the APK, or a bundle inlined at build time, use\n * `bootstrapClientIframeWithHtml(htmlString)` instead.\n *\n * **Call it once at shell boot**, before any other interaction. After it\n * returns, invoke `verifySandbox()` for attestation (Layer 2).\n */\n async bootstrapClientIframe(clientPath = 'client.html'): Promise<void> {\n const res = await fetch(clientPath);\n if (!res.ok) throw new Error(`BridgeShell: failed to load ${clientPath} (${res.status})`);\n const clientHtml = await res.text();\n await this.bootstrapClientIframeWithHtml(clientHtml);\n }\n\n /**\n * **Layer 1.** Bootstraps from an HTML string.\n *\n * Takes the client HTML directly — already read from a file, embedded at\n * build time, read from storage — and sets it as the iframe's `srcdoc`,\n * prefixed by the override script, which runs at parse time before any\n * client script.\n *\n * Use this when `fetch` does not apply: an asset bundled under `file://`, a\n * bundle inlined at build time, any scenario without network. Android\n * WebView blocks `fetch` on the `file://` scheme, so this is the path the\n * app actually takes. For HTTP, use `bootstrapClientIframe(clientPath)`.\n *\n * **Call it once at shell boot**, before any other interaction. After it\n * returns, invoke `verifySandbox()` for attestation (Layer 2).\n */\n async bootstrapClientIframeWithHtml(clientHtml: string): Promise<void> {\n this.iframe.srcdoc = OVERRIDE_PREFIX + clientHtml;\n await this.waitForIframeLoad();\n }\n\n private waitForIframeLoad(): Promise<void> {\n return new Promise<void>((resolve) => {\n const onLoad = (): void => {\n this.iframe.removeEventListener('load', onLoad);\n resolve();\n };\n this.iframe.addEventListener('load', onLoad);\n });\n }\n\n /**\n * **Layer 2.** A `postMessage` round trip asking the iframe for an\n * authoritative attestation of whether the native globals are reachable.\n * Times out after 2 s.\n *\n * `ok` is `true` only when none of them is reachable. If it comes back\n * `false`, **the shell must abort the app boot**: Layer 1 failed, and client\n * code would run with a path to the native layer.\n */\n verifySandbox(): Promise<SandboxVerifyResult> {\n if (!this.iframe.contentWindow) {\n return Promise.reject(new Error('BridgeShell: iframe has no contentWindow'));\n }\n return new Promise<SandboxVerifyResult>((resolve, reject) => {\n const nonce = Math.random().toString(36).slice(2);\n const timer = setTimeout(() => {\n this.pendingVerifies.delete(nonce);\n reject(new Error(`BridgeShell: verify-sandbox timed out after ${VERIFY_TIMEOUT_MS}ms`));\n }, VERIFY_TIMEOUT_MS);\n this.pendingVerifies.set(nonce, { resolve, reject, timer });\n this.postToClient({ type: 'verify-sandbox' });\n });\n }\n\n /**\n * Tears the shell down: removes the `message` listener, cancels pending\n * subscriptions on the native `Bridge`, and clears internal state.\n */\n detach(): void {\n if (this.detached) return;\n this.detached = true;\n if (typeof window !== 'undefined') {\n window.removeEventListener('message', this.onMessage);\n }\n for (const unsub of this.subscriptions.values()) unsub();\n this.subscriptions.clear();\n for (const pending of this.pendingVerifies.values()) {\n clearTimeout(pending.timer);\n pending.reject(new Error('BridgeShell: detached'));\n }\n this.pendingVerifies.clear();\n }\n\n private onMessage = async (event: MessageEvent): Promise<void> => {\n if (this.detached) return;\n if (event.source !== this.iframe.contentWindow) return;\n\n const parsed = v.safeParse(ClientToShellMessageSchema, event.data);\n if (!parsed.success) {\n // Drop silently — most likely noise (a browser extension, a dev tool).\n // Loga só em modo dev para diagnose.\n if (typeof console !== 'undefined') {\n console.debug('[BridgeShell] dropped malformed message:', parsed.issues?.[0]?.message);\n }\n return;\n }\n\n const msg = parsed.output;\n switch (msg.type) {\n case 'subscribe':\n await this.handleSubscribe(msg.key as BridgeKey);\n break;\n case 'unsubscribe':\n this.handleUnsubscribe(msg.key as BridgeKey);\n break;\n case 'send':\n await this.handleSend(msg.command, msg.args ?? {});\n break;\n case 'handshake':\n // The client handshakes with the **shell**, not the native side: it\n // lives in a sandboxed iframe and cannot reach the native layer. So the\n // shell handshakes with the native side on its behalf and relays\n // `nativeVersion`. Without this a client has no way to know which\n // capabilities it is getting, and the instruction \"check nativeVersion\n // before depending on a new capability\" is impossible to follow.\n void this.resolveNativeVersion().then((nativeVersion) => {\n this.postToClient({\n type: 'handshake-ack',\n ack: { shellVersion: SHELL_VERSION, nativeVersion, accepted: true },\n });\n });\n break;\n case 'jsError':\n // Forward the iframe's JS error to the native side, which routes it\n // to logging.\n Bridge.send('jsError', {\n origin: 'iframe',\n message: msg.payload.message,\n stack: msg.payload.stack,\n source: msg.payload.source,\n lineno: msg.payload.lineno,\n colno: msg.payload.colno,\n });\n break;\n case 'sandbox-verify-response': {\n // Layer 2: the client answered verify-sandbox. Resolve the oldest\n // pending entry — in practice there is only ever one, but the map keeps\n // it robust.\n const first = this.pendingVerifies.keys().next().value;\n if (first !== undefined) {\n const pending = this.pendingVerifies.get(first);\n if (pending) {\n clearTimeout(pending.timer);\n this.pendingVerifies.delete(first);\n // `?? false`: a client on SDK < 0.18.0 does not know the new\n // channel and omits the field — its attestation is weaker, not\n // false.\n const nativeChannelReachable = msg.nativeChannelReachable ?? false;\n const ok =\n !msg.flutterBridgeReachable && !msg.condorBridgeReachable && !nativeChannelReachable;\n pending.resolve({\n flutterBridgeReachable: msg.flutterBridgeReachable,\n condorBridgeReachable: msg.condorBridgeReachable,\n nativeChannelReachable,\n ok,\n });\n }\n }\n break;\n }\n }\n };\n\n private async handleSubscribe(key: BridgeKey): Promise<void> {\n if (!this.policy.readOnlyKeys.includes(key)) {\n this.postToClient({ type: 'nack', key, reason: 'not-read-only' });\n return;\n }\n if (this.subscriptions.has(key)) return; // idempotent\n const unsub = Bridge.on(key, (payload) => {\n if (this.detached) return;\n this.postToClient({ type: 'event', key, payload });\n });\n this.subscriptions.set(key, unsub);\n }\n\n private handleUnsubscribe(key: BridgeKey): void {\n const unsub = this.subscriptions.get(key);\n if (!unsub) return;\n unsub();\n this.subscriptions.delete(key);\n }\n\n private async handleSend(command: string, args: Record<string, unknown>): Promise<void> {\n if (this.policy.deniedCommands.includes(command)) {\n this.postToClient({ type: 'nack', command, reason: 'denied' });\n return;\n }\n if (this.policy.requiresConfirmation.includes(command)) {\n if (!this.onConfirm) {\n // Fail-safe: with no callback, a command requiring confirmation is denied.\n this.postToClient({ type: 'nack', command, reason: 'no-confirmation-handler' });\n return;\n }\n let approved = false;\n try {\n approved = await this.onConfirm({ command, args });\n } catch (err) {\n this.postToClient({\n type: 'nack',\n command,\n reason: `confirmation-error: ${err instanceof Error ? err.message : String(err)}`,\n });\n return;\n }\n if (!approved) {\n this.postToClient({ type: 'nack', command, reason: 'user-rejected' });\n return;\n }\n } else if (!this.policy.allowedCommands.includes(command)) {\n // Comando fora de allowed/denied/requiresConfirmation — drop por default.\n this.postToClient({ type: 'nack', command, reason: 'not-allowed' });\n return;\n }\n Bridge.send(command, args);\n }\n\n /**\n * Resolves `nativeVersion`, firing the native handshake the first time and\n * caching the result.\n *\n * ⚠️ `Bridge.handshake` has **no timeout**: its promise only settles when the\n * native side emits `handshake-ack`. In a browser with no native host it\n * never settles, so the race below is what guarantees the client always gets\n * an answer — `null` — instead of hanging.\n */\n private async resolveNativeVersion(): Promise<string | null> {\n if (this.nativeVersion !== null) return this.nativeVersion;\n if (!this.nativeHandshake) {\n this.nativeHandshake = Bridge.handshake({ clientVersion: SHELL_VERSION })\n .then((ack) => {\n this.nativeVersion = ack.nativeVersion;\n })\n .catch(() => {\n // No native host, or refused: stay `null`, which is honest.\n });\n }\n await Promise.race([\n this.nativeHandshake,\n new Promise<void>((resolve) => setTimeout(resolve, NATIVE_HANDSHAKE_TIMEOUT_MS)),\n ]);\n return this.nativeVersion;\n }\n\n private postToClient(msg: ShellToClientMessage): void {\n if (this.detached) return;\n this.iframe.contentWindow?.postMessage(msg, '*');\n }\n}\n","/**\n * Valibot schemas for the shell↔client `postMessage` protocol.\n *\n * Client content runs inside `<iframe sandbox=\"allow-scripts\">` with a `null`\n * origin, so it talks to the Condor-controlled shell over `window.postMessage`.\n * These schemas are the **only accepted contract** — any malformed message is\n * discarded by the shell in silence, which is why hand-rolled `postMessage`\n * calls appear to do nothing. Use `BridgeClient`.\n *\n * **Threat model:** the iframe may be hostile (a compromised supply chain, XSS\n * in the client code). These schemas plus the `ShellPolicy` enforced by\n * `BridgeShell` form the structural boundary.\n */\n\nimport * as v from 'valibot';\nimport { BRIDGE_KEYS } from './keys';\n\nconst BridgeKeySchema = v.picklist(Object.values(BRIDGE_KEYS) as [string, ...string[]]);\n\n// ─── Client → Shell ──────────────────────────────────────────────────\n\nexport const SubscribeMessage = v.object({\n type: v.literal('subscribe'),\n key: BridgeKeySchema,\n});\n\nexport const UnsubscribeMessage = v.object({\n type: v.literal('unsubscribe'),\n key: BridgeKeySchema,\n});\n\nexport const SendMessage = v.object({\n type: v.literal('send'),\n command: v.string(),\n args: v.optional(v.record(v.string(), v.unknown()), {}),\n});\n\nexport const HandshakeMessage = v.object({\n type: v.literal('handshake'),\n payload: v.object({ clientVersion: v.string() }),\n});\n\nexport const JsErrorMessage = v.object({\n type: v.literal('jsError'),\n payload: v.object({\n message: v.string(),\n stack: v.optional(v.string()),\n source: v.optional(v.string()),\n lineno: v.optional(v.number()),\n colno: v.optional(v.number()),\n }),\n});\n\nexport const SandboxVerifyResponseMessage = v.object({\n type: v.literal('sandbox-verify-response'),\n flutterBridgeReachable: v.boolean(),\n condorBridgeReachable: v.boolean(),\n // Optional: clients on SDK < 0.18.0 do not send it.\n nativeChannelReachable: v.optional(v.boolean()),\n});\n\nexport const ClientToShellMessageSchema = v.variant('type', [\n SubscribeMessage,\n UnsubscribeMessage,\n SendMessage,\n HandshakeMessage,\n JsErrorMessage,\n SandboxVerifyResponseMessage,\n]);\n\n/** Union of every client → shell message. Type only; the runtime schema is `ClientToShellMessageSchema`, which is not part of the public API. */\nexport type ClientToShellMessage = v.InferOutput<typeof ClientToShellMessageSchema>;\n\n// ─── Shell → Client ──────────────────────────────────────────────────\n\nexport const EventMessage = v.object({\n type: v.literal('event'),\n key: BridgeKeySchema,\n payload: v.unknown(),\n});\n\nexport const HandshakeAckMessage = v.object({\n type: v.literal('handshake-ack'),\n ack: v.object({\n shellVersion: v.string(),\n /**\n * Schema version declared by the **native** side, relayed by the shell.\n *\n * `null` when the native side has not answered, or does not exist (browser\n * mock mode). The client runs inside a sandboxed iframe and never talks to\n * the native side directly, so this is the **only** way it can learn which\n * capabilities are available.\n */\n nativeVersion: v.nullable(v.string()),\n accepted: v.boolean(),\n }),\n});\n\nexport const NackMessage = v.object({\n type: v.literal('nack'),\n key: v.optional(v.string()),\n command: v.optional(v.string()),\n reason: v.string(),\n});\n\nexport const VerifySandboxMessage = v.object({\n type: v.literal('verify-sandbox'),\n});\n\nexport const ShellToClientMessageSchema = v.variant('type', [\n EventMessage,\n HandshakeAckMessage,\n NackMessage,\n VerifySandboxMessage,\n]);\n\n/** Union of every shell → client message. Type only; the runtime schema is `ShellToClientMessageSchema`, which is not part of the public API. */\nexport type ShellToClientMessage = v.InferOutput<typeof ShellToClientMessageSchema>;\n\n// ─── Policy ──────────────────────────────────────────────────────────\n\n/**\n * Default-deny policy enforced by `BridgeShell`. Every key and command coming\n * from the iframe is checked against these lists before it touches the native\n * bridge.\n *\n * - `readOnlyKeys` — keys the client may subscribe to.\n * - `allowedCommands` — pass-through commands, no human confirmation.\n * - `requiresConfirmation` — commands that fire the shell's\n * `onConfirmationRequest` callback, so a person approves or declines.\n * - `deniedCommands` — explicit block, defence in depth: destructive commands\n * such as `dfu` that must never flow from the iframe.\n *\n * **Not embedded in the package** — the `BridgeShell` host supplies the\n * concrete policy. That keeps the package agnostic to the catalogue and lets\n * the policy evolve without a release.\n */\nexport interface ShellPolicy {\n readOnlyKeys: string[];\n allowedCommands: string[];\n requiresConfirmation: string[];\n deniedCommands: string[];\n}\n\n/**\n * Argument of the `BridgeShell` `onConfirmationRequest` callback.\n *\n * Resolving `approve: true` lets the command flow to the native side.\n * Resolving `approve: false` makes the shell send the iframe a `nack` with\n * `reason: 'user-rejected'` — which client code only ever sees as a console\n * warning, so the ack it was waiting for simply never arrives.\n */\nexport interface ConfirmationRequest {\n command: string;\n args: Record<string, unknown>;\n}\n\n/**\n * Result of `BridgeShell.verifySandbox()` after a round trip with the iframe.\n * If any `*Reachable` flag comes back `true`, the boundary is leaking: the\n * override prefix injected by `bootstrapClientIframe` failed, and the app must\n * not render client code with a path to the native layer.\n */\nexport interface SandboxVerifyResult {\n flutterBridgeReachable: boolean;\n condorBridgeReachable: boolean;\n /** Whether `window.CondorNative` is visible inside the iframe. */\n nativeChannelReachable: boolean;\n /** `true` only when none of the three is reachable. */\n ok: boolean;\n}\n","/**\n * The shell policy of the Condor Canvas app, reproduced for the development\n * harness so a command the app refuses is refused in the browser too.\n *\n * Mirrors `apps/canvas/web-mock-src/src/shell.ts` (see\n * `contract/bridge-contract.json` → `verifiedAgainst.sources.shellPolicy`).\n * `tests/dev-harness.test.ts` derives the same lists from the contract and\n * fails if they drift.\n */\n\nimport { BRIDGE_KEYS } from '../keys';\nimport type { ShellPolicy } from '../shell-messages';\n\nexport const CANVAS_POLICY: ShellPolicy = {\n readOnlyKeys: [\n BRIDGE_KEYS.userDevice,\n BRIDGE_KEYS.deviceConnection,\n BRIDGE_KEYS.deviceLightSensors,\n BRIDGE_KEYS.deviceNotification,\n BRIDGE_KEYS.pingPong,\n BRIDGE_KEYS.realTime,\n BRIDGE_KEYS.syncTime,\n BRIDGE_KEYS.deleteMemory,\n BRIDGE_KEYS.sensorLog,\n BRIDGE_KEYS.systemStatus,\n BRIDGE_KEYS.navigationBack,\n BRIDGE_KEYS.language,\n ],\n allowedCommands: [\n 'userDevice',\n 'realTime',\n 'openSettings',\n 'deviceConnection',\n 'ping',\n 'jsError',\n 'sensorLog',\n 'setStatusBarColor',\n 'requestPermission',\n 'navigationState',\n 'language',\n ],\n requiresConfirmation: ['syncTime', 'deleteMemory', 'logout'],\n deniedCommands: ['dfu'],\n};\n\n/** CSP of the app shell, inherited by the client's `srcdoc` iframe. */\nexport const CANVAS_CSP =\n \"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; \" +\n \"img-src 'self' data:; font-src 'self' data:; connect-src 'self'; frame-src 'self'; \" +\n \"object-src 'none'; base-uri 'none'; form-action 'none';\";\n","/**\n * Scenarios for the development harness — the device behaviours that a plain\n * \"answer everything at once\" mock hides.\n *\n * Each one reproduces something the Condor Canvas app really does, so a bundle\n * that survives every scenario in the browser survives them on a device.\n */\n\nimport type { SystemStatusPayload, UserDevicePayload } from '../payloads';\nimport { sharedSerial, systemStatus, twoDevices } from './fixtures';\n\n/** Native schema version the harness reports by default. */\nexport const HARNESS_NATIVE_VERSION = '0.17.0';\n\nexport interface Scenario {\n /** Shown in the harness toolbar. */\n description: string;\n /**\n * Relayed to the client by the handshake. `null` reproduces a shell that\n * could not reach the native side: the client receives `nativeVersion: null`.\n */\n nativeVersion: string | null;\n /** Delay of every native reply, in ms. A pair draws uniformly from the range. */\n latencyMs: number | [min: number, max: number];\n /**\n * Time until the app's background service is up, in ms after the page loads.\n * Until then `ping` and `userDevice` are **dropped without a reply** — on\n * the device they travel to that service, and a message sent before it runs\n * is lost.\n */\n serviceStartMs: number;\n /**\n * `userDevice` never answers. Today the app replies only when the device\n * list loads, so an account with no linked device gets silence.\n */\n userDeviceSilent: boolean;\n /** When set, every `sensorLog` reply fails with this `error`. */\n sensorLogError?: string;\n /** Log period of the devices, in seconds (programmable; default 60). */\n logPeriodS: number;\n systemStatus: SystemStatusPayload;\n devices: () => UserDevicePayload;\n}\n\nexport type ScenarioName = 'default' | 'cold-start' | 'no-devices' | 'shared-serial' | 'offline';\n\nconst base: Scenario = {\n description: 'Two devices, background service already running, realistic latency.',\n nativeVersion: HARNESS_NATIVE_VERSION,\n latencyMs: [80, 250],\n serviceStartMs: 0,\n userDeviceSilent: false,\n logPeriodS: 60,\n systemStatus: systemStatus(),\n devices: () => twoDevices(),\n};\n\nexport const SCENARIOS: Record<ScenarioName, Scenario> = {\n default: base,\n 'cold-start': {\n ...base,\n description:\n 'App launched from cold: the background service takes 4 s to start, and ' +\n 'every ping/userDevice sent before that is lost. A bundle that asks once ' +\n 'stays on its loading screen forever.',\n serviceStartMs: 4000,\n },\n 'no-devices': {\n ...base,\n description:\n 'Account with no linked device: userDevice never answers and ' +\n 'systemStatus.hasDevices is false. Your bundle must show an empty state.',\n userDeviceSilent: true,\n systemStatus: systemStatus({ hasDevices: false }),\n },\n 'shared-serial': {\n ...base,\n description:\n 'An ActLumus and an ActLumus Plus share serial number 7047. Only deviceId ' +\n 'tells them apart; sensorLog cannot address one of them.',\n devices: () => sharedSerial(),\n },\n offline: {\n ...base,\n description:\n 'No internet. systemStatus.internet is false and sensorLog fails; ' +\n 'userDevice answers from the cache.',\n sensorLogError: 'Connection failed',\n systemStatus: systemStatus({ internet: false }),\n },\n};\n\nexport function resolveScenario(scenario: ScenarioName | Scenario | undefined): Scenario {\n if (scenario === undefined) return SCENARIOS.default;\n if (typeof scenario === 'string') {\n const found = SCENARIOS[scenario];\n if (!found) {\n throw new Error(\n `condor-mobile-bridge dev: unknown scenario \"${scenario}\". ` +\n `Known: ${Object.keys(SCENARIOS).join(', ')}.`,\n );\n }\n return found;\n }\n return scenario;\n}\n","/**\n * Development harness — runs a client bundle in the browser the way the Condor\n * Canvas app runs it on a device.\n *\n * The bundle goes into a real `<iframe sandbox=\"allow-scripts\">` through the\n * real `BridgeShell`, under the app's policy. Behind the shell, a simulated\n * native side answers commands as the app does — including the parts that\n * hurt: replies lost while the background service starts, silence for an\n * account with no device, latency. Opening `dist/index.html` directly gives\n * none of this, and `BridgeClient` refuses to run there.\n *\n * Use it through the CLI (`npx condor-mobile-bridge dev -i dist/index.html`)\n * or, with your own dev server, from `@condorinst/mobile-bridge/dev`:\n *\n * ```ts\n * import { createDevHarness } from '@condorinst/mobile-bridge/dev';\n * const html = await (await fetch('/index.html')).text();\n * await createDevHarness({ html, scenario: 'cold-start' });\n * ```\n *\n * The harness page is the **top** frame. Never import this module into the\n * bundle itself: `condor-mobile-bridge validate` rejects a bundle that does.\n */\n\nimport { Bridge } from '../bridge';\nimport { BridgeShell } from '../bridge-shell';\nimport { installDevPanel } from '../internal/dev-panel';\nimport type { MockAdapter, MockMessage } from '../internal/mock';\nimport { getActiveAdapter } from '../internal/native';\nimport type { LanguagePayload, SensorLogQueryPayload, SystemStatusPayload } from '../payloads';\nimport type { ConfirmationRequest } from '../shell-messages';\nimport { sensorLogPage } from './fixtures';\nimport { CANVAS_POLICY } from './policy';\nimport { resolveScenario, type Scenario, type ScenarioName } from './scenarios';\n\n/** Marker the `validate` CLI looks for: the harness must never ship in a bundle. */\nexport const DEV_HARNESS_MARKER = '__condorDevHarness__';\n\nexport interface HarnessLogEntry {\n at: number;\n /** `sent`: the bundle's command reached the simulated native side. */\n kind: 'sent' | 'reply' | 'dropped' | 'info';\n command?: string;\n key?: string;\n detail: string;\n}\n\nexport interface DevHarnessOptions {\n /** The bundle's `index.html`, self-contained, as a string. */\n html: string;\n /** A preset name or a full scenario. Defaults to `'default'`. */\n scenario?: ScenarioName | Scenario;\n /** Where the iframe goes. Defaults to `document.body`. */\n mount?: HTMLElement;\n /** Shows the floating dev panel (sent log + manual emit). Defaults to `true`. */\n devPanel?: boolean;\n /**\n * Answers the confirmation the app asks for `syncTime`, `deleteMemory` and\n * `logout`. Defaults to an in-page dialog.\n */\n onConfirmationRequest?: (req: ConfirmationRequest) => boolean | Promise<boolean>;\n /** Called for every harness log entry, besides `console.info`. */\n onLog?: (entry: HarnessLogEntry) => void;\n}\n\nexport interface DevHarness {\n readonly scenario: Scenario;\n readonly iframe: HTMLIFrameElement;\n readonly shell: BridgeShell;\n readonly log: readonly HarnessLogEntry[];\n /** Emits a native event to the bundle, as the app would. */\n emit(key: string, payload: unknown): void;\n /**\n * Presses the OS back button. Emits `navigationBack` only when the bundle\n * last reported `canGoBack: true`, as the app does; otherwise the app keeps\n * the Home and the bundle gets nothing.\n */\n pressBack(): void;\n /** Tears everything down. */\n destroy(): void;\n}\n\ninterface Envelope {\n type?: string;\n payload?: Record<string, unknown>;\n}\n\n/**\n * The simulated native side. Exported for tests; most callers want\n * {@link createDevHarness}.\n */\nexport function createSimulatedNative(\n adapter: MockAdapter,\n scenario: Scenario,\n hooks: { onLog?: (entry: HarnessLogEntry) => void; now?: () => number } = {},\n): {\n readonly log: readonly HarnessLogEntry[];\n pressBack(): void;\n dispose(): void;\n} {\n const now = hooks.now ?? Date.now;\n const startedAt = now();\n const log: HarnessLogEntry[] = [];\n const timers = new Set<ReturnType<typeof setTimeout>>();\n let status: SystemStatusPayload = { ...scenario.systemStatus };\n let canGoBack = false;\n\n const record = (entry: Omit<HarnessLogEntry, 'at'>): void => {\n const full = { at: now(), ...entry };\n log.push(full);\n if (log.length > 500) log.shift();\n hooks.onLog?.(full);\n if (typeof console !== 'undefined') console.info(`[condor dev] ${full.kind}: ${full.detail}`);\n };\n\n const latency = (): number => {\n const l = scenario.latencyMs;\n return Array.isArray(l) ? l[0] + Math.random() * (l[1] - l[0]) : l;\n };\n\n const reply = (key: string, payload: unknown, delay = latency()): void => {\n const timer = setTimeout(() => {\n timers.delete(timer);\n record({ kind: 'reply', key, detail: `${key} → bundle` });\n adapter.triggerEmit(key, payload);\n }, delay);\n timers.add(timer);\n };\n\n const serviceUp = (): boolean => now() - startedAt >= scenario.serviceStartMs;\n\n const language = (): LanguagePayload => {\n const deviceLocale = typeof navigator !== 'undefined' ? navigator.language : 'en-US';\n const lang = deviceLocale.slice(0, 2);\n return {\n deviceLocale,\n appLanguage: null,\n resolvedLanguage: ['en', 'pt', 'de', 'fr'].includes(lang) ? lang : 'en',\n };\n };\n\n const handle = (msg: MockMessage): void => {\n const env = (msg.payload ?? {}) as Envelope;\n const command = env.type ?? '';\n const args = env.payload ?? {};\n if (command !== 'handshake') {\n const shown = JSON.stringify(args);\n const detail =\n shown === '{}'\n ? command\n : `${command} ${shown.length > 160 ? `${shown.slice(0, 157)}...` : shown}`;\n record({ kind: 'sent', command, detail });\n }\n\n switch (command) {\n case 'handshake':\n if (scenario.nativeVersion === null) {\n record({\n kind: 'info',\n detail: 'handshake unanswered: the bundle gets nativeVersion null',\n });\n return;\n }\n reply('handshake-ack', { nativeVersion: scenario.nativeVersion, accepted: true });\n // The app re-emits both right after the handshake (the attach-time\n // emission happened before the bundle existed).\n reply('systemStatus', status, latency() + 20);\n reply('language', language(), latency() + 30);\n return;\n\n case 'ping':\n if (!serviceUp()) {\n record({\n kind: 'dropped',\n command,\n detail: 'ping lost: the background service is not running yet',\n });\n return;\n }\n reply('pingPong', { data: 'pong' });\n return;\n\n case 'userDevice':\n if (!serviceUp()) {\n record({\n kind: 'dropped',\n command,\n detail: 'userDevice lost: the background service is not running yet. Ask again.',\n });\n return;\n }\n if (scenario.userDeviceSilent) {\n record({\n kind: 'dropped',\n command,\n detail:\n 'userDevice unanswered: the account has no linked device (the app replies only on success)',\n });\n return;\n }\n reply('userDevice', scenario.devices());\n return;\n\n case 'sensorLog': {\n const query = args as unknown as SensorLogQueryPayload;\n if (scenario.sensorLogError) {\n reply('sensorLog', {\n requestId: query.requestId,\n success: false,\n error: scenario.sensorLogError,\n });\n return;\n }\n const matches = scenario\n .devices()\n .devicesConfig.filter((d) => d.serialNo === query.serialNo);\n if (matches.length > 1) {\n // sensorLog takes no deviceId: the backend cannot tell the two apart.\n reply('sensorLog', {\n requestId: query.requestId,\n success: false,\n error: 'DEVICE_SERIAL_AMBIGUOUS',\n });\n return;\n }\n const device = matches[0];\n reply(\n 'sensorLog',\n sensorLogPage(query, {\n now: now(),\n periodS: scenario.logPeriodS,\n deviceId: device?.deviceId,\n }),\n );\n return;\n }\n\n case 'realTime':\n reply('realTime', {\n serialNo: args.serialNo,\n ...(args.deviceId !== undefined ? { deviceId: args.deviceId } : {}),\n success: true,\n value: args.value === true,\n });\n return;\n\n case 'syncTime':\n case 'deleteMemory':\n reply(command, {\n serialNo: args.serialNo,\n ...(args.deviceId !== undefined ? { deviceId: args.deviceId } : {}),\n success: true,\n });\n return;\n\n case 'deviceConnection':\n if (args.type === 'add') {\n reply('deviceConnection', {\n serialNo: args.serialNo,\n ...(args.deviceId !== undefined ? { deviceId: args.deviceId } : {}),\n isConnect: true,\n });\n }\n return;\n\n case 'language':\n reply('language', language());\n return;\n\n case 'requestPermission': {\n const name = String(args.permission);\n status = {\n ...status,\n missingEssentialPermissions: status.missingEssentialPermissions.filter((p) => p !== name),\n missingOptionalPermissions: status.missingOptionalPermissions.filter((p) => p !== name),\n };\n reply('systemStatus', status, latency() + 400);\n return;\n }\n\n case 'jsError':\n record({\n kind: 'info',\n command,\n detail: `jsError from the bundle: ${String(args.message)}`,\n });\n return;\n\n case 'logout':\n record({\n kind: 'info',\n command,\n detail: 'logout confirmed: the app would return to its login screen',\n });\n return;\n\n case 'navigationState':\n canGoBack = args.canGoBack === true;\n return;\n\n default:\n // openSettings, setStatusBarColor: no reply by contract.\n return;\n }\n };\n\n const unsubscribe = adapter.onCallHandler(handle);\n if (scenario.serviceStartMs > 0) {\n const timer = setTimeout(() => {\n timers.delete(timer);\n record({ kind: 'info', detail: 'background service is up: ping and userDevice now answer' });\n }, scenario.serviceStartMs);\n timers.add(timer);\n }\n\n return {\n log,\n pressBack(): void {\n if (!canGoBack) {\n record({\n kind: 'info',\n detail: 'OS back: the bundle reported canGoBack false, so the app keeps the Home',\n });\n return;\n }\n reply('navigationBack', {}, 0);\n },\n dispose(): void {\n unsubscribe();\n for (const t of timers) clearTimeout(t);\n timers.clear();\n },\n };\n}\n\nfunction confirmInPage(req: ConfirmationRequest): Promise<boolean> {\n return new Promise((resolve) => {\n const overlay = document.createElement('div');\n overlay.setAttribute(\n 'style',\n 'position:fixed;inset:0;background:rgba(0,0,0,.45);display:flex;align-items:center;' +\n 'justify-content:center;z-index:2147483646;font:14px system-ui,sans-serif',\n );\n const box = document.createElement('div');\n box.setAttribute(\n 'style',\n 'background:#fff;color:#111;border-radius:12px;padding:20px;max-width:320px;' +\n 'box-shadow:0 8px 32px rgba(0,0,0,.3)',\n );\n const text = document.createElement('p');\n text.textContent = `The app asks the person to confirm \"${req.command}\". On a device this is a Condor dialog; if they decline, your bundle receives nothing.`;\n const buttons = document.createElement('div');\n buttons.setAttribute('style', 'display:flex;gap:8px;justify-content:flex-end;margin-top:12px');\n const done = (value: boolean): void => {\n overlay.remove();\n resolve(value);\n };\n for (const [label, value] of [\n ['Decline', false],\n ['Confirm', true],\n ] as const) {\n const button = document.createElement('button');\n button.textContent = label;\n button.addEventListener('click', () => done(value));\n buttons.appendChild(button);\n }\n box.append(text, buttons);\n overlay.appendChild(box);\n document.body.appendChild(overlay);\n });\n}\n\n/**\n * Mounts the bundle in a sandboxed iframe behind the real `BridgeShell` and a\n * simulated native side. See the module comment.\n */\nexport async function createDevHarness(opts: DevHarnessOptions): Promise<DevHarness> {\n if (typeof document === 'undefined') {\n throw new Error(\n 'createDevHarness: needs a DOM (run it in the browser page that hosts the bundle).',\n );\n }\n const adapter = getActiveAdapter();\n if (!adapter.isMock) {\n throw new Error(\n 'createDevHarness: a native host is present; the harness only runs in a plain browser.',\n );\n }\n (globalThis as Record<string, unknown>)[DEV_HARNESS_MARKER] = true;\n\n const scenario = resolveScenario(opts.scenario);\n const native = createSimulatedNative(adapter, scenario, { onLog: opts.onLog });\n\n const iframe = document.createElement('iframe');\n iframe.setAttribute('sandbox', 'allow-scripts');\n iframe.setAttribute('title', 'Condor Canvas bundle');\n iframe.setAttribute('style', 'border:0;width:100%;height:100%;display:block;background:#fff');\n (opts.mount ?? document.body).appendChild(iframe);\n\n const shell = new BridgeShell({\n iframe,\n policy: CANVAS_POLICY,\n onConfirmationRequest: opts.onConfirmationRequest ?? confirmInPage,\n });\n\n if (opts.devPanel !== false) {\n installDevPanel({ adapter, options: { startCollapsed: true } });\n }\n\n await shell.bootstrapClientIframeWithHtml(opts.html);\n try {\n const result = await shell.verifySandbox();\n if (!result.ok) {\n console.error(\n '[condor dev] sandbox verification failed: the app would abort the boot.',\n result,\n );\n }\n } catch (err) {\n console.warn(\n '[condor dev] the bundle did not answer the sandbox probe: its script did not run. Check the console of the iframe for errors, that the page imports BridgeClient, and that the input is self-contained (or let the harness inline it: pass the dist/index.html your bundler wrote).',\n err,\n );\n }\n\n return {\n scenario,\n iframe,\n shell,\n get log() {\n return native.log;\n },\n emit(key, payload) {\n Bridge.mockEmit(key, payload);\n },\n pressBack() {\n native.pressBack();\n },\n destroy() {\n native.dispose();\n shell.detach();\n iframe.remove();\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACqBO,IAAM,uBAAuB;AAEpC,IAAM,MAAM,CAAC,MAAsB,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG;AAGrD,SAAS,qBAAqB,MAAoB;AACvD,SACE,GAAG,KAAK,YAAY,CAAC,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,QAAQ,CAAC,CAAC,IACrE,IAAI,KAAK,SAAS,CAAC,CAAC,IAAI,IAAI,KAAK,WAAW,CAAC,CAAC,IAAI,IAAI,KAAK,WAAW,CAAC,CAAC;AAE/E;AAGO,SAAS,oBAAoB,OAAuB;AACzD,QAAM,IAAI,oDAAoD,KAAK,KAAK;AACxE,MAAI,CAAC,EAAG,QAAO,OAAO;AACtB,QAAM,CAAC,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,MAAM;AAC3C,SAAO,IAAI,KAAK,KAAK,IAAI,MAAM,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC,EAAE,QAAQ;AAClF;AAcA,SAAS,OAAO,MAAoC;AAClD,QAAM,OAAyB;AAAA,IAC7B,UAAU,KAAK;AAAA,IACf,UAAU,KAAK;AAAA,IACf,gBAAgB,KAAK;AAAA,IACrB,qBAAqB;AAAA,IACrB,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,uBAAuB;AAAA,IACvB,gCAAgC;AAAA,IAChC,mBAAmB;AAAA,IACnB,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,qBAAqB;AAAA,EACvB;AACA,MAAI,KAAK,QAAS,MAAK,UAAU,KAAK;AACtC,SAAO;AACT;AAEA,SAAS,UAAU,MAAkB,KAAkC;AACrE,SAAO;AAAA,IACL,UAAU,KAAK;AAAA,IACf,UAAU,KAAK;AAAA,IACf,gBAAgB,MAAM,KAAK,mBAAmB;AAAA,IAC9C,YAAY,KAAK;AAAA,IACjB,eAAe,KAAK,YAAY,kBAAkB,UAAU;AAAA,IAC5D,iBAAiB,KAAK,YAAY,kBAAkB,MAAM;AAAA,IAC1D,gBAAgB,MAAM,KAAK,mBAAmB;AAAA,IAC9C,iBAAiB;AAAA,IACjB,mBAAmB;AAAA,IACnB,cAAc,KAAK;AAAA,IACnB,gBAAgB,MAAM,KAAK,UAAU;AAAA,IACrC,YAAY,KAAK;AAAA,IACjB,UAAU,KAAK;AAAA,IACf,YAAY,KAAK,YACb;AAAA,MACE;AAAA,QACE,UAAU,KAAK;AAAA,QACf,aAAa,MAAM,KAAK;AAAA,QACxB,SAAS,KAAK;AAAA,QACd,aAAa;AAAA,MACf;AAAA,IACF,IACA,CAAC;AAAA,EACP;AACF;AAEA,SAAS,WAAW,MAAwC;AAC1D,SAAO;AAAA,IACL,UAAU,KAAK;AAAA,IACf,UAAU,KAAK;AAAA,IACf,UAAU;AAAA,IACV,UAAU;AAAA,IACV,cAAc;AAAA,IACd,eAAe;AAAA,IACf,kBAAkB;AAAA,EACpB;AACF;AAEA,SAAS,UAAU,OAAqB,MAAM,KAAK,IAAI,GAAsB;AAC3E,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,eAAe,MAAM,IAAI,MAAM;AAAA,IAC/B,kBAAkB,MAAM,IAAI,CAAC,MAAM,UAAU,GAAG,GAAG,CAAC;AAAA,IACpD,mBAAmB,MAAM,IAAI,UAAU;AAAA,EACzC;AACF;AAGO,SAAS,WAAW,MAAM,KAAK,IAAI,GAAsB;AAC9D,SAAO;AAAA,IACL;AAAA,MACE;AAAA,QACE,UAAU;AAAA,QACV,UAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU;AAAA,QACV,MAAM;AAAA,QACN,SAAS;AAAA,QACT,UAAU;AAAA,QACV,kBAAkB;AAAA,MACpB;AAAA,MACA;AAAA,QACE,UAAU;AAAA,QACV,UAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU;AAAA,QACV,MAAM;AAAA,QACN,SAAS;AAAA,QACT,UAAU;AAAA,QACV,kBAAkB;AAAA,QAClB,WAAW;AAAA,MACb;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACF;AAOO,SAAS,aAAa,MAAM,KAAK,IAAI,GAAsB;AAChE,SAAO;AAAA,IACL;AAAA,MACE;AAAA,QACE,UAAU;AAAA,QACV,UAAU;AAAA,QACV,UAAU;AAAA,QACV,MAAM;AAAA,QACN,SAAS;AAAA,QACT,UAAU;AAAA,QACV,kBAAkB;AAAA,MACpB;AAAA,MACA;AAAA,QACE,UAAU;AAAA,QACV,UAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU;AAAA,QACV,MAAM;AAAA,QACN,SAAS;AAAA,QACT,UAAU;AAAA,QACV,kBAAkB;AAAA,MACpB;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,aAAa,YAA0C,CAAC,GAAwB;AAC9F,SAAO;AAAA,IACL,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,4BAA4B,CAAC;AAAA,IAC7B,6BAA6B,CAAC;AAAA,IAC9B,iBAAiB,CAAC;AAAA,IAClB,qBAAqB,CAAC;AAAA,IACtB,GAAG;AAAA,EACL;AACF;AAGA,SAAS,QAAQ,SAAiB,UAA2D;AAC3F,QAAM,IAAI,IAAI,KAAK,OAAO;AAC1B,QAAM,OAAO,EAAE,SAAS,IAAI,EAAE,WAAW,IAAI;AAC7C,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,KAAM,OAAO,KAAK,KAAM,KAAK,EAAE,CAAC;AAClE,QAAM,SAAU,UAAU,MAAS,YAAY,IAAK;AACpD,QAAM,WAAW,KAAK,OAAO,WAAW,OAAO,QAAQ,MAAM,EAAE,IAAI;AACnE,SAAO,EAAE,UAAU,WAAW,KAAK,MAAM,WAAW,OAAO,EAAE,IAAI,GAAG;AACtE;AAEA,SAAS,MAAM,SAAiB,UAAkB,UAAiC;AACjF,QAAM,EAAE,UAAU,UAAU,IAAI,QAAQ,SAAS,QAAQ;AACzD,SAAO;AAAA,IACL,IAAI,KAAK,MAAM,UAAU,GAAI,IAAI,KAAM,WAAW;AAAA,IAClD,UAAU,qBAAqB,IAAI,KAAK,OAAO,CAAC;AAAA,IAChD,UAAU;AAAA,IACV,WAAW;AAAA,IACX,aAAa;AAAA,IACb,cAAc;AAAA,IACd,eAAe;AAAA,IACf,WAAW;AAAA,IACX,cAAc;AAAA,EAChB;AACF;AAEA,IAAM,eAAe;AACrB,IAAM,eAAe,CAAC,YAA4B,QAAQ,OAAO;AACjE,IAAM,eAAe,CAAC,WAA2B,OAAO,OAAO,MAAM,QAAQ,MAAM,CAAC;AAU7E,SAAS,cACd,OACA,OAA8D,CAAC,GAC7C;AAClB,QAAM,MAAM,KAAK,OAAO,KAAK,IAAI;AACjC,QAAM,YAAY,KAAK,WAAW,wBAAwB;AAC1D,QAAM,QAAQ,MAAM,SAAS;AAC7B,MAAI,QAAQ,KAAK,QAAQ,KAAM;AAC7B,WAAO,EAAE,WAAW,MAAM,WAAW,SAAS,OAAO,OAAO,gBAAgB;AAAA,EAC9E;AACA,MAAI,MAAM,iBAAiB,MAAM,cAAc;AAC7C,WAAO,EAAE,WAAW,MAAM,WAAW,SAAS,OAAO,OAAO,sBAAsB;AAAA,EACpF;AAEA,QAAM,SAAS,KAAK,MAAM,MAAM,QAAQ,IAAI;AAC5C,QAAM,SAAS,SAAS,eAAe;AACvC,QAAM,aAAa,MAAM,YAAY,oBAAoB,MAAM,SAAS,IAAI;AAC5E,QAAM,WAAW,MAAM,UAAU,oBAAoB,MAAM,OAAO,IAAI,IAAI;AAC1E,MAAI,OAAO,MAAM,UAAU,KAAK,OAAO,MAAM,QAAQ,KAAK,aAAa,WAAW,GAAG;AACnF,WAAO,EAAE,WAAW,MAAM,WAAW,SAAS,OAAO,OAAO,qBAAqB;AAAA,EACnF;AACA,QAAM,QAAQ,KAAK,IAAI,QAAQ,KAAK,KAAK,aAAa,QAAQ,IAAI,QAAQ;AAC1E,QAAM,OAAO,KAAK,IAAI,QAAQ,KAAK,MAAM,WAAW,QAAQ,IAAI,QAAQ;AAExE,MAAI;AACJ,MAAI;AACJ,MAAI,MAAM,cAAc;AACtB,SAAK,KAAK,IAAI,MAAM,aAAa,MAAM,YAAY,IAAI,QAAQ;AAC/D,WAAO,KAAK,IAAI,OAAO,MAAM,QAAQ,KAAK,QAAQ;AAAA,EACpD,WAAW,MAAM,eAAe;AAC9B,WAAO,KAAK,IAAI,OAAO,aAAa,MAAM,aAAa,IAAI,QAAQ;AACnE,SAAK,KAAK,IAAI,MAAM,QAAQ,QAAQ,KAAK,QAAQ;AAAA,EACnD,WAAW,MAAM,WAAW;AAC1B,WAAO;AACP,SAAK,KAAK,IAAI,MAAM,QAAQ,QAAQ,KAAK,QAAQ;AAAA,EACnD,OAAO;AACL,SAAK;AACL,WAAO,KAAK,IAAI,OAAO,MAAM,QAAQ,KAAK,QAAQ;AAAA,EACpD;AAEA,QAAM,OAAwB,CAAC;AAC/B,WAAS,IAAI,MAAM,KAAK,IAAI,KAAK,UAAU;AACzC,SAAK,KAAK,MAAM,GAAG,MAAM,UAAU,KAAK,YAAY,CAAC,CAAC;AAAA,EACxD;AACA,SAAO;AAAA,IACL,WAAW,MAAM;AAAA,IACjB,SAAS;AAAA,IACT;AAAA,IACA,eAAe,KAAK,SAAS,aAAa,EAAE,IAAI;AAAA,IAChD,cAAc,KAAK,SAAS,aAAa,IAAI,IAAI;AAAA,IACjD,SAAS,KAAK,SAAS,KAAK,KAAK;AAAA,IACjC,aAAa,KAAK,SAAS,KAAK,OAAO;AAAA,EACzC;AACF;;;ACpRO,IAAM,cAAc;AAAA,EACzB,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,oBAAoB;AAAA,EACpB,UAAU;AAAA,EACV,UAAU;AAAA,EACV,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,WAAW;AAAA,EACX,KAAK;AAAA,EACL,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOd,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhB,UAAU;AACZ;;;AClBA,IAAM,WAAW;AACjB,IAAM,sBAAsB;AAuD5B,IAAM,WAA4B;AAAA,EAChC,UAAU;AAAA,EACV,aAAa;AAAA,EACb,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,yBAAyB;AAAA,EACzB,oBAAoB;AACtB;AAEA,SAAS,eAAe,MAAyC;AAC/D,SAAO;AAAA,IACL,UAAU,MAAM,YAAY,SAAS;AAAA,IACrC,aAAa,MAAM,eAAe,SAAS;AAAA,IAC3C,OAAO,MAAM,SAAS,SAAS;AAAA,IAC/B,gBAAgB,MAAM,kBAAkB,SAAS;AAAA,IACjD,yBAAyB,MAAM,2BAA2B,SAAS;AAAA,IACnE,oBAAoB,MAAM,sBAAsB,SAAS;AAAA,EAC3D;AACF;AAEA,SAAS,iBAAiB,IAAiB,MAA6B;AACtE,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,YAA+E;AAAA,IACnF,gBAAgB,EAAE,QAAQ,QAAQ,OAAO,OAAO;AAAA,IAChD,eAAe,EAAE,QAAQ,QAAQ,MAAM,OAAO;AAAA,IAC9C,aAAa,EAAE,KAAK,QAAQ,OAAO,OAAO;AAAA,IAC1C,YAAY,EAAE,KAAK,QAAQ,MAAM,OAAO;AAAA,EAC1C;AACA,SAAO,OAAO,GAAG,OAAO;AAAA,IACtB,UAAU;AAAA,IACV,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,OAAO,SAAS,YAAY;AAAA,IAC5B,YAAY,SAAS,cAAc;AAAA,IACnC,QAAQ,SAAS,mBAAmB;AAAA,IACpC,cAAc;AAAA,IACd,WAAW;AAAA,IACX,UAAU;AAAA,IACV,SAAS;AAAA,IACT,eAAe;AAAA,IACf,GAAG,UAAU,KAAK,QAAQ;AAAA,EAC5B,CAAC;AACH;AAEA,SAAS,YAAY,OAAoB,SAAsB,QAAkC;AAC/F,QAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,SAAO,YAAY;AACnB,SAAO,OAAO,OAAO,OAAO;AAAA,IAC1B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,QAAQ;AAAA,EACV,CAAC;AACD,SAAO,OAAO,MAAM,OAAO;AAAA,IACzB,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,SAAS;AAAA,IACT,cAAc;AAAA,IACd,UAAU;AAAA,IACV,eAAe;AAAA,EACjB,CAAC;AACD,QAAM,cAAc;AACpB,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC3B,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,SAAS;AAAA,EACX,CAAC;AACD,SAAO,OAAO,OAAO,OAAO;AAAA,IAC1B,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,YAAY;AAAA,EACd,CAAC;AACD,SAAO,OAAO,OAAO,SAAS,eAAe,eAAe,GAAG,SAAS,MAAM;AAC9E,SAAO;AACT;AAEA,SAAS,mBAAkE;AACzE,QAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,YAAU,YAAY;AACtB,SAAO,OAAO,UAAU,OAAO;AAAA,IAC7B,SAAS;AAAA,IACT,cAAc;AAAA,IACd,WAAW;AAAA,IACX,WAAW;AAAA,EACb,CAAC;AACD,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,cAAc;AACpB,SAAO,OAAO,MAAM,OAAO,EAAE,SAAS,OAAO,cAAc,OAAO,UAAU,OAAO,CAAC;AACpF,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,OAAK,YAAY;AACjB,YAAU,OAAO,OAAO,IAAI;AAC5B,SAAO,EAAE,WAAW,KAAK;AAC3B;AAEA,SAAS,oBACP,YACA,QACA,SACa;AACb,QAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,YAAU,YAAY;AACtB,SAAO,OAAO,UAAU,OAAO;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,eAAe;AAAA,IACf,KAAK;AAAA,EACP,CAAC;AACD,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,cAAc;AACpB,SAAO,OAAO,MAAM,OAAO,EAAE,SAAS,OAAO,UAAU,OAAO,CAAC;AAE/D,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,YAAY;AACnB,SAAO,OAAO,OAAO,OAAO;AAAA,IAC1B,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,UAAU;AAAA,EACZ,CAAC;AACD,aAAW,OAAO,YAAY;AAC5B,UAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,QAAI,QAAQ;AACZ,QAAI,cAAc;AAClB,WAAO,YAAY,GAAG;AAAA,EACxB;AACA,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,QAAQ;AACf,SAAO,cAAc;AACrB,SAAO,YAAY,MAAM;AAEzB,QAAM,WAAW,SAAS,cAAc,UAAU;AAClD,WAAS,YAAY;AACrB,WAAS,cAAc;AACvB,SAAO,OAAO,SAAS,OAAO;AAAA,IAC5B,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,WAAW;AAAA,IACX,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,SAAO,OAAO,QAAQ,OAAO,EAAE,SAAS,QAAQ,KAAK,MAAM,CAAC;AAE5D,QAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,UAAQ,OAAO;AACf,UAAQ,cAAc;AACtB,UAAQ,YAAY;AACpB,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC3B,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,MAAM;AAAA,EACR,CAAC;AACD,UAAQ,iBAAiB,SAAS,MAAM;AACtC,WAAO,OAAO,OAAO,SAAS,KAAK;AAAA,EACrC,CAAC;AAED,QAAM,WAAW,SAAS,cAAc,QAAQ;AAChD,WAAS,OAAO;AAChB,WAAS,cAAc;AACvB,WAAS,YAAY;AACrB,SAAO,OAAO,SAAS,OAAO;AAAA,IAC5B,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,UAAU;AAAA,EACZ,CAAC;AACD,WAAS,iBAAiB,SAAS,OAAO;AAE1C,UAAQ,OAAO,SAAS,QAAQ;AAChC,YAAU,OAAO,OAAO,QAAQ,UAAU,OAAO;AACjD,SAAO;AACT;AAEA,SAAS,wBACP,gBACA,UACa;AACb,QAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,YAAU,YAAY;AACtB,SAAO,OAAO,UAAU,OAAO;AAAA,IAC7B,SAAS;AAAA,IACT,cAAc;AAAA,IACd,SAAS;AAAA,IACT,eAAe;AAAA,IACf,KAAK;AAAA,EACP,CAAC;AAED,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,cAAc;AACpB,SAAO,OAAO,MAAM,OAAO,EAAE,SAAS,OAAO,UAAU,OAAO,CAAC;AAE/D,QAAM,MAAM,SAAS,cAAc,OAAO;AAC1C,SAAO,OAAO,IAAI,OAAO;AAAA,IACvB,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,WAAW,SAAS,cAAc,OAAO;AAC/C,WAAS,OAAO;AAChB,WAAS,YAAY;AACrB,WAAS,UAAU;AACnB,SAAO,OAAO,SAAS,OAAO;AAAA,IAC5B,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,QAAM,cAAc;AAEpB,WAAS,iBAAiB,UAAU,MAAM;AACxC,aAAS,SAAS,OAAO;AAAA,EAC3B,CAAC;AAED,MAAI,OAAO,UAAU,KAAK;AAC1B,YAAU,OAAO,OAAO,GAAG;AAC3B,SAAO;AACT;AAEA,SAAS,eAAe,MAAmB,SAAsB,KAAmB;AAClF,OAAK,YAAY;AACjB,QAAM,MAAM,QAAQ,YAAY;AAChC,QAAM,OAAO,IAAI,MAAM,CAAC,GAAG,EAAE,QAAQ;AACrC,aAAW,OAAO,MAAM;AACtB,UAAM,MAAM,SAAS,cAAc,KAAK;AACxC,WAAO,OAAO,IAAI,OAAO;AAAA,MACvB,SAAS;AAAA,MACT,cAAc;AAAA,MACd,WAAW;AAAA,IACb,CAAC;AACD,UAAM,KAAK,IAAI,KAAK,IAAI,SAAS,EAAE,mBAAmB;AACtD,UAAM,UAAU,IAAI;AACpB,UAAM,OAAO,SAAS,QAAQ;AAC9B,QAAI,cAAc,GAAG,EAAE,aAAQ,IAAI,KAAK,KAAK,UAAU,IAAI,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;AAChF,SAAK,YAAY,GAAG;AAAA,EACtB;AACF;AAOA,IAAI,eAAsC;AAEnC,SAAS,gBAAgB,QAAuC;AACrE,MAAI,OAAO,aAAa,aAAa;AACnC,UAAM,IAAI,MAAM,wEAAwE;AAAA,EAC1F;AAGA,MAAI,cAAc;AAChB,iBAAa,UAAU;AACvB,mBAAe;AAAA,EACjB;AAEA,QAAM,OAAO,eAAe,OAAO,OAAO;AAC1C,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,OAAK,KAAK;AACV,mBAAiB,MAAM,IAAI;AAE3B,QAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,QAAM,UAAU,SAAS,cAAc,MAAM;AAC7C,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,OAAO;AACd,SAAO,cAAc,KAAK,iBAAiB,MAAM;AACjD,QAAM,SAAS,YAAY,OAAO,SAAS,MAAM;AAEjD,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAO,OAAO,KAAK,OAAO;AAAA,IACxB,SAAS,KAAK,iBAAiB,SAAS;AAAA,IACxC,eAAe;AAAA,IACf,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,EAAE,WAAW,eAAe,MAAM,SAAS,IAAI,iBAAiB;AAGtE,QAAM,SAAS,OAAO,SAAS;AAC/B,MAAI,qBAAqB,KAAK;AAC9B,MAAI,0BAA+C;AAEnD,MAAI,qBAAyC;AAC7C,MAAI,QAAQ;AACV,yBAAqB,wBAAwB,oBAAoB,CAAC,SAAS;AACzE,2BAAqB;AAAA,IACvB,CAAC;AACD,8BAA0B,OAAO,QAAQ,cAAc,CAAC,QAAQ;AAC9D,UAAI,CAAC,mBAAoB;AACzB,UAAI;AACJ,UAAI;AACF,mBAAW,OAAO,GAAG;AAAA,MACvB,SAAS,KAAK;AACZ,gBAAQ,MAAM,gEAAgE,GAAG;AACjF;AAAA,MACF;AACA,UAAI,CAAC,SAAU;AACf,iBAAW,MAAM;AACf,YAAI;AACF,iBAAO,QAAQ,YAAY,SAAS,KAAK,SAAS,OAAO;AAAA,QAC3D,SAAS,KAAK;AACZ,kBAAQ;AAAA,YACN;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF,GAAG,KAAK,kBAAkB;AAAA,IAC5B,CAAC;AAAA,EACH;AAEA,QAAM,UAAU;AAAA,IACd,OAAO,OAAO,WAAW;AAAA,IACzB,CAAC,KAAK,gBAAgB;AACpB,UAAI,UAAmB,CAAC;AACxB,YAAM,UAAU,YAAY,KAAK;AACjC,UAAI,QAAQ,SAAS,GAAG;AACtB,YAAI;AACF,oBAAU,KAAK,MAAM,OAAO;AAAA,QAC9B,SAAS,KAAK;AACZ,kBAAQ,MAAM,yDAAyD,GAAG;AAC1E;AAAA,QACF;AAAA,MACF;AACA,aAAO,QAAQ,YAAY,KAAK,OAAO;AAAA,IACzC;AAAA,IACA,MAAM;AACJ,aAAO,QAAQ,cAAc;AAC7B,qBAAe,UAAU,OAAO,SAAS,KAAK,WAAW;AACzD,cAAQ,cAAc;AAAA,IACxB;AAAA,EACF;AAEA,MAAI,oBAAoB;AACtB,SAAK,OAAO,eAAe,oBAAoB,OAAO;AAAA,EACxD,OAAO;AACL,SAAK,OAAO,eAAe,OAAO;AAAA,EACpC;AACA,OAAK,OAAO,QAAQ,IAAI;AAExB,SAAO,iBAAiB,SAAS,CAAC,MAAM;AACtC,MAAE,gBAAgB;AAClB,UAAM,YAAY,KAAK,MAAM,YAAY;AACzC,SAAK,MAAM,UAAU,YAAY,SAAS;AAC1C,WAAO,cAAc,YAAY,WAAM;AAAA,EACzC,CAAC;AAED,WAAS,KAAK,YAAY,IAAI;AAE9B,QAAM,UAAU,MAAM;AACpB,UAAM,QAAQ,OAAO,QAAQ,YAAY,EAAE;AAC3C,YAAQ,cAAc,GAAG,KAAK;AAC9B,mBAAe,UAAU,OAAO,SAAS,KAAK,WAAW;AAAA,EAC3D;AACA,UAAQ;AAER,QAAM,WAAW,YAAY,SAAS,mBAAmB;AAEzD,QAAM,QAAwB;AAAA,IAC5B,YAAY;AACV,oBAAc,QAAQ;AACtB,gCAA0B;AAC1B,gCAA0B;AAC1B,WAAK,OAAO;AACZ,UAAI,iBAAiB,MAAO,gBAAe;AAAA,IAC7C;AAAA,IACA;AAAA,EACF;AACA,iBAAe;AACf,SAAO;AACT;;;ACzcA,IAAM,aAAa;AAwBZ,SAAS,oBAAiC;AAC/C,QAAM,WAA0B,CAAC;AACjC,QAAM,gBAAgB,oBAAI,IAAgC;AAE1D,SAAO;AAAA,IACL,QAAQ;AAAA,IAER,YAAY,aAAa,SAAS;AAChC,YAAM,MAAmB,EAAE,aAAa,SAAS,WAAW,KAAK,IAAI,EAAE;AACvE,eAAS,KAAK,GAAG;AACjB,UAAI,SAAS,SAAS,YAAY;AAChC,iBAAS,MAAM;AAAA,MACjB;AACA,cAAQ,MAAM,sCAAiC,aAAa,OAAO;AACnE,iBAAW,YAAY,eAAe;AACpC,YAAI;AACF,mBAAS,GAAG;AAAA,QACd,SAAS,KAAK;AACZ,kBAAQ,MAAM,oDAAoD,GAAG;AAAA,QACvE;AAAA,MACF;AAAA,IACF;AAAA,IAEA,cAAc;AACZ,aAAO;AAAA,IACT;AAAA,IAEA,gBAAgB;AACd,eAAS,SAAS;AAAA,IACpB;AAAA,IAEA,YAAY,KAAK,SAAS;AACxB,YAAM,SAAS,OAAO,WAAW,cAAc,OAAO,eAAe;AACrE,UAAI,CAAC,UAAU,OAAO,OAAO,SAAS,YAAY;AAChD,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,aAAO,KAAK,KAAK,OAAO;AAAA,IAC1B;AAAA,IAEA,cAAc,UAAU;AACtB,oBAAc,IAAI,QAAQ;AAC1B,aAAO,MAAM;AACX,sBAAc,OAAO,QAAQ;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AACF;;;ACvCA,IAAI,gBAAsC;AAEnC,SAAS,iBAAiB,OAAmC;AAClE,kBAAgB;AAClB;AASA,IAAI,gBAAsC;AAE1C,SAAS,qBAAqB,SAAqC;AACjE,SAAO;AAAA,IACL,QAAQ;AAAA;AAAA;AAAA,IAGR,YAAY,cAAc,SAAS;AACjC,cAAQ,YAAY,KAAK,UAAU,OAAO,CAAC;AAAA,IAC7C;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB,MAAwC;AACnE,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,YAAY,aAAa,SAAS;AAChC,WAAK,KAAK,YAAY,aAAa,OAAO;AAAA,IAC5C;AAAA,EACF;AACF;AAEA,SAAS,gBAA+B;AACtC,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,kBAAkB;AAAA,EAC3B;AACA,QAAM,UAAU,OAAO;AACvB,MAAI,WAAW,OAAO,QAAQ,gBAAgB,YAAY;AACxD,WAAO,qBAAqB,OAAO;AAAA,EACrC;AACA,QAAM,OAAO,OAAO;AACpB,MAAI,QAAQ,OAAO,KAAK,gBAAgB,YAAY;AAClD,WAAO,oBAAoB,IAAI;AAAA,EACjC;AACA,SAAO,kBAAkB;AAC3B;AAEO,SAAS,mBAAkC;AAChD,MAAI,CAAC,eAAe;AAClB,oBAAgB,cAAc;AAAA,EAChC;AACA,SAAO;AACT;AAgBO,SAAS,WAAW,aAAqB,SAAwC;AACtF,QAAM,UAAU,gBAAgB,cAAc,OAAO,IAAI;AACzD,mBAAiB,EAAE,YAAY,aAAa,OAAO;AACrD;;;ACxHA,IAAM,cAAc,oBAAI,IAA2B;AAE5C,SAAS,cACd,KACA,IACY;AACZ,MAAI,MAAM,YAAY,IAAI,GAAG;AAC7B,MAAI,CAAC,KAAK;AACR,UAAM,oBAAI,IAAc;AACxB,gBAAY,IAAI,KAAK,GAAG;AAAA,EAC1B;AACA,MAAI,IAAI,EAAc;AACtB,SAAO,MAAM;AACX,UAAM,UAAU,YAAY,IAAI,GAAG;AACnC,QAAI,CAAC,QAAS;AACd,YAAQ,OAAO,EAAc;AAC7B,QAAI,QAAQ,SAAS,GAAG;AACtB,kBAAY,OAAO,GAAG;AAAA,IACxB;AAAA,EACF;AACF;AAEO,SAAS,sBAAsB,KAAa,SAAwB;AACzE,QAAM,MAAM,YAAY,IAAI,GAAG;AAC/B,MAAI,CAAC,IAAK;AACV,aAAW,MAAM,KAAK;AACpB,QAAI;AACF,SAAG,OAAO;AAAA,IACZ,SAAS,KAAK;AAEZ,cAAQ,MAAM,0CAA0C,GAAG,YAAY,GAAG;AAAA,IAC5E;AAAA,EACF;AACF;AAmBO,SAAS,oBAA8B;AAC5C,SAAO,MAAM,KAAK,YAAY,KAAK,CAAC;AACtC;;;AC7CA,IAAM,oBAAoB;AAC1B,IAAM,iBAAiB;AACvB,IAAM,mBAAmB;AAiBzB,IAAI,mBAA4C;AAChD,IAAI,qBAAqB;AAEzB,SAAS,KAAK,KAAa,SAAwB;AACjD,MAAI,QAAQ,qBAAqB,kBAAkB;AACjD,UAAM,MAAO,WAAW,CAAC;AACzB,UAAM,WAAW;AACjB,uBAAmB;AACnB,aAAS,QAAQ;AAAA,MACf,eAAe,IAAI,iBAAiB;AAAA,MACpC,UAAU,IAAI,YAAY;AAAA,IAC5B,CAAC;AACD;AAAA,EACF;AACA,wBAAsB,KAAK,OAAO;AACpC;AAEA,SAAS,wBAA8B;AACrC,MAAI,mBAAoB;AACxB,MAAI,OAAO,WAAW,YAAa;AACnC,uBAAqB;AAErB,MAAI,OAAO,gBAAgB,OAAO,OAAO,aAAa,SAAS,YAAY;AAIzE,WAAO,aAAa,OAAO;AAAA,EAC7B,OAAO;AACL,WAAO,eAAe,EAAE,KAAK;AAAA,EAC/B;AACF;AAEA,sBAAsB;AAEtB,SAAS,qBAAkC;AACzC,QAAM,UAAU,iBAAiB;AACjC,MAAI,CAAC,QAAQ,QAAQ;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AA8FO,IAAM,SAAuB;AAAA,EAClC,IAAI,SAAkB;AACpB,WAAO,iBAAiB,EAAE;AAAA,EAC5B;AAAA,EAEA,UAAU,MAA+C;AACvD,0BAAsB;AACtB,QAAI,kBAAkB;AACpB,aAAO,QAAQ;AAAA,QACb,IAAI;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO,IAAI,QAAsB,CAAC,SAAS,WAAW;AACpD,yBAAmB,EAAE,SAAS,OAAO;AACrC,UAAI;AACF,mBAAW,gBAAgB;AAAA,UACzB,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS,EAAE,eAAe,KAAK,cAAc;AAAA,QAC/C,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,2BAAmB;AACnB,eAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,MAC5D;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,GAAwB,KAAQ,IAAiD;AAC/E,0BAAsB;AACtB,WAAO,cAAc,KAAK,EAAE;AAAA,EAC9B;AAAA,EAEA,KAAK,MAAc,SAAyC;AAC1D,eAAW,gBAAgB;AAAA,MACzB;AAAA,MACA,SAAS;AAAA,MACT,SAAS,WAAW,CAAC;AAAA,IACvB,CAAC;AAAA,EACH;AAAA,EAEA,eAAqB;AACnB,SAAK,KAAK,cAAc;AAAA,EAC1B;AAAA,EAEA,iBAAiB,OAAmC;AAClD,qBAAiB,KAAK;AAAA,EACxB;AAAA,EAEA,SAAS,KAAa,SAAyB;AAC7C,uBAAmB,EAAE,YAAY,KAAK,WAAW,CAAC,CAAC;AAAA,EACrD;AAAA,EAEA,eAA0B;AACxB,UAAM,UAAU,mBAAmB;AACnC,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,UAAU,QAAQ,YAAY;AAAA,MAC9B,gBAAgB,kBAAkB;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,gBAAgB,SAAiC;AAC/C,UAAM,UAAU,mBAAmB;AACnC,oBAAwB,EAAE,SAAS,QAAQ,CAAC;AAAA,EAC9C;AACF;;;ACrNA,IAAAA,KAAmB;;;ACTnB,QAAmB;AAGnB,IAAM,kBAAoB,WAAS,OAAO,OAAO,WAAW,CAA0B;AAI/E,IAAM,mBAAqB,SAAO;AAAA,EACvC,MAAQ,UAAQ,WAAW;AAAA,EAC3B,KAAK;AACP,CAAC;AAEM,IAAM,qBAAuB,SAAO;AAAA,EACzC,MAAQ,UAAQ,aAAa;AAAA,EAC7B,KAAK;AACP,CAAC;AAEM,IAAM,cAAgB,SAAO;AAAA,EAClC,MAAQ,UAAQ,MAAM;AAAA,EACtB,SAAW,SAAO;AAAA,EAClB,MAAQ,WAAW,SAAS,SAAO,GAAK,UAAQ,CAAC,GAAG,CAAC,CAAC;AACxD,CAAC;AAEM,IAAM,mBAAqB,SAAO;AAAA,EACvC,MAAQ,UAAQ,WAAW;AAAA,EAC3B,SAAW,SAAO,EAAE,eAAiB,SAAO,EAAE,CAAC;AACjD,CAAC;AAEM,IAAM,iBAAmB,SAAO;AAAA,EACrC,MAAQ,UAAQ,SAAS;AAAA,EACzB,SAAW,SAAO;AAAA,IAChB,SAAW,SAAO;AAAA,IAClB,OAAS,WAAW,SAAO,CAAC;AAAA,IAC5B,QAAU,WAAW,SAAO,CAAC;AAAA,IAC7B,QAAU,WAAW,SAAO,CAAC;AAAA,IAC7B,OAAS,WAAW,SAAO,CAAC;AAAA,EAC9B,CAAC;AACH,CAAC;AAEM,IAAM,+BAAiC,SAAO;AAAA,EACnD,MAAQ,UAAQ,yBAAyB;AAAA,EACzC,wBAA0B,UAAQ;AAAA,EAClC,uBAAyB,UAAQ;AAAA;AAAA,EAEjC,wBAA0B,WAAW,UAAQ,CAAC;AAChD,CAAC;AAEM,IAAM,6BAA+B,UAAQ,QAAQ;AAAA,EAC1D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAOM,IAAM,eAAiB,SAAO;AAAA,EACnC,MAAQ,UAAQ,OAAO;AAAA,EACvB,KAAK;AAAA,EACL,SAAW,UAAQ;AACrB,CAAC;AAEM,IAAM,sBAAwB,SAAO;AAAA,EAC1C,MAAQ,UAAQ,eAAe;AAAA,EAC/B,KAAO,SAAO;AAAA,IACZ,cAAgB,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASvB,eAAiB,WAAW,SAAO,CAAC;AAAA,IACpC,UAAY,UAAQ;AAAA,EACtB,CAAC;AACH,CAAC;AAEM,IAAM,cAAgB,SAAO;AAAA,EAClC,MAAQ,UAAQ,MAAM;AAAA,EACtB,KAAO,WAAW,SAAO,CAAC;AAAA,EAC1B,SAAW,WAAW,SAAO,CAAC;AAAA,EAC9B,QAAU,SAAO;AACnB,CAAC;AAEM,IAAM,uBAAyB,SAAO;AAAA,EAC3C,MAAQ,UAAQ,gBAAgB;AAClC,CAAC;AAEM,IAAM,6BAA+B,UAAQ,QAAQ;AAAA,EAC1D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;;;ADhFD,IAAM,gBAAgB;AAOtB,IAAM,8BAA8B;AACpC,IAAM,oBAAoB;AA6B1B,IAAM,kBAAkB;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;AAiEjB,IAAM,cAAN,MAAkB;AAAA,EAyBvB,YAAY,MAA0B;AArBtC,SAAiB,gBAAgB,oBAAI,IAA2B;AAChE,SAAQ,WAAW;AAMnB;AAAA;AAAA;AAAA;AAAA,SAAQ,gBAA+B;AAEvC;AAAA,SAAQ,kBAAwC;AAGhD;AAAA,SAAQ,kBAAkB,oBAAI,IAO5B;AA0GF,SAAQ,YAAY,OAAO,UAAuC;AAChE,UAAI,KAAK,SAAU;AACnB,UAAI,MAAM,WAAW,KAAK,OAAO,cAAe;AAEhD,YAAM,SAAW,aAAU,4BAA4B,MAAM,IAAI;AACjE,UAAI,CAAC,OAAO,SAAS;AAGnB,YAAI,OAAO,YAAY,aAAa;AAClC,kBAAQ,MAAM,4CAA4C,OAAO,SAAS,CAAC,GAAG,OAAO;AAAA,QACvF;AACA;AAAA,MACF;AAEA,YAAM,MAAM,OAAO;AACnB,cAAQ,IAAI,MAAM;AAAA,QAChB,KAAK;AACH,gBAAM,KAAK,gBAAgB,IAAI,GAAgB;AAC/C;AAAA,QACF,KAAK;AACH,eAAK,kBAAkB,IAAI,GAAgB;AAC3C;AAAA,QACF,KAAK;AACH,gBAAM,KAAK,WAAW,IAAI,SAAS,IAAI,QAAQ,CAAC,CAAC;AACjD;AAAA,QACF,KAAK;AAOH,eAAK,KAAK,qBAAqB,EAAE,KAAK,CAAC,kBAAkB;AACvD,iBAAK,aAAa;AAAA,cAChB,MAAM;AAAA,cACN,KAAK,EAAE,cAAc,eAAe,eAAe,UAAU,KAAK;AAAA,YACpE,CAAC;AAAA,UACH,CAAC;AACD;AAAA,QACF,KAAK;AAGH,iBAAO,KAAK,WAAW;AAAA,YACrB,QAAQ;AAAA,YACR,SAAS,IAAI,QAAQ;AAAA,YACrB,OAAO,IAAI,QAAQ;AAAA,YACnB,QAAQ,IAAI,QAAQ;AAAA,YACpB,QAAQ,IAAI,QAAQ;AAAA,YACpB,OAAO,IAAI,QAAQ;AAAA,UACrB,CAAC;AACD;AAAA,QACF,KAAK,2BAA2B;AAI9B,gBAAM,QAAQ,KAAK,gBAAgB,KAAK,EAAE,KAAK,EAAE;AACjD,cAAI,UAAU,QAAW;AACvB,kBAAM,UAAU,KAAK,gBAAgB,IAAI,KAAK;AAC9C,gBAAI,SAAS;AACX,2BAAa,QAAQ,KAAK;AAC1B,mBAAK,gBAAgB,OAAO,KAAK;AAIjC,oBAAM,yBAAyB,IAAI,0BAA0B;AAC7D,oBAAM,KACJ,CAAC,IAAI,0BAA0B,CAAC,IAAI,yBAAyB,CAAC;AAChE,sBAAQ,QAAQ;AAAA,gBACd,wBAAwB,IAAI;AAAA,gBAC5B,uBAAuB,IAAI;AAAA,gBAC3B;AAAA,gBACA;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF;AACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AArLE,SAAK,SAAS,KAAK;AACnB,SAAK,SAAS,KAAK;AACnB,SAAK,YAAY,KAAK;AACtB,QAAI,OAAO,WAAW,aAAa;AACjC,aAAO,iBAAiB,WAAW,KAAK,SAAS;AAAA,IACnD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,sBAAsB,aAAa,eAA8B;AACrE,UAAM,MAAM,MAAM,MAAM,UAAU;AAClC,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,+BAA+B,UAAU,KAAK,IAAI,MAAM,GAAG;AACxF,UAAM,aAAa,MAAM,IAAI,KAAK;AAClC,UAAM,KAAK,8BAA8B,UAAU;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,8BAA8B,YAAmC;AACrE,SAAK,OAAO,SAAS,kBAAkB;AACvC,UAAM,KAAK,kBAAkB;AAAA,EAC/B;AAAA,EAEQ,oBAAmC;AACzC,WAAO,IAAI,QAAc,CAAC,YAAY;AACpC,YAAM,SAAS,MAAY;AACzB,aAAK,OAAO,oBAAoB,QAAQ,MAAM;AAC9C,gBAAQ;AAAA,MACV;AACA,WAAK,OAAO,iBAAiB,QAAQ,MAAM;AAAA,IAC7C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,gBAA8C;AAC5C,QAAI,CAAC,KAAK,OAAO,eAAe;AAC9B,aAAO,QAAQ,OAAO,IAAI,MAAM,0CAA0C,CAAC;AAAA,IAC7E;AACA,WAAO,IAAI,QAA6B,CAAC,SAAS,WAAW;AAC3D,YAAM,QAAQ,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC;AAChD,YAAM,QAAQ,WAAW,MAAM;AAC7B,aAAK,gBAAgB,OAAO,KAAK;AACjC,eAAO,IAAI,MAAM,+CAA+C,iBAAiB,IAAI,CAAC;AAAA,MACxF,GAAG,iBAAiB;AACpB,WAAK,gBAAgB,IAAI,OAAO,EAAE,SAAS,QAAQ,MAAM,CAAC;AAC1D,WAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAAA,IAC9C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAe;AACb,QAAI,KAAK,SAAU;AACnB,SAAK,WAAW;AAChB,QAAI,OAAO,WAAW,aAAa;AACjC,aAAO,oBAAoB,WAAW,KAAK,SAAS;AAAA,IACtD;AACA,eAAW,SAAS,KAAK,cAAc,OAAO,EAAG,OAAM;AACvD,SAAK,cAAc,MAAM;AACzB,eAAW,WAAW,KAAK,gBAAgB,OAAO,GAAG;AACnD,mBAAa,QAAQ,KAAK;AAC1B,cAAQ,OAAO,IAAI,MAAM,uBAAuB,CAAC;AAAA,IACnD;AACA,SAAK,gBAAgB,MAAM;AAAA,EAC7B;AAAA,EAkFA,MAAc,gBAAgB,KAA+B;AAC3D,QAAI,CAAC,KAAK,OAAO,aAAa,SAAS,GAAG,GAAG;AAC3C,WAAK,aAAa,EAAE,MAAM,QAAQ,KAAK,QAAQ,gBAAgB,CAAC;AAChE;AAAA,IACF;AACA,QAAI,KAAK,cAAc,IAAI,GAAG,EAAG;AACjC,UAAM,QAAQ,OAAO,GAAG,KAAK,CAAC,YAAY;AACxC,UAAI,KAAK,SAAU;AACnB,WAAK,aAAa,EAAE,MAAM,SAAS,KAAK,QAAQ,CAAC;AAAA,IACnD,CAAC;AACD,SAAK,cAAc,IAAI,KAAK,KAAK;AAAA,EACnC;AAAA,EAEQ,kBAAkB,KAAsB;AAC9C,UAAM,QAAQ,KAAK,cAAc,IAAI,GAAG;AACxC,QAAI,CAAC,MAAO;AACZ,UAAM;AACN,SAAK,cAAc,OAAO,GAAG;AAAA,EAC/B;AAAA,EAEA,MAAc,WAAW,SAAiB,MAA8C;AACtF,QAAI,KAAK,OAAO,eAAe,SAAS,OAAO,GAAG;AAChD,WAAK,aAAa,EAAE,MAAM,QAAQ,SAAS,QAAQ,SAAS,CAAC;AAC7D;AAAA,IACF;AACA,QAAI,KAAK,OAAO,qBAAqB,SAAS,OAAO,GAAG;AACtD,UAAI,CAAC,KAAK,WAAW;AAEnB,aAAK,aAAa,EAAE,MAAM,QAAQ,SAAS,QAAQ,0BAA0B,CAAC;AAC9E;AAAA,MACF;AACA,UAAI,WAAW;AACf,UAAI;AACF,mBAAW,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;AAAA,MACnD,SAAS,KAAK;AACZ,aAAK,aAAa;AAAA,UAChB,MAAM;AAAA,UACN;AAAA,UACA,QAAQ,uBAAuB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QACjF,CAAC;AACD;AAAA,MACF;AACA,UAAI,CAAC,UAAU;AACb,aAAK,aAAa,EAAE,MAAM,QAAQ,SAAS,QAAQ,gBAAgB,CAAC;AACpE;AAAA,MACF;AAAA,IACF,WAAW,CAAC,KAAK,OAAO,gBAAgB,SAAS,OAAO,GAAG;AAEzD,WAAK,aAAa,EAAE,MAAM,QAAQ,SAAS,QAAQ,cAAc,CAAC;AAClE;AAAA,IACF;AACA,WAAO,KAAK,SAAS,IAAI;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAc,uBAA+C;AAC3D,QAAI,KAAK,kBAAkB,KAAM,QAAO,KAAK;AAC7C,QAAI,CAAC,KAAK,iBAAiB;AACzB,WAAK,kBAAkB,OAAO,UAAU,EAAE,eAAe,cAAc,CAAC,EACrE,KAAK,CAAC,QAAQ;AACb,aAAK,gBAAgB,IAAI;AAAA,MAC3B,CAAC,EACA,MAAM,MAAM;AAAA,MAEb,CAAC;AAAA,IACL;AACA,UAAM,QAAQ,KAAK;AAAA,MACjB,KAAK;AAAA,MACL,IAAI,QAAc,CAAC,YAAY,WAAW,SAAS,2BAA2B,CAAC;AAAA,IACjF,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,aAAa,KAAiC;AACpD,QAAI,KAAK,SAAU;AACnB,SAAK,OAAO,eAAe,YAAY,KAAK,GAAG;AAAA,EACjD;AACF;;;AEjaO,IAAM,gBAA6B;AAAA,EACxC,cAAc;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,EACd;AAAA,EACA,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,sBAAsB,CAAC,YAAY,gBAAgB,QAAQ;AAAA,EAC3D,gBAAgB,CAAC,KAAK;AACxB;AAGO,IAAM,aACX;;;ACnCK,IAAM,yBAAyB;AAkCtC,IAAM,OAAiB;AAAA,EACrB,aAAa;AAAA,EACb,eAAe;AAAA,EACf,WAAW,CAAC,IAAI,GAAG;AAAA,EACnB,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,YAAY;AAAA,EACZ,cAAc,aAAa;AAAA,EAC3B,SAAS,MAAM,WAAW;AAC5B;AAEO,IAAM,YAA4C;AAAA,EACvD,SAAS;AAAA,EACT,cAAc;AAAA,IACZ,GAAG;AAAA,IACH,aACE;AAAA,IAGF,gBAAgB;AAAA,EAClB;AAAA,EACA,cAAc;AAAA,IACZ,GAAG;AAAA,IACH,aACE;AAAA,IAEF,kBAAkB;AAAA,IAClB,cAAc,aAAa,EAAE,YAAY,MAAM,CAAC;AAAA,EAClD;AAAA,EACA,iBAAiB;AAAA,IACf,GAAG;AAAA,IACH,aACE;AAAA,IAEF,SAAS,MAAM,aAAa;AAAA,EAC9B;AAAA,EACA,SAAS;AAAA,IACP,GAAG;AAAA,IACH,aACE;AAAA,IAEF,gBAAgB;AAAA,IAChB,cAAc,aAAa,EAAE,UAAU,MAAM,CAAC;AAAA,EAChD;AACF;AAEO,SAAS,gBAAgB,UAAyD;AACvF,MAAI,aAAa,OAAW,QAAO,UAAU;AAC7C,MAAI,OAAO,aAAa,UAAU;AAChC,UAAM,QAAQ,UAAU,QAAQ;AAChC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI;AAAA,QACR,+CAA+C,QAAQ,aAC3C,OAAO,KAAK,SAAS,EAAE,KAAK,IAAI,CAAC;AAAA,MAC/C;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;ACrEO,IAAM,qBAAqB;AAuD3B,SAAS,sBACd,SACA,UACA,QAA0E,CAAC,GAK3E;AACA,QAAM,MAAM,MAAM,OAAO,KAAK;AAC9B,QAAM,YAAY,IAAI;AACtB,QAAM,MAAyB,CAAC;AAChC,QAAM,SAAS,oBAAI,IAAmC;AACtD,MAAI,SAA8B,EAAE,GAAG,SAAS,aAAa;AAC7D,MAAI,YAAY;AAEhB,QAAMC,UAAS,CAAC,UAA6C;AAC3D,UAAM,OAAO,EAAE,IAAI,IAAI,GAAG,GAAG,MAAM;AACnC,QAAI,KAAK,IAAI;AACb,QAAI,IAAI,SAAS,IAAK,KAAI,MAAM;AAChC,UAAM,QAAQ,IAAI;AAClB,QAAI,OAAO,YAAY,YAAa,SAAQ,KAAK,gBAAgB,KAAK,IAAI,KAAK,KAAK,MAAM,EAAE;AAAA,EAC9F;AAEA,QAAM,UAAU,MAAc;AAC5B,UAAM,IAAI,SAAS;AACnB,WAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,OAAO,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK;AAAA,EACnE;AAEA,QAAM,QAAQ,CAAC,KAAa,SAAkB,QAAQ,QAAQ,MAAY;AACxE,UAAM,QAAQ,WAAW,MAAM;AAC7B,aAAO,OAAO,KAAK;AACnB,MAAAA,QAAO,EAAE,MAAM,SAAS,KAAK,QAAQ,GAAG,GAAG,iBAAY,CAAC;AACxD,cAAQ,YAAY,KAAK,OAAO;AAAA,IAClC,GAAG,KAAK;AACR,WAAO,IAAI,KAAK;AAAA,EAClB;AAEA,QAAM,YAAY,MAAe,IAAI,IAAI,aAAa,SAAS;AAE/D,QAAM,WAAW,MAAuB;AACtC,UAAM,eAAe,OAAO,cAAc,cAAc,UAAU,WAAW;AAC7E,UAAM,OAAO,aAAa,MAAM,GAAG,CAAC;AACpC,WAAO;AAAA,MACL;AAAA,MACA,aAAa;AAAA,MACb,kBAAkB,CAAC,MAAM,MAAM,MAAM,IAAI,EAAE,SAAS,IAAI,IAAI,OAAO;AAAA,IACrE;AAAA,EACF;AAEA,QAAM,SAAS,CAAC,QAA2B;AACzC,UAAM,MAAO,IAAI,WAAW,CAAC;AAC7B,UAAM,UAAU,IAAI,QAAQ;AAC5B,UAAM,OAAO,IAAI,WAAW,CAAC;AAC7B,QAAI,YAAY,aAAa;AAC3B,YAAM,QAAQ,KAAK,UAAU,IAAI;AACjC,YAAM,SACJ,UAAU,OACN,UACA,GAAG,OAAO,IAAI,MAAM,SAAS,MAAM,GAAG,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,KAAK;AAC5E,MAAAA,QAAO,EAAE,MAAM,QAAQ,SAAS,OAAO,CAAC;AAAA,IAC1C;AAEA,YAAQ,SAAS;AAAA,MACf,KAAK;AACH,YAAI,SAAS,kBAAkB,MAAM;AACnC,UAAAA,QAAO;AAAA,YACL,MAAM;AAAA,YACN,QAAQ;AAAA,UACV,CAAC;AACD;AAAA,QACF;AACA,cAAM,iBAAiB,EAAE,eAAe,SAAS,eAAe,UAAU,KAAK,CAAC;AAGhF,cAAM,gBAAgB,QAAQ,QAAQ,IAAI,EAAE;AAC5C,cAAM,YAAY,SAAS,GAAG,QAAQ,IAAI,EAAE;AAC5C;AAAA,MAEF,KAAK;AACH,YAAI,CAAC,UAAU,GAAG;AAChB,UAAAA,QAAO;AAAA,YACL,MAAM;AAAA,YACN;AAAA,YACA,QAAQ;AAAA,UACV,CAAC;AACD;AAAA,QACF;AACA,cAAM,YAAY,EAAE,MAAM,OAAO,CAAC;AAClC;AAAA,MAEF,KAAK;AACH,YAAI,CAAC,UAAU,GAAG;AAChB,UAAAA,QAAO;AAAA,YACL,MAAM;AAAA,YACN;AAAA,YACA,QAAQ;AAAA,UACV,CAAC;AACD;AAAA,QACF;AACA,YAAI,SAAS,kBAAkB;AAC7B,UAAAA,QAAO;AAAA,YACL,MAAM;AAAA,YACN;AAAA,YACA,QACE;AAAA,UACJ,CAAC;AACD;AAAA,QACF;AACA,cAAM,cAAc,SAAS,QAAQ,CAAC;AACtC;AAAA,MAEF,KAAK,aAAa;AAChB,cAAM,QAAQ;AACd,YAAI,SAAS,gBAAgB;AAC3B,gBAAM,aAAa;AAAA,YACjB,WAAW,MAAM;AAAA,YACjB,SAAS;AAAA,YACT,OAAO,SAAS;AAAA,UAClB,CAAC;AACD;AAAA,QACF;AACA,cAAM,UAAU,SACb,QAAQ,EACR,cAAc,OAAO,CAAC,MAAM,EAAE,aAAa,MAAM,QAAQ;AAC5D,YAAI,QAAQ,SAAS,GAAG;AAEtB,gBAAM,aAAa;AAAA,YACjB,WAAW,MAAM;AAAA,YACjB,SAAS;AAAA,YACT,OAAO;AAAA,UACT,CAAC;AACD;AAAA,QACF;AACA,cAAM,SAAS,QAAQ,CAAC;AACxB;AAAA,UACE;AAAA,UACA,cAAc,OAAO;AAAA,YACnB,KAAK,IAAI;AAAA,YACT,SAAS,SAAS;AAAA,YAClB,UAAU,QAAQ;AAAA,UACpB,CAAC;AAAA,QACH;AACA;AAAA,MACF;AAAA,MAEA,KAAK;AACH,cAAM,YAAY;AAAA,UAChB,UAAU,KAAK;AAAA,UACf,GAAI,KAAK,aAAa,SAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;AAAA,UACjE,SAAS;AAAA,UACT,OAAO,KAAK,UAAU;AAAA,QACxB,CAAC;AACD;AAAA,MAEF,KAAK;AAAA,MACL,KAAK;AACH,cAAM,SAAS;AAAA,UACb,UAAU,KAAK;AAAA,UACf,GAAI,KAAK,aAAa,SAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;AAAA,UACjE,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MAEF,KAAK;AACH,YAAI,KAAK,SAAS,OAAO;AACvB,gBAAM,oBAAoB;AAAA,YACxB,UAAU,KAAK;AAAA,YACf,GAAI,KAAK,aAAa,SAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;AAAA,YACjE,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AACA;AAAA,MAEF,KAAK;AACH,cAAM,YAAY,SAAS,CAAC;AAC5B;AAAA,MAEF,KAAK,qBAAqB;AACxB,cAAM,OAAO,OAAO,KAAK,UAAU;AACnC,iBAAS;AAAA,UACP,GAAG;AAAA,UACH,6BAA6B,OAAO,4BAA4B,OAAO,CAAC,MAAM,MAAM,IAAI;AAAA,UACxF,4BAA4B,OAAO,2BAA2B,OAAO,CAAC,MAAM,MAAM,IAAI;AAAA,QACxF;AACA,cAAM,gBAAgB,QAAQ,QAAQ,IAAI,GAAG;AAC7C;AAAA,MACF;AAAA,MAEA,KAAK;AACH,QAAAA,QAAO;AAAA,UACL,MAAM;AAAA,UACN;AAAA,UACA,QAAQ,4BAA4B,OAAO,KAAK,OAAO,CAAC;AAAA,QAC1D,CAAC;AACD;AAAA,MAEF,KAAK;AACH,QAAAA,QAAO;AAAA,UACL,MAAM;AAAA,UACN;AAAA,UACA,QAAQ;AAAA,QACV,CAAC;AACD;AAAA,MAEF,KAAK;AACH,oBAAY,KAAK,cAAc;AAC/B;AAAA,MAEF;AAEE;AAAA,IACJ;AAAA,EACF;AAEA,QAAM,cAAc,QAAQ,cAAc,MAAM;AAChD,MAAI,SAAS,iBAAiB,GAAG;AAC/B,UAAM,QAAQ,WAAW,MAAM;AAC7B,aAAO,OAAO,KAAK;AACnB,MAAAA,QAAO,EAAE,MAAM,QAAQ,QAAQ,2DAA2D,CAAC;AAAA,IAC7F,GAAG,SAAS,cAAc;AAC1B,WAAO,IAAI,KAAK;AAAA,EAClB;AAEA,SAAO;AAAA,IACL;AAAA,IACA,YAAkB;AAChB,UAAI,CAAC,WAAW;AACd,QAAAA,QAAO;AAAA,UACL,MAAM;AAAA,UACN,QAAQ;AAAA,QACV,CAAC;AACD;AAAA,MACF;AACA,YAAM,kBAAkB,CAAC,GAAG,CAAC;AAAA,IAC/B;AAAA,IACA,UAAgB;AACd,kBAAY;AACZ,iBAAW,KAAK,OAAQ,cAAa,CAAC;AACtC,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AACF;AAEA,SAAS,cAAc,KAA4C;AACjE,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,IAEF;AACA,UAAM,MAAM,SAAS,cAAc,KAAK;AACxC,QAAI;AAAA,MACF;AAAA,MACA;AAAA,IAEF;AACA,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,cAAc,uCAAuC,IAAI,OAAO;AACrE,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,aAAa,SAAS,+DAA+D;AAC7F,UAAM,OAAO,CAAC,UAAyB;AACrC,cAAQ,OAAO;AACf,cAAQ,KAAK;AAAA,IACf;AACA,eAAW,CAAC,OAAO,KAAK,KAAK;AAAA,MAC3B,CAAC,WAAW,KAAK;AAAA,MACjB,CAAC,WAAW,IAAI;AAAA,IAClB,GAAY;AACV,YAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,aAAO,cAAc;AACrB,aAAO,iBAAiB,SAAS,MAAM,KAAK,KAAK,CAAC;AAClD,cAAQ,YAAY,MAAM;AAAA,IAC5B;AACA,QAAI,OAAO,MAAM,OAAO;AACxB,YAAQ,YAAY,GAAG;AACvB,aAAS,KAAK,YAAY,OAAO;AAAA,EACnC,CAAC;AACH;AAMA,eAAsB,iBAAiB,MAA8C;AACnF,MAAI,OAAO,aAAa,aAAa;AACnC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,UAAU,iBAAiB;AACjC,MAAI,CAAC,QAAQ,QAAQ;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,EAAC,WAAuC,kBAAkB,IAAI;AAE9D,QAAM,WAAW,gBAAgB,KAAK,QAAQ;AAC9C,QAAM,SAAS,sBAAsB,SAAS,UAAU,EAAE,OAAO,KAAK,MAAM,CAAC;AAE7E,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,aAAa,WAAW,eAAe;AAC9C,SAAO,aAAa,SAAS,sBAAsB;AACnD,SAAO,aAAa,SAAS,+DAA+D;AAC5F,GAAC,KAAK,SAAS,SAAS,MAAM,YAAY,MAAM;AAEhD,QAAM,QAAQ,IAAI,YAAY;AAAA,IAC5B;AAAA,IACA,QAAQ;AAAA,IACR,uBAAuB,KAAK,yBAAyB;AAAA,EACvD,CAAC;AAED,MAAI,KAAK,aAAa,OAAO;AAC3B,oBAAgB,EAAE,SAAS,SAAS,EAAE,gBAAgB,KAAK,EAAE,CAAC;AAAA,EAChE;AAEA,QAAM,MAAM,8BAA8B,KAAK,IAAI;AACnD,MAAI;AACF,UAAM,SAAS,MAAM,MAAM,cAAc;AACzC,QAAI,CAAC,OAAO,IAAI;AACd,cAAQ;AAAA,QACN;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,KAAK;AACZ,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,IAAI,MAAM;AACR,aAAO,OAAO;AAAA,IAChB;AAAA,IACA,KAAK,KAAK,SAAS;AACjB,aAAO,SAAS,KAAK,OAAO;AAAA,IAC9B;AAAA,IACA,YAAY;AACV,aAAO,UAAU;AAAA,IACnB;AAAA,IACA,UAAU;AACR,aAAO,QAAQ;AACf,YAAM,OAAO;AACb,aAAO,OAAO;AAAA,IAChB;AAAA,EACF;AACF;","names":["v","record"]}
|