@ubercode/dcmtk 0.13.2 → 0.15.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/dist/dicom.cjs +50 -36
- package/dist/dicom.cjs.map +1 -1
- package/dist/dicom.js +50 -36
- package/dist/dicom.js.map +1 -1
- package/dist/{index-Bve4fMIh.d.cts → index-CtqMUrjP.d.cts} +2 -0
- package/dist/{index-CZiFWENk.d.ts → index-D7nnTY1R.d.ts} +2 -0
- package/dist/index.cjs +193 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +193 -66
- package/dist/index.js.map +1 -1
- package/dist/servers.cjs +41 -7
- package/dist/servers.cjs.map +1 -1
- package/dist/servers.d.cts +1 -1
- package/dist/servers.d.ts +1 -1
- package/dist/servers.js +41 -7
- package/dist/servers.js.map +1 -1
- package/dist/tools.cjs +57 -40
- package/dist/tools.cjs.map +1 -1
- package/dist/tools.d.cts +18 -1
- package/dist/tools.d.ts +18 -1
- package/dist/tools.js +57 -41
- package/dist/tools.js.map +1 -1
- package/package.json +1 -1
package/dist/servers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/constants.ts","../src/DcmtkProcess.ts","../src/parsers/LineParser.ts","../src/patterns.ts","../src/findDcmtkPath.ts","../src/tools/_resolveBinary.ts","../src/tools/_toolError.ts","../src/events/dcmrecv.ts","../src/servers/AssociationTracker.ts","../src/servers/Dcmrecv.ts","../src/events/storescp.ts","../src/servers/StoreSCP.ts","../src/utils/fs.ts","../src/brands.ts","../src/dicom/tagPath.ts","../src/dicom/walkTags.ts","../src/dicom/DicomDataset.ts","../src/dicom/ChangeSet.ts","../src/exec.ts","../src/tools/_xmlToJson.ts","../src/tools/_repairJson.ts","../src/tools/dcm2json.ts","../src/tools/dcmodify.ts","../src/dicom/_fileHelpers.ts","../src/dicom/DicomInstance.ts","../src/servers/DicomReceiver.ts","../src/events/dcmprscp.ts","../src/servers/DcmprsCP.ts","../src/events/dcmpsrcv.ts","../src/servers/Dcmpsrcv.ts","../src/events/dcmqrscp.ts","../src/servers/DcmQRSCP.ts","../src/events/wlmscpfs.ts","../src/servers/Wlmscpfs.ts"],"names":["EventEmitter","stderr","isWindows","binaryName","join","path","parser","z","buildArgs","kill","spawn","rm","VERBOSITY_FLAGS","copyFile","stat","unlink","delay","buildNetworkArgs"],"mappings":"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","file":"servers.js","sourcesContent":["/**\n * Represents the outcome of an operation that can succeed or fail.\n *\n * @typeParam T - The type of the success value\n * @typeParam E - The type of the error (defaults to Error)\n *\n * @example\n * ```ts\n * function divide(a: number, b: number): Result<number> {\n * if (b === 0) {\n * return err(new Error('Division by zero'));\n * }\n * return ok(a / b);\n * }\n *\n * const result = divide(10, 2);\n * if (result.ok) {\n * console.log(result.value); // 5\n * } else {\n * console.error(result.error.message);\n * }\n * ```\n */\ntype Result<T, E = Error> = { readonly ok: true; readonly value: T } | { readonly ok: false; readonly error: E };\n\n/**\n * Creates a successful Result containing the given value.\n *\n * @param value - The success value to wrap\n * @returns A Result representing success\n *\n * @example\n * ```ts\n * const result = ok(42);\n * // result.ok === true, result.value === 42\n * ```\n */\nfunction ok<T>(value: T): Result<T, never> {\n return { ok: true, value };\n}\n\n/**\n * Creates a failed Result containing the given error.\n *\n * @param error - The error to wrap\n * @returns A Result representing failure\n *\n * @example\n * ```ts\n * const result = err(new Error('not found'));\n * // result.ok === false, result.error.message === 'not found'\n * ```\n */\nfunction err<E>(error: E): Result<never, E> {\n return { ok: false, error };\n}\n\n/**\n * Exhaustive check helper for discriminated unions and switch statements.\n * Calling this in a default case ensures all variants are handled at compile time.\n *\n * @param x - A value that should be of type `never` if all cases are handled\n * @returns Never returns; always throws\n * @throws Always throws an Error indicating an unhandled case\n *\n * @example\n * ```ts\n * type Shape = { kind: 'circle' } | { kind: 'square' };\n *\n * function area(shape: Shape): number {\n * switch (shape.kind) {\n * case 'circle': return Math.PI;\n * case 'square': return 1;\n * default: assertUnreachable(shape);\n * }\n * }\n * ```\n */\nfunction assertUnreachable(x: never): never {\n throw new Error(`Exhaustive check failed: ${JSON.stringify(x)}`);\n}\n\n// ---------------------------------------------------------------------------\n// Process result types (Rule 7.1: immutable)\n// ---------------------------------------------------------------------------\n\n/**\n * The result of executing a short-lived DCMTK binary.\n * All properties are readonly to enforce immutability.\n */\ninterface DcmtkProcessResult {\n /** The captured stdout output from the process. */\n readonly stdout: string;\n /** The captured stderr output from the process. */\n readonly stderr: string;\n /** The exit code of the process (0 typically means success). */\n readonly exitCode: number;\n}\n\n// ---------------------------------------------------------------------------\n// Common option types (Rule 8.4: options objects for > 4 params)\n// ---------------------------------------------------------------------------\n\n/**\n * Options for short-lived DCMTK process execution.\n * Provides configurable timeout and abort support per Rule 4.2.\n */\ninterface ExecOptions {\n /** Working directory for the child process. */\n readonly cwd?: string | undefined;\n /** Timeout in milliseconds. Defaults to DEFAULT_TIMEOUT_MS. */\n readonly timeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n/**\n * Options for spawning a DCMTK process with user-supplied arguments.\n * Uses spawn() instead of exec() to avoid shell injection (Rule 7.4).\n */\ninterface SpawnOptions extends ExecOptions {\n /** Additional environment variables merged with process.env. */\n readonly env?: Readonly<Record<string, string>> | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Event types (Rule 8.3: discriminated unions)\n// ---------------------------------------------------------------------------\n\n/**\n * Line source discriminant for output parsing.\n */\ntype LineSource = 'stdout' | 'stderr';\n\n/**\n * A single line of output from a DCMTK process.\n */\ninterface ProcessLine {\n readonly source: LineSource;\n readonly text: string;\n}\n\n// ---------------------------------------------------------------------------\n// Result utility functions\n// ---------------------------------------------------------------------------\n\n/**\n * Transforms the success value of a Result, passing through errors unchanged.\n *\n * @param result - The Result to transform\n * @param fn - The transformation function\n * @returns A new Result with the transformed value, or the original error\n *\n * @example\n * ```ts\n * const result = ok(42);\n * const doubled = mapResult(result, x => x * 2);\n * // doubled.ok === true, doubled.value === 84\n * ```\n */\nfunction mapResult<T, U>(result: Result<T>, fn: (value: T) => U): Result<U> {\n if (result.ok) {\n return ok(fn(result.value));\n }\n return result;\n}\n\n/**\n * Extracts the success type from a Result.\n * Useful for extracting branded types from factory function returns.\n *\n * @example\n * ```ts\n * type Tag = ResultValue<ReturnType<typeof createDicomTag>>; // DicomTag\n * ```\n */\ntype ResultValue<R> = R extends Result<infer T> ? T : never;\n\nexport { ok, err, assertUnreachable, mapResult };\nexport type { Result, ResultValue, DcmtkProcessResult, ExecOptions, SpawnOptions, LineSource, ProcessLine };\n","/**\n * Application-wide constants.\n *\n * All values use `as const` assertions per Rule 3.5 (no traditional enums).\n * All bounds are documented per Rule 8.1 (bounded loops/buffers).\n *\n * @module constants\n */\n\n// ---------------------------------------------------------------------------\n// Timeouts (Rule 4.2: mandatory timeouts on all async operations)\n// ---------------------------------------------------------------------------\n\n/** Default timeout for short-lived process execution (30 seconds). */\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/** Default timeout for long-lived process startup (10 seconds). */\nconst DEFAULT_START_TIMEOUT_MS = 10_000;\n\n/** Default timeout for graceful shutdown drain (5 seconds). */\nconst DEFAULT_DRAIN_TIMEOUT_MS = 5_000;\n\n/** Default timeout for multi-line block accumulation in line parser (1 second). */\nconst DEFAULT_BLOCK_TIMEOUT_MS = 1_000;\n\n// ---------------------------------------------------------------------------\n// DICOM network constants\n// ---------------------------------------------------------------------------\n\n/** DICOM protocol default PDU sizes. */\nconst PDU_SIZE = {\n /** Default maximum PDU receive size (16 KB). */\n DEFAULT: 16_384,\n /** Minimum allowed PDU size (4 KB). */\n MIN: 4_096,\n /** Maximum allowed PDU size (128 KB). */\n MAX: 131_072,\n} as const;\n\n/** Default DICOM port used by DCMTK tools. */\nconst DEFAULT_DICOM_PORT = 104;\n\n// ---------------------------------------------------------------------------\n// Platform-specific known DCMTK install paths\n// ---------------------------------------------------------------------------\n\n/** Known DCMTK binary locations on Windows. */\nconst WINDOWS_SEARCH_PATHS = ['C:\\\\Program Files\\\\DCMTK\\\\bin', 'C:\\\\Program Files (x86)\\\\DCMTK\\\\bin', 'C:\\\\ProgramData\\\\chocolatey\\\\bin'] as const;\n\n/** Known DCMTK binary locations on Unix/macOS. */\nconst UNIX_SEARCH_PATHS = ['/usr/local/bin', '/usr/bin', '/opt/local/bin', '/opt/homebrew/bin'] as const;\n\n// ---------------------------------------------------------------------------\n// Required DCMTK binaries (minimum set for core functionality)\n// ---------------------------------------------------------------------------\n\n/** Binaries that must be present for the library to function. */\nconst REQUIRED_BINARIES = ['dcm2json', 'dcm2xml', 'dcmodify', 'dcmdump', 'dcmrecv', 'dcmsend', 'echoscu'] as const;\n\n// ---------------------------------------------------------------------------\n// Bounded limits (Rule 8.1: all loops and buffers must have upper bounds)\n// ---------------------------------------------------------------------------\n\n/** Maximum lines accumulated in multi-line block parser. */\nconst MAX_BLOCK_LINES = 1_000;\n\n/** Maximum number of event patterns a line parser can hold. */\nconst MAX_EVENT_PATTERNS = 200;\n\n/** Maximum loop iterations for iterative traversal (e.g., nested sequences). */\nconst MAX_TRAVERSAL_DEPTH = 50;\n\n/** Maximum number of operations (modifications + erasures) in a single ChangeSet. */\nconst MAX_CHANGESET_OPERATIONS = 10_000;\n\n/** Maximum bytes allowed for stdout + stderr buffering (100 MB). */\nconst MAX_OUTPUT_BYTES = 100 * 1024 * 1024;\n\nexport {\n DEFAULT_TIMEOUT_MS,\n DEFAULT_START_TIMEOUT_MS,\n DEFAULT_DRAIN_TIMEOUT_MS,\n DEFAULT_BLOCK_TIMEOUT_MS,\n PDU_SIZE,\n DEFAULT_DICOM_PORT,\n WINDOWS_SEARCH_PATHS,\n UNIX_SEARCH_PATHS,\n REQUIRED_BINARIES,\n MAX_BLOCK_LINES,\n MAX_EVENT_PATTERNS,\n MAX_TRAVERSAL_DEPTH,\n MAX_CHANGESET_OPERATIONS,\n MAX_OUTPUT_BYTES,\n};\n","/**\n * Base class for long-lived DCMTK processes (servers).\n *\n * Manages spawning, line-by-line output buffering, typed event emission,\n * lifecycle (start/stop), mandatory timeouts, and graceful shutdown.\n *\n * Implements `Disposable` for deterministic cleanup (Rule 5.1).\n *\n * @module DcmtkProcess\n */\n\nimport { EventEmitter } from 'node:events';\nimport { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport { stderr } from 'stderr-lib';\nimport kill from 'tree-kill';\nimport type { Result, LineSource } from './types';\nimport { ok, err } from './types';\nimport { DEFAULT_START_TIMEOUT_MS, DEFAULT_DRAIN_TIMEOUT_MS, MAX_OUTPUT_BYTES } from './constants';\n\n// ---------------------------------------------------------------------------\n// Event types\n// ---------------------------------------------------------------------------\n\n/** Events emitted by a DcmtkProcess. */\ninterface DcmtkProcessEventMap {\n started: [];\n stopped: [{ readonly reason: string }];\n error: [{ readonly error: Error; readonly fatal: boolean }];\n line: [{ readonly source: LineSource; readonly text: string }];\n}\n\n/** Configuration for a DcmtkProcess instance. */\ninterface DcmtkProcessConfig {\n /** Full path to the DCMTK binary. */\n readonly binary: string;\n /** Command-line arguments. */\n readonly args: readonly string[];\n /** Working directory. */\n readonly cwd?: string | undefined;\n /** Timeout for start() to resolve, in milliseconds. */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop(), in milliseconds. */\n readonly drainTimeoutMs?: number | undefined;\n /**\n * A function that inspects each output line and returns `true` when\n * the process is considered \"started\" (e.g., \"listening on port X\").\n * If not provided, start() resolves immediately after spawn.\n */\n readonly isStartedPredicate?: ((line: string) => boolean) | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// State enum (as const, not traditional enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\nconst ProcessState = {\n IDLE: 'IDLE',\n STARTING: 'STARTING',\n RUNNING: 'RUNNING',\n STOPPING: 'STOPPING',\n STOPPED: 'STOPPED',\n} as const;\n\ntype ProcessStateValue = (typeof ProcessState)[keyof typeof ProcessState];\n\n// ---------------------------------------------------------------------------\n// DcmtkProcess class\n// ---------------------------------------------------------------------------\n\n/**\n * Base class for persistent DCMTK processes (e.g., dcmrecv, storescp).\n *\n * @example\n * ```ts\n * const proc = new DcmtkProcess({\n * binary: '/usr/local/bin/dcmrecv',\n * args: ['--config', 'storescp.cfg', '11112'],\n * isStartedPredicate: line => line.includes('listening'),\n * });\n *\n * const result = await proc.start();\n * if (result.ok) {\n * // Process is running\n * proc.on('line', ({ source, text }) => console.log(`[${source}] ${text}`));\n * }\n *\n * await proc.stop();\n * ```\n */\nclass DcmtkProcess extends EventEmitter<DcmtkProcessEventMap> {\n private state: ProcessStateValue = ProcessState.IDLE;\n private child: ChildProcess | null = null;\n private stdoutBuffer = '';\n private stderrBuffer = '';\n private readonly config: DcmtkProcessConfig;\n\n constructor(config: DcmtkProcessConfig) {\n super();\n // Servers can have up to ~15 event types plus internal listeners;\n // raise above the default 10 to avoid MaxListenersExceeded warnings.\n this.setMaxListeners(20);\n this.config = config;\n // Prevent unhandled 'error' events from crashing the process (Node.js\n // throws if 'error' is emitted with no listener). Consumers should\n // register their own 'error' listener before calling start() to receive\n // errors. Startup errors are also returned via Result from start().\n this.on('error', () => {});\n }\n\n /** Whether the process is currently running. */\n get isRunning(): boolean {\n return this.state === ProcessState.RUNNING;\n }\n\n /** Current process state. */\n get currentState(): ProcessStateValue {\n return this.state;\n }\n\n /**\n * Starts the DCMTK process.\n *\n * Single-use enforcement: returns an error if called more than once.\n * Waits for the `isStartedPredicate` to match an output line, or resolves\n * immediately after spawn if no predicate is configured.\n *\n * @returns A Result indicating success or failure\n */\n async start(): Promise<Result<void>> {\n if (this.state !== ProcessState.IDLE) {\n return err(new Error(`Cannot start: process is in state \"${this.state}\"`));\n }\n this.state = ProcessState.STARTING;\n const timeoutMs = this.config.startTimeoutMs ?? DEFAULT_START_TIMEOUT_MS;\n\n return new Promise<Result<void>>(resolve => {\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n this.state = ProcessState.STOPPED;\n this.killChild();\n resolve(err(new Error(`Process failed to start within ${timeoutMs}ms`)));\n }, timeoutMs);\n\n // Safe from races: Node.js is single-threaded, so the `settled`\n // flag check + set is atomic within each event handler invocation.\n const settle = (result: Result<void>): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(result);\n };\n\n try {\n this.child = spawn(this.config.binary, [...this.config.args], {\n cwd: this.config.cwd,\n windowsHide: true,\n });\n /* v8 ignore start -- spawn() rarely throws synchronously */\n } catch (e: unknown) {\n settle(err(new Error(`Failed to spawn process: ${stderr(e).message}`)));\n return;\n }\n /* v8 ignore stop */\n this.wireChildEvents(settle);\n });\n }\n\n /**\n * Stops the process gracefully.\n *\n * Waits up to `drainTimeoutMs` for the process to exit, then force-kills.\n */\n async stop(): Promise<void> {\n if (this.state === ProcessState.STOPPED || this.state === ProcessState.IDLE) {\n return;\n }\n\n this.state = ProcessState.STOPPING;\n const drainMs = this.config.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS;\n\n return new Promise<void>(resolve => {\n /* v8 ignore next 4 -- drain timeout is a safety net for unresponsive processes */\n const timer = setTimeout(() => {\n this.killChild();\n this.state = ProcessState.STOPPED;\n resolve();\n }, drainMs);\n\n // Safe: Node.js is single-threaded, so `this.child` cannot become null\n // between the check and the `.once('close', ...)` registration. The\n // drain timeout handles the edge case where the child exits before\n // the close listener is registered.\n if (this.child) {\n this.child.once('close', () => {\n clearTimeout(timer);\n this.state = ProcessState.STOPPED;\n resolve();\n });\n this.killChild();\n /* v8 ignore start -- edge case: state is RUNNING but child is already null */\n } else {\n clearTimeout(timer);\n this.state = ProcessState.STOPPED;\n resolve();\n }\n /* v8 ignore stop */\n });\n }\n\n /**\n * Implements Disposable for deterministic cleanup (Rule 5.1).\n */\n [Symbol.dispose](): void {\n if (this.child) {\n this.killChild();\n this.child = null;\n }\n this.state = ProcessState.STOPPED;\n this.removeAllListeners();\n }\n\n // -----------------------------------------------------------------------\n // Private helpers\n // -----------------------------------------------------------------------\n\n private killChild(): void {\n if (this.child?.pid !== undefined && this.child.pid !== null) {\n try {\n kill(this.child.pid);\n /* v8 ignore next */\n } catch {\n // Process may already be dead\n }\n }\n }\n\n /**\n * Wires all child process event handlers for startup.\n */\n private wireChildEvents(settle: (result: Result<void>) => void): void {\n const child = this.child;\n if (!child) return;\n\n child.on('error', (error: Error) => {\n this.emit('error', { error, fatal: true });\n if (this.state === ProcessState.STARTING) {\n this.state = ProcessState.STOPPED;\n settle(err(new Error(`Process error during start: ${error.message}`)));\n }\n });\n\n child.on('close', (code: number | null) => {\n const prevState = this.state;\n this.state = ProcessState.STOPPED;\n this.child = null;\n const reason = `Process exited with code ${String(code ?? 'null')}`;\n this.emit('stopped', { reason });\n if (prevState === ProcessState.STARTING) settle(err(new Error(reason)));\n });\n\n child.stdout?.on('data', (chunk: Buffer | string) => {\n this.handleData('stdout', chunk);\n });\n child.stderr?.on('data', (chunk: Buffer | string) => {\n this.handleData('stderr', chunk);\n });\n\n child.on('spawn', () => {\n if (!this.config.isStartedPredicate) {\n this.state = ProcessState.RUNNING;\n this.emit('started');\n settle(ok(undefined));\n }\n });\n\n if (this.config.isStartedPredicate) {\n this.wireStartedPredicate(settle);\n }\n }\n\n /**\n * Wires a line listener that resolves start() when the predicate matches.\n */\n private wireStartedPredicate(settle: (result: Result<void>) => void): void {\n const onLine = ({ text }: { readonly source: LineSource; readonly text: string }): void => {\n if (this.config.isStartedPredicate?.(text)) {\n this.removeListener('line', onLine);\n this.state = ProcessState.RUNNING;\n this.emit('started');\n settle(ok(undefined));\n }\n };\n this.on('line', onLine);\n }\n\n private handleData(source: LineSource, chunk: Buffer | string): void {\n if (source === 'stdout') {\n this.stdoutBuffer += String(chunk);\n } else {\n this.stderrBuffer += String(chunk);\n }\n\n if (this.stdoutBuffer.length + this.stderrBuffer.length > MAX_OUTPUT_BYTES) {\n this.emit('error', { error: new Error(`Process output exceeded ${MAX_OUTPUT_BYTES} bytes`), fatal: true });\n this.killChild();\n return;\n }\n\n this.processLines(source, source === 'stdout' ? 'stdoutBuffer' : 'stderrBuffer');\n }\n\n private processLines(source: LineSource, bufferKey: 'stdoutBuffer' | 'stderrBuffer'): void {\n // Handle bare \\r (CR-only) line endings by converting to \\n\n this[bufferKey] = this[bufferKey].replace(/\\r(?!\\n)/g, '\\n');\n\n let newlineIdx = this[bufferKey].indexOf('\\n');\n\n // Iterative line extraction — no recursion (Rule 8.2)\n while (newlineIdx !== -1) {\n const current = this[bufferKey];\n const line = current.substring(0, newlineIdx).replace(/\\r$/, '');\n this[bufferKey] = current.substring(newlineIdx + 1);\n this.emit('line', { source, text: line });\n newlineIdx = this[bufferKey].indexOf('\\n');\n }\n }\n}\n\nexport { DcmtkProcess, ProcessState };\nexport type { DcmtkProcessEventMap, DcmtkProcessConfig, ProcessStateValue };\n","/**\n * Line-by-line parser for DCMTK process output.\n *\n * Matches output lines against registered EventPattern objects and emits\n * structured events. Supports both single-line and multi-line block matching.\n *\n * All algorithms are iterative (Rule 8.2: no recursion).\n * All buffers are bounded (Rule 8.1).\n *\n * @module parsers/LineParser\n */\n\nimport { EventEmitter } from 'node:events';\nimport { stderr } from 'stderr-lib';\nimport type { EventPattern } from './EventPattern';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { MAX_BLOCK_LINES, MAX_EVENT_PATTERNS, DEFAULT_BLOCK_TIMEOUT_MS } from '../constants';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Events emitted by the LineParser. */\ninterface LineParserEventMap {\n /** Emitted when a pattern matches. Carries the event name and extracted data. */\n match: [{ readonly event: string; readonly data: unknown }];\n /** Emitted when a multi-line block times out before the footer is matched. Consumers should listen for this event to detect and handle incomplete blocks. */\n blockTimeout: [{ readonly event: string; readonly lines: readonly string[] }];\n /** Emitted when a pattern processor throws. */\n error: [Error];\n}\n\n/** Tracks the state of an in-progress multi-line block. */\ninterface BlockState {\n readonly pattern: EventPattern;\n readonly lines: string[];\n readonly timer: ReturnType<typeof setTimeout>;\n}\n\n// ---------------------------------------------------------------------------\n// LineParser class\n// ---------------------------------------------------------------------------\n\n/**\n * Parses DCMTK output lines against registered event patterns.\n *\n * @example\n * ```ts\n * const parser = new LineParser();\n * parser.addPattern({\n * event: 'LISTENING',\n * pattern: /listening on port (\\d+)/i,\n * processor: match => ({ port: Number(match[1]) }),\n * });\n *\n * parser.on('match', ({ event, data }) => {\n * console.log(`${event}:`, data);\n * });\n *\n * parser.feed('I: listening on port 11112');\n * // Emits: match { event: 'LISTENING', data: { port: 11112 } }\n * ```\n */\nclass LineParser extends EventEmitter<LineParserEventMap> {\n private readonly patterns: EventPattern[] = [];\n private activeBlock: BlockState | null = null;\n\n constructor() {\n super();\n // LineParser is used internally and the number of patterns can be\n // large — disable the listener limit (0 = unlimited) to avoid\n // MaxListenersExceeded warnings.\n this.setMaxListeners(0);\n // Prevent unhandled 'error' events from crashing the process.\n // Consumers should register their own 'error' listener.\n this.on('error', () => {});\n }\n\n /**\n * Registers an event pattern.\n *\n * @param pattern - The pattern to register\n * @returns Result indicating success or failure if pattern limit exceeded\n */\n addPattern(pattern: EventPattern): Result<void> {\n if (this.patterns.length >= MAX_EVENT_PATTERNS) {\n return err(new Error(`Maximum event patterns (${MAX_EVENT_PATTERNS}) exceeded`));\n }\n this.patterns.push(pattern);\n return ok(undefined);\n }\n\n /**\n * Feeds a single line of output to the parser.\n *\n * The line is matched against all registered patterns (iteratively, Rule 8.2).\n * If a multi-line block is active, the line is accumulated until the footer matches.\n *\n * @param line - A single line of DCMTK output (without trailing newline)\n */\n feed(line: string): void {\n // If a multi-line block is active, accumulate lines\n if (this.activeBlock !== null) {\n this.feedToBlock(line);\n return;\n }\n\n // Check for multi-line block headers first\n for (let i = 0; i < this.patterns.length; i++) {\n const pattern = this.patterns[i];\n /* v8 ignore next -- safety guard for noUncheckedIndexedAccess */\n if (pattern === undefined) continue;\n\n if (pattern.multiLine) {\n const headerMatch = pattern.multiLine.header.exec(line);\n if (headerMatch) {\n this.startBlock(pattern, line);\n return;\n }\n }\n }\n\n // Check single-line patterns\n this.matchSingleLine(line);\n }\n\n /**\n * Feeds multiple lines of output (e.g., from a chunk split by newlines).\n *\n * @param lines - Array of lines to process\n */\n feedLines(lines: readonly string[]): void {\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line !== undefined) {\n this.feed(line);\n }\n }\n }\n\n /**\n * Resets the parser state, clearing any active multi-line block.\n */\n reset(): void {\n if (this.activeBlock !== null) {\n clearTimeout(this.activeBlock.timer);\n this.activeBlock = null;\n }\n }\n\n /**\n * Implements Disposable for cleanup (Rule 5.1).\n */\n [Symbol.dispose](): void {\n this.reset();\n this.removeAllListeners();\n }\n\n // -----------------------------------------------------------------------\n // Private helpers\n // -----------------------------------------------------------------------\n\n private matchSingleLine(line: string): void {\n for (let i = 0; i < this.patterns.length; i++) {\n const pattern = this.patterns[i];\n /* v8 ignore next -- safety guard for noUncheckedIndexedAccess */\n if (pattern === undefined) continue;\n\n // Skip multi-line-only patterns for single-line matching\n if (pattern.multiLine) continue;\n\n const match = pattern.pattern.exec(line);\n if (match) {\n try {\n const data = pattern.processor(match);\n this.emit('match', { event: pattern.event, data });\n } catch (thrown: unknown) {\n this.emit('error', stderr(thrown));\n }\n return; // First match wins\n }\n }\n }\n\n private startBlock(pattern: EventPattern, headerLine: string): void {\n /* v8 ignore next -- multiLine is always defined when startBlock is called */\n const timeoutMs = pattern.multiLine?.timeoutMs ?? DEFAULT_BLOCK_TIMEOUT_MS;\n\n const timer = setTimeout(() => {\n if (this.activeBlock !== null) {\n const lines = [...this.activeBlock.lines];\n const evt = this.activeBlock.pattern.event;\n this.activeBlock = null;\n this.emit('blockTimeout', { event: evt, lines });\n }\n }, timeoutMs);\n\n this.activeBlock = {\n pattern,\n lines: [headerLine],\n timer,\n };\n }\n\n private feedToBlock(line: string): void {\n /* v8 ignore next -- safety guard: activeBlock is always set when feedToBlock is called */\n if (this.activeBlock === null) return;\n\n const { pattern, lines, timer } = this.activeBlock;\n /* v8 ignore next -- multiLine is always defined for block patterns */\n const maxLines = pattern.multiLine?.maxLines ?? MAX_BLOCK_LINES;\n\n lines.push(line);\n\n // Check footer\n if (pattern.multiLine?.footer.test(line)) {\n clearTimeout(timer);\n const blockText = lines.join('\\n');\n const match = pattern.pattern.exec(blockText);\n this.activeBlock = null;\n\n if (match) {\n try {\n const data = pattern.processor(match);\n this.emit('match', { event: pattern.event, data });\n } catch (thrown: unknown) {\n this.emit('error', stderr(thrown));\n }\n }\n return;\n }\n\n // Enforce bounded accumulation (Rule 8.1)\n if (lines.length >= maxLines) {\n clearTimeout(timer);\n const evt = pattern.event;\n const accumulated = [...lines];\n this.activeBlock = null;\n this.emit('blockTimeout', { event: evt, lines: accumulated });\n }\n }\n}\n\nexport { LineParser };\nexport type { LineParserEventMap };\n","/**\n * Shared validation regex patterns and constants.\n *\n * Centralises all DICOM-related validation patterns so that brands,\n * validation schemas, and server modules reference a single source\n * of truth rather than maintaining duplicated copies.\n *\n * @module patterns\n */\n\n// ---------------------------------------------------------------------------\n// DICOM tag and UID patterns\n// ---------------------------------------------------------------------------\n\n/** Matches a DICOM tag in `(XXXX,XXXX)` format where X is a hex digit. */\nconst DICOM_TAG_PATTERN = /^\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)$/;\n\n/** Matches a DICOM AE Title: printable ASCII excluding backslash (DICOM PS3.5 default repertoire). */\nconst AE_TITLE_PATTERN = /^[\\x20-\\x5b\\x5d-\\x7e]+$/;\n\n/**\n * Matches a dotted numeric OID (e.g. `1.2.840.10008`).\n *\n * Note: This intentionally accepts any syntactically valid dotted-numeric form.\n * DICOM PS3.5 §9.1 requires UIDs start with a non-zero root (e.g., `0.0.0` is\n * technically invalid), but real-world DICOM datasets contain such UIDs, so we\n * validate syntax only and leave semantic UID validation to the application layer.\n */\nconst UID_PATTERN = /^[0-9]+(\\.[0-9]+)*$/;\n\n/** Matches a single DICOM tag path segment with optional array index. */\nconst TAG_PATH_SEGMENT = /\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)(\\[\\d+\\])?/;\n\n/** Matches a full dot-separated DICOM tag path (e.g. `(0040,A730)[0].(0010,0010)`). */\nconst DICOM_TAG_PATH_PATTERN = new RegExp(`^${TAG_PATH_SEGMENT.source}(\\\\.${TAG_PATH_SEGMENT.source})*$`);\n\n// ---------------------------------------------------------------------------\n// Validation constants\n// ---------------------------------------------------------------------------\n\n/** Minimum length for an AE Title. */\nconst AE_TITLE_MIN_LENGTH = 1;\n\n/** Maximum length for an AE Title. */\nconst AE_TITLE_MAX_LENGTH = 16;\n\n/** Maximum length for a DICOM UID. */\nconst UID_MAX_LENGTH = 64;\n\n/** Minimum valid network port number. */\nconst PORT_MIN = 1;\n\n/** Maximum valid network port number. */\nconst PORT_MAX = 65535;\n\n// ---------------------------------------------------------------------------\n// DICOM query key patterns\n// ---------------------------------------------------------------------------\n\n/**\n * Matches a valid DICOM query key for `-k` arguments.\n *\n * Accepted formats:\n * - `XXXX,XXXX` — bare tag\n * - `XXXX,XXXX=value` — tag with value\n * - `XXXX,XXXX[0].XXXX,XXXX=value` — nested path with value\n * - `XXXX,XXXX.XXXX,XXXX=value` — dotted path with value\n *\n * The tag portion must start with a valid hex tag pair. Value after `=` is unconstrained.\n */\n// eslint-disable-next-line no-useless-escape\nconst DICOM_QUERY_KEY_PATTERN = /^[0-9A-Fa-f]{4},[0-9A-Fa-f]{4}(?:[\\[.\\]0-9A-Fa-f,]*)?(?:=.*)?$/;\n\n/**\n * Returns true if the string is a valid DICOM query key for `-k` arguments.\n */\nfunction isValidDicomKey(key: string): boolean {\n return DICOM_QUERY_KEY_PATTERN.test(key);\n}\n\n// ---------------------------------------------------------------------------\n// Path safety\n// ---------------------------------------------------------------------------\n\n/** Pattern matching `..` as a path segment (between separators, or at start/end). */\nconst PATH_TRAVERSAL_PATTERN = /(?:^|[\\\\/])\\.\\.(?:[\\\\/]|$)/;\n\n/**\n * Returns true if the string contains only valid DICOM AE Title characters.\n */\nfunction isValidAETitle(value: string): boolean {\n return AE_TITLE_PATTERN.test(value);\n}\n\n/**\n * Returns true if the path does not contain traversal sequences.\n *\n * @param p - The filesystem path to check\n * @returns `true` when the path is safe (no `..` segments)\n */\nfunction isSafePath(p: string): boolean {\n return !PATH_TRAVERSAL_PATTERN.test(p);\n}\n\nexport {\n DICOM_TAG_PATTERN,\n AE_TITLE_PATTERN,\n UID_PATTERN,\n TAG_PATH_SEGMENT,\n DICOM_TAG_PATH_PATTERN,\n AE_TITLE_MIN_LENGTH,\n AE_TITLE_MAX_LENGTH,\n UID_MAX_LENGTH,\n PORT_MIN,\n PORT_MAX,\n DICOM_QUERY_KEY_PATTERN,\n isValidDicomKey,\n isValidAETitle,\n PATH_TRAVERSAL_PATTERN,\n isSafePath,\n};\n","/**\n * Locates DCMTK binaries on the host system.\n *\n * Search order:\n * 1. `DCMTK_PATH` environment variable\n * 2. Platform-specific known install locations\n * 3. System PATH (via `which`/`where` lookup)\n *\n * @module findDcmtkPath\n */\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport type { Result } from './types';\nimport { ok, err } from './types';\nimport { WINDOWS_SEARCH_PATHS, UNIX_SEARCH_PATHS, REQUIRED_BINARIES } from './constants';\nimport { isSafePath } from './patterns';\n\n/** Cached path result. Cleared only by passing `noCache: true`. */\nlet cachedPath: string | undefined;\n\nconst isWindows = process.platform === 'win32';\n\n/**\n * Returns the binary filename with platform-appropriate extension.\n *\n * @param name - The base binary name (e.g., `\"dcm2json\"`)\n * @returns The binary name with `.exe` appended on Windows\n */\nfunction binaryName(name: string): string {\n /* v8 ignore next -- platform-specific branch */\n return isWindows ? `${name}.exe` : name;\n}\n\n/**\n * Checks whether a directory contains all required DCMTK binaries.\n *\n * @param dir - The directory to check\n * @returns `true` if all required binaries exist in the directory\n */\nfunction hasRequiredBinaries(dir: string): boolean {\n for (const bin of REQUIRED_BINARIES) {\n if (!existsSync(join(dir, binaryName(bin)))) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Attempts to locate a binary via the system PATH using `which` (Unix) or `where` (Windows).\n *\n * @param name - The binary name to search for\n * @returns The directory containing the binary, or `undefined` if not found\n */\nfunction findViaSystemPath(name: string): string | undefined {\n try {\n /* v8 ignore next -- platform-specific branch */\n const cmd = isWindows ? `where ${binaryName(name)}` : `which ${name}`;\n const result = execSync(cmd, { encoding: 'utf-8', timeout: 5_000, windowsHide: true }).trim();\n const firstLine = result.split('\\n')[0]?.trim();\n if (firstLine) {\n /* v8 ignore next -- platform-specific branch */\n const lastSep = firstLine.lastIndexOf(isWindows ? '\\\\' : '/');\n if (lastSep >= 0) {\n return firstLine.substring(0, lastSep);\n }\n }\n } catch {\n // Binary not in PATH — this is expected, not exceptional\n }\n return undefined;\n}\n\n/**\n * Checks the DCMTK_PATH environment variable for a valid DCMTK installation.\n *\n * @returns A Result if the env var is set (success or error), or `undefined` if unset\n */\nfunction searchEnvPath(): Result<string> | undefined {\n const envPath = process.env['DCMTK_PATH'];\n if (envPath === undefined || envPath.length === 0) {\n return undefined;\n }\n if (!isSafePath(envPath)) {\n return err(new Error(`DCMTK_PATH=\"${envPath}\" contains path traversal sequences`));\n }\n if (hasRequiredBinaries(envPath)) {\n return ok(envPath);\n }\n return err(new Error(`DCMTK_PATH=\"${envPath}\" is set but required binaries are missing`));\n}\n\n/**\n * Searches platform-specific known install locations for DCMTK binaries.\n *\n * @returns The directory path if found, or `undefined`\n */\nfunction searchKnownPaths(): string | undefined {\n /* v8 ignore next -- platform-specific branch */\n const searchPaths = isWindows ? WINDOWS_SEARCH_PATHS : UNIX_SEARCH_PATHS;\n for (const candidate of searchPaths) {\n if (hasRequiredBinaries(candidate)) {\n return candidate;\n }\n }\n return undefined;\n}\n\n/**\n * Searches the system PATH for DCMTK binaries.\n *\n * @returns The directory path if found, or `undefined`\n */\nfunction searchSystemPath(): string | undefined {\n /* v8 ignore next -- fallback never used since REQUIRED_BINARIES is non-empty */\n const systemDir = findViaSystemPath(REQUIRED_BINARIES[0] ?? 'dcm2json');\n if (systemDir !== undefined && hasRequiredBinaries(systemDir)) {\n return systemDir;\n }\n return undefined;\n}\n\n/**\n * Options for {@link findDcmtkPath}.\n */\ninterface FindDcmtkPathOptions {\n /** Bypass the cached result and perform a fresh search. */\n readonly noCache?: boolean | undefined;\n}\n\n/**\n * Locates the directory containing DCMTK command-line binaries.\n *\n * Searches in the following order:\n * 1. `DCMTK_PATH` environment variable (if set)\n * 2. Platform-specific known install locations\n * 3. System PATH lookup via `which`/`where`\n *\n * The result is cached after the first successful call. Pass `{ noCache: true }`\n * to force a fresh search.\n *\n * @param options - Optional configuration\n * @returns A Result containing the DCMTK binary directory path, or an error if not found\n * @throws Never throws for expected failures (Rule 6.1)\n *\n * @example\n * ```ts\n * const result = findDcmtkPath();\n * if (result.ok) {\n * console.log(`DCMTK found at: ${result.value}`);\n * } else {\n * console.error(result.error.message);\n * }\n * ```\n */\nfunction findDcmtkPath(options?: FindDcmtkPathOptions): Result<string> {\n if (cachedPath !== undefined && !options?.noCache) {\n return ok(cachedPath);\n }\n\n const envResult = searchEnvPath();\n if (envResult !== undefined) {\n if (envResult.ok) {\n cachedPath = envResult.value;\n }\n return envResult;\n }\n\n const knownPath = searchKnownPaths();\n if (knownPath !== undefined) {\n cachedPath = knownPath;\n return ok(knownPath);\n }\n\n const systemPath = searchSystemPath();\n if (systemPath !== undefined) {\n cachedPath = systemPath;\n return ok(systemPath);\n }\n\n return err(\n new Error(\n 'DCMTK binaries not found. Install DCMTK and either:\\n' +\n ' - Set the DCMTK_PATH environment variable, or\\n' +\n ' - Install DCMTK to a standard location, or\\n' +\n ' - Ensure DCMTK binaries are on the system PATH'\n )\n );\n}\n\n/**\n * Clears the cached DCMTK path. Primarily for testing.\n */\nfunction clearDcmtkPathCache(): void {\n cachedPath = undefined;\n}\n\nexport { findDcmtkPath, clearDcmtkPathCache };\nexport type { FindDcmtkPathOptions };\n","/**\n * Resolves the full path to a DCMTK binary.\n *\n * Wraps {@link findDcmtkPath} + `path.join` and appends `.exe` on Windows.\n *\n * @module _resolveBinary\n * @internal\n */\n\nimport { join } from 'node:path';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { findDcmtkPath } from '../findDcmtkPath';\n\nconst isWindows = process.platform === 'win32';\n\n/**\n * Resolves the full filesystem path to a named DCMTK binary.\n *\n * @param toolName - The DCMTK binary name (e.g., \"dcm2xml\")\n * @returns A Result containing the full binary path or an error if DCMTK is not found\n */\nfunction resolveBinary(toolName: string): Result<string> {\n const pathResult = findDcmtkPath();\n if (!pathResult.ok) {\n return err(pathResult.error);\n }\n /* v8 ignore next -- platform-specific branch */\n const binaryName = isWindows ? `${toolName}.exe` : toolName;\n return ok(join(pathResult.value, binaryName));\n}\n\nexport { resolveBinary };\n","/**\n * Standardized error factory for tool wrappers.\n *\n * Produces consistent error messages that include the tool name, sanitized\n * arguments (truncated), exit code, and a stderr excerpt.\n *\n * @module _toolError\n * @internal\n */\n\n/** Maximum length for the arguments portion of the error message. */\nconst MAX_ARGS_LENGTH = 200;\n\n/** Maximum length for the stderr excerpt in the error message. */\nconst MAX_STDERR_LENGTH = 500;\n\n/**\n * Truncates a string to a maximum length, appending \"...\" if truncated.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum allowed length\n * @returns The original string or a truncated version\n */\nfunction truncate(value: string, maxLength: number): string {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.substring(0, maxLength)}...`;\n}\n\n/**\n * Creates a standardized Error for a tool wrapper failure.\n *\n * **Privacy note:** Arguments are included in the error message for debugging.\n * These may contain file paths. Callers exposing errors to end users or external\n * logs should sanitize sensitive paths before display.\n *\n * @param toolName - The DCMTK binary name (e.g., \"dcm2xml\")\n * @param args - The command-line arguments passed to the tool\n * @param exitCode - The process exit code\n * @param stderr - The captured stderr output\n * @returns An Error with a descriptive message\n */\nfunction createToolError(toolName: string, args: readonly string[], exitCode: number, stderr: string): Error {\n const argsStr = truncate(args.join(' '), MAX_ARGS_LENGTH);\n const stderrStr = truncate(stderr.trim(), MAX_STDERR_LENGTH);\n const parts = [`${toolName} failed (exit code ${String(exitCode)})`];\n if (argsStr.length > 0) {\n parts.push(`args: ${argsStr}`);\n }\n if (stderrStr.length > 0) {\n parts.push(`stderr: ${stderrStr}`);\n }\n return new Error(parts.join(' | '));\n}\n\n/**\n * Formats a Zod validation error into a concise, human-readable string.\n *\n * Flattens nested Zod issues into `field: message` pairs, producing\n * cleaner output than the raw Zod `.message` JSON string.\n *\n * @param toolName - The DCMTK tool name for context\n * @param zodError - The Zod error object (must have `.issues` array)\n * @returns A formatted Error\n */\nfunction createValidationError(\n toolName: string,\n zodError: { readonly issues: ReadonlyArray<{ readonly path: ReadonlyArray<PropertyKey>; readonly message: string }> }\n): Error {\n const parts: string[] = [];\n for (let i = 0; i < zodError.issues.length; i++) {\n const issue = zodError.issues[i];\n /* v8 ignore next */\n if (issue === undefined) continue;\n const path = issue.path.length > 0 ? issue.path.map(String).join('.') : '(root)';\n parts.push(`${path}: ${issue.message}`);\n }\n const detail = parts.length > 0 ? parts.join('; ') : 'unknown validation error';\n return new Error(`${toolName}: invalid options — ${detail}`);\n}\n\nexport { createToolError, createValidationError, truncate, MAX_ARGS_LENGTH, MAX_STDERR_LENGTH };\n","/**\n * Event patterns and types for dcmrecv output parsing.\n *\n * Defines regex patterns that match DCMTK dcmrecv verbose output,\n * along with typed event data interfaces for each event.\n *\n * @module events/dcmrecv\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmrecv process output. */\nconst DcmrecvEvent = {\n LISTENING: 'LISTENING',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n C_STORE_REQUEST: 'C_STORE_REQUEST',\n STORED_FILE: 'STORED_FILE',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n ECHO_REQUEST: 'ECHO_REQUEST',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n REFUSING_ASSOCIATION: 'REFUSING_ASSOCIATION',\n /** Synthetic: STORED_FILE enriched with association context. */\n FILE_RECEIVED: 'FILE_RECEIVED',\n /** Synthetic: emitted on association release/abort with summary. */\n ASSOCIATION_COMPLETE: 'ASSOCIATION_COMPLETE',\n} as const;\n\ntype DcmrecvEventValue = (typeof DcmrecvEvent)[keyof typeof DcmrecvEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface AssociationReceivedData {\n readonly source: string;\n readonly callingAE: string;\n readonly calledAE: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface AssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for C_STORE_REQUEST event. */\ninterface CStoreRequestData {\n readonly raw: string;\n}\n\n/** Data for STORED_FILE event. */\ninterface StoredFileData {\n readonly filePath: string;\n}\n\n/** Data for REFUSING_ASSOCIATION event. */\ninterface RefusingAssociationData {\n readonly reason: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface CannotStartListenerData {\n readonly message: string;\n}\n\n/** Data for FILE_RECEIVED synthetic event. */\ninterface FileReceivedData {\n readonly filePath: string;\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Data for ASSOCIATION_COMPLETE synthetic event. */\ninterface AssociationCompleteData {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly durationMs: number;\n readonly endReason: 'release' | 'abort';\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmrecv verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmrecv verbose output. */\nconst DCMRECV_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmrecvEvent.LISTENING,\n pattern: /listening/i,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{1,100}(\\S+):\\s+(\\S+)\\s+->\\s+(\\S+)/,\n processor: (match): AssociationReceivedData => ({\n source: match[1] ?? '',\n callingAE: match[2] ?? '',\n calledAE: match[3] ?? '',\n }),\n },\n {\n event: DcmrecvEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): AssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmrecvEvent.C_STORE_REQUEST,\n pattern: /Received Store Request/i,\n processor: (match): CStoreRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmrecvEvent.STORED_FILE,\n pattern: /Stored received object to file:\\s{0,20}(.{1,1024})/,\n processor: (match): StoredFileData => ({\n filePath: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmrecvEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.ASSOCIATION_ABORTED,\n pattern: /Received Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.ECHO_REQUEST,\n pattern: /Received C-ECHO Request/,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.CANNOT_START_LISTENER,\n pattern: /cannot (?:start SCP and )?listen on port/i,\n processor: (match): CannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmrecvEvent.REFUSING_ASSOCIATION,\n pattern: /Refusing Association\\s{0,20}\\((.{1,500})\\)/,\n processor: (match): RefusingAssociationData => ({\n reason: match[1] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMRECV_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmrecvEvent.CANNOT_START_LISTENER]);\n\nexport { DcmrecvEvent, DCMRECV_PATTERNS, DCMRECV_FATAL_EVENTS };\nexport type {\n DcmrecvEventValue,\n AssociationReceivedData,\n AssociationAcknowledgedData,\n CStoreRequestData,\n StoredFileData,\n RefusingAssociationData,\n CannotStartListenerData,\n FileReceivedData,\n AssociationCompleteData,\n};\n","/**\n * Pure state machine tracking DICOM association lifecycle.\n *\n * No I/O, no async, no EventEmitter — just state transitions.\n * Used by Dcmrecv and StoreSCP to correlate files to associations.\n *\n * State machine:\n * ```\n * IDLE -> [beginAssociation] -> ACTIVE -> [trackFile]* -> [endAssociation] -> IDLE\n * ```\n *\n * This single-slot design is safe because all DCMTK server binaries\n * (dcmrecv, storescp, etc.) are single-threaded and handle one\n * association at a time. Concurrent connections queue at the TCP level,\n * so associations never interleave in the output stream.\n *\n * @module servers/AssociationTracker\n */\n\n// ---------------------------------------------------------------------------\n// Interfaces\n// ---------------------------------------------------------------------------\n\n/** Context for the currently active association. */\ninterface AssociationContext {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly startTime: number;\n readonly files: string[];\n}\n\n/** A file enriched with association context. */\ninterface TrackedFile {\n readonly filePath: string;\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Summary emitted when an association completes. */\ninterface AssociationSummary {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly durationMs: number;\n readonly endReason: 'release' | 'abort';\n}\n\n// ---------------------------------------------------------------------------\n// AssociationTracker class\n// ---------------------------------------------------------------------------\n\n/**\n * Tracks DICOM association lifecycle for file-to-source correlation.\n *\n * Maintains a simple IDLE/ACTIVE state machine. While active, all tracked\n * files are enriched with the current association context. Only one\n * association can be active at a time — this is safe because DCMTK\n * servers are single-threaded and process associations sequentially.\n *\n * @example\n * ```ts\n * const tracker = new AssociationTracker();\n * const id = tracker.beginAssociation({ callingAE: 'SCU', calledAE: 'SCP', source: 'db' });\n * const file = tracker.trackFile('/path/to/received.dcm');\n * const summary = tracker.endAssociation('release');\n * ```\n */\nclass AssociationTracker {\n private association: AssociationContext | undefined;\n private counter = 0;\n\n /**\n * Begins a new association, transitioning from IDLE to ACTIVE.\n *\n * If an association is already active, it is silently ended (abort)\n * and the new one begins.\n *\n * @param data - Association metadata\n * @returns The unique association ID\n */\n beginAssociation(data: { readonly callingAE: string; readonly calledAE: string; readonly source: string }): string {\n this.counter++;\n const associationId = `assoc-${String(this.counter)}`;\n this.association = {\n associationId,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n startTime: Date.now(),\n files: [],\n };\n return associationId;\n }\n\n /**\n * Tracks a file received during the current association.\n *\n * If no association is active, returns a TrackedFile with empty context.\n *\n * @param filePath - Path to the received file\n * @returns A TrackedFile enriched with association context\n */\n trackFile(filePath: string): TrackedFile {\n if (this.association === undefined) {\n return {\n filePath,\n associationId: '',\n callingAE: '',\n calledAE: '',\n source: '',\n };\n }\n this.association.files.push(filePath);\n return {\n filePath,\n associationId: this.association.associationId,\n callingAE: this.association.callingAE,\n calledAE: this.association.calledAE,\n source: this.association.source,\n };\n }\n\n /**\n * Ends the current association, transitioning from ACTIVE to IDLE.\n *\n * @param reason - Why the association ended\n * @returns An AssociationSummary, or undefined if no association was active\n */\n endAssociation(reason: 'release' | 'abort'): AssociationSummary | undefined {\n if (this.association === undefined) return undefined;\n\n const summary: AssociationSummary = {\n associationId: this.association.associationId,\n callingAE: this.association.callingAE,\n calledAE: this.association.calledAE,\n source: this.association.source,\n files: [...this.association.files],\n durationMs: Date.now() - this.association.startTime,\n endReason: reason,\n };\n\n this.association = undefined;\n return summary;\n }\n\n /** The currently active association context, or undefined. */\n get current(): AssociationContext | undefined {\n return this.association;\n }\n\n /** Whether an association is currently active. */\n get isActive(): boolean {\n return this.association !== undefined;\n }\n\n /** Resets the tracker to IDLE, discarding any active association. */\n reset(): void {\n this.association = undefined;\n }\n}\n\nexport { AssociationTracker };\nexport type { AssociationContext, TrackedFile, AssociationSummary };\n","/**\n * DICOM receiver server wrapping the dcmrecv binary.\n *\n * Provides a type-safe, event-driven API for receiving DICOM objects\n * via C-STORE. Uses a static factory pattern because binary resolution\n * must happen before the constructor call.\n *\n * @module servers/Dcmrecv\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath, isValidAETitle } from '../patterns';\nimport { DcmrecvEvent, DCMRECV_PATTERNS, DCMRECV_FATAL_EVENTS } from '../events/dcmrecv';\nimport type {\n AssociationReceivedData,\n AssociationAcknowledgedData,\n CStoreRequestData,\n StoredFileData,\n RefusingAssociationData,\n CannotStartListenerData,\n FileReceivedData,\n AssociationCompleteData,\n} from '../events/dcmrecv';\nimport { AssociationTracker } from './AssociationTracker';\n\n// ---------------------------------------------------------------------------\n// Event map type (for documentation — consumers see typed overloads on class)\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the Dcmrecv server. */\ninterface DcmrecvEventMap {\n LISTENING: [];\n ASSOCIATION_RECEIVED: [AssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [AssociationAcknowledgedData];\n C_STORE_REQUEST: [CStoreRequestData];\n STORED_FILE: [StoredFileData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n ECHO_REQUEST: [];\n CANNOT_START_LISTENER: [CannotStartListenerData];\n REFUSING_ASSOCIATION: [RefusingAssociationData];\n FILE_RECEIVED: [FileReceivedData];\n ASSOCIATION_COMPLETE: [AssociationCompleteData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Subdirectory generation mode for received files. */\nconst SubdirectoryMode = {\n NONE: 'none',\n SERIES_DATE: 'series-date',\n} as const;\n\ntype SubdirectoryModeValue = (typeof SubdirectoryMode)[keyof typeof SubdirectoryMode];\n\n/** Filename generation mode for received files. */\nconst FilenameMode = {\n DEFAULT: 'default',\n UNIQUE: 'unique',\n SHORT_UNIQUE: 'short-unique',\n SYSTEM_TIME: 'system-time',\n} as const;\n\ntype FilenameModeValue = (typeof FilenameMode)[keyof typeof FilenameMode];\n\n/** Storage mode for received DICOM objects. */\nconst StorageMode = {\n NORMAL: 'normal',\n BIT_PRESERVING: 'bit-preserving',\n IGNORE: 'ignore',\n} as const;\n\ntype StorageModeValue = (typeof StorageMode)[keyof typeof StorageMode];\n\n/** Options for creating a Dcmrecv server instance. */\ninterface DcmrecvOptions {\n /** Port to listen on (required). */\n readonly port: number;\n /** Application Entity Title. */\n readonly aeTitle?: string | undefined;\n /** Output directory for received files. */\n readonly outputDirectory?: string | undefined;\n /** Path to an association negotiation configuration file. */\n readonly configFile?: string | undefined;\n /** Profile name within the configuration file. */\n readonly configProfile?: string | undefined;\n /** Subdirectory generation mode. */\n readonly subdirectory?: SubdirectoryModeValue | undefined;\n /** Filename generation mode. */\n readonly filenameMode?: FilenameModeValue | undefined;\n /** File extension for received files. */\n readonly filenameExtension?: string | undefined;\n /** Storage mode for received DICOM objects. */\n readonly storageMode?: StorageModeValue | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmrecvOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n aeTitle: z.string().min(1).max(16).refine(isValidAETitle, { message: 'AE Title contains invalid characters' }).optional(),\n outputDirectory: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in outputDirectory' }).optional(),\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }).optional(),\n configProfile: z.string().min(1).optional(),\n subdirectory: z.enum(['none', 'series-date']).optional(),\n filenameMode: z.enum(['default', 'unique', 'short-unique', 'system-time']).optional(),\n filenameExtension: z.string().min(1).optional(),\n storageMode: z.enum(['normal', 'bit-preserving', 'ignore']).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builders (each <= 40 lines)\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmrecvOptions): string[] {\n const args: string[] = ['--verbose'];\n\n if (options.aeTitle !== undefined) {\n args.push('--aetitle', options.aeTitle);\n }\n if (options.outputDirectory !== undefined) {\n args.push('--output-directory', options.outputDirectory);\n }\n if (options.configFile !== undefined && options.configProfile !== undefined) {\n args.push('--config-file', options.configFile, options.configProfile);\n }\n\n addFilenameArgs(args, options);\n addStorageArgs(args, options);\n addNetworkArgs(args, options);\n\n args.push(String(options.port));\n return args;\n}\n\n/** Appends filename-related CLI flags. */\nfunction addFilenameArgs(args: string[], options: DcmrecvOptions): void {\n if (options.subdirectory === 'series-date') {\n args.push('--sort-on-patientsname');\n }\n if (options.filenameMode === 'unique') {\n args.push('--unique-filenames');\n } else if (options.filenameMode === 'short-unique') {\n args.push('--short-unique-filenames');\n } else if (options.filenameMode === 'system-time') {\n args.push('--system-time-filenames');\n }\n if (options.filenameExtension !== undefined) {\n args.push('--filename-extension', options.filenameExtension);\n }\n}\n\n/** Appends storage-related CLI flags. */\nfunction addStorageArgs(args: string[], options: DcmrecvOptions): void {\n if (options.storageMode === 'bit-preserving') {\n args.push('--bit-preserving');\n } else if (options.storageMode === 'ignore') {\n args.push('--ignore');\n }\n}\n\n/** Appends network-related CLI flags. */\nfunction addNetworkArgs(args: string[], options: DcmrecvOptions): void {\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Dcmrecv class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM receiver server wrapping the dcmrecv binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Server-specific events (LISTENING, STORED_FILE, etc.) are emitted dynamically\n * via the LineParser. Use `onEvent()` for typed listeners on server events.\n *\n * @example\n * ```ts\n * const result = Dcmrecv.create({ port: 11112, outputDirectory: '/tmp/received' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('STORED_FILE', (data) => console.log('Stored:', data.filePath));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass Dcmrecv extends DcmtkProcess {\n private readonly parser: LineParser;\n private readonly tracker: AssociationTracker;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.tracker = new AssociationTracker();\n this.wireParser();\n this.wireTracker();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /**\n * Registers a typed listener for a dcmrecv-specific event.\n *\n * @param event - The event name from DcmrecvEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n onEvent<K extends keyof DcmrecvEventMap>(event: K, listener: (...args: DcmrecvEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (...args: DcmrecvEventMap['ASSOCIATION_RECEIVED']) => void): this {\n return this.onEvent('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for stored files.\n *\n * @param listener - Callback receiving stored file data\n * @returns this for chaining\n */\n onStoredFile(listener: (...args: DcmrecvEventMap['STORED_FILE']) => void): this {\n return this.onEvent('STORED_FILE', listener);\n }\n\n /**\n * Registers a listener for received files enriched with association context.\n *\n * @param listener - Callback receiving tracked file data\n * @returns this for chaining\n */\n onFileReceived(listener: (...args: DcmrecvEventMap['FILE_RECEIVED']) => void): this {\n return this.onEvent('FILE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for completed associations.\n *\n * @param listener - Callback receiving association summary\n * @returns this for chaining\n */\n onAssociationComplete(listener: (...args: DcmrecvEventMap['ASSOCIATION_COMPLETE']) => void): this {\n return this.onEvent('ASSOCIATION_COMPLETE', listener);\n }\n\n /**\n * Creates a new Dcmrecv server instance.\n *\n * @param options - Configuration options for the dcmrecv server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmrecvOptions): Result<Dcmrecv> {\n const validation = DcmrecvOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmrecv', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmrecv');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMRECV_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n isStartedPredicate: line => /listening/i.test(line),\n };\n\n return ok(new Dcmrecv(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMRECV_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires the AssociationTracker to server events. */\n private wireTracker(): void {\n this.onEvent('ASSOCIATION_RECEIVED', data => {\n this.tracker.beginAssociation(data);\n });\n\n this.onEvent('STORED_FILE', data => {\n const tracked = this.tracker.trackFile(data.filePath);\n this.emit(DcmrecvEvent.FILE_RECEIVED as string, tracked);\n });\n\n this.onEvent('ASSOCIATION_RELEASE', () => {\n const summary = this.tracker.endAssociation('release');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n\n this.onEvent('ASSOCIATION_ABORTED', () => {\n const summary = this.tracker.endAssociation('abort');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { Dcmrecv, SubdirectoryMode, FilenameMode, StorageMode };\nexport type { DcmrecvOptions, DcmrecvEventMap, SubdirectoryModeValue, FilenameModeValue, StorageModeValue };\n","/**\n * Event patterns and types for storescp output parsing.\n *\n * Extends dcmrecv patterns with storescp-specific events like\n * file storage progress and subdirectory creation.\n *\n * @module events/storescp\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\nimport { DcmrecvEvent, DCMRECV_PATTERNS, DCMRECV_FATAL_EVENTS } from './dcmrecv';\nimport type { AssociationReceivedData } from './dcmrecv';\n\n// ---------------------------------------------------------------------------\n// Event constants (superset of dcmrecv — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by storescp process output. */\nconst StorescpEvent = {\n ...DcmrecvEvent,\n STORING_FILE: 'STORING_FILE',\n SUBDIRECTORY_CREATED: 'SUBDIRECTORY_CREATED',\n} as const;\n\ntype StorescpEventValue = (typeof StorescpEvent)[keyof typeof StorescpEvent];\n\n// ---------------------------------------------------------------------------\n// Additional event data interfaces\n// ---------------------------------------------------------------------------\n\n/** Data for STORING_FILE event. */\ninterface StoringFileData {\n readonly filePath: string;\n}\n\n/** Data for SUBDIRECTORY_CREATED event. */\ninterface SubdirectoryCreatedData {\n readonly directory: string;\n}\n\n// ---------------------------------------------------------------------------\n// storescp-specific patterns\n// ---------------------------------------------------------------------------\n\n/**\n * storescp-specific ASSOCIATION_RECEIVED pattern.\n * storescp --verbose outputs only \"Association Received\" (no AE details),\n * so this pattern returns empty fields for source/callingAE/calledAE.\n */\nconst STORESCP_ASSOCIATION_RECEIVED: EventPattern = {\n event: StorescpEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received/i,\n processor: (): AssociationReceivedData => ({ source: '', callingAE: '', calledAE: '' }),\n};\n\nconst STORESCP_ADDITIONAL_PATTERNS: readonly EventPattern[] = [\n {\n event: StorescpEvent.STORING_FILE,\n pattern: /storing DICOM file:\\s{0,20}(.{1,1024})/i,\n processor: (match): StoringFileData => ({\n filePath: (match[1] ?? '').trim(),\n }),\n },\n {\n event: StorescpEvent.SUBDIRECTORY_CREATED,\n pattern: /created new subdirectory[:\\s]{0,20}(.{1,1024})/i,\n processor: (match): SubdirectoryCreatedData => ({\n directory: (match[1] ?? '').trim(),\n }),\n },\n];\n\n/** Combined event patterns for parsing storescp verbose output. */\nconst STORESCP_PATTERNS: readonly EventPattern[] = [\n ...DCMRECV_PATTERNS.filter(p => p.event !== DcmrecvEvent.ASSOCIATION_RECEIVED),\n STORESCP_ASSOCIATION_RECEIVED,\n ...STORESCP_ADDITIONAL_PATTERNS,\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst STORESCP_FATAL_EVENTS: ReadonlySet<string> = new Set([...DCMRECV_FATAL_EVENTS]);\n\nexport { StorescpEvent, STORESCP_PATTERNS, STORESCP_FATAL_EVENTS };\nexport type { StorescpEventValue, StoringFileData, SubdirectoryCreatedData };\n","/**\n * DICOM Storage SCP server wrapping the storescp binary.\n *\n * Provides a type-safe, event-driven API for receiving DICOM objects\n * via the storescp command-line tool. Supports sorting, exec hooks,\n * custom transfer syntaxes, and all standard storescp options.\n *\n * @module servers/StoreSCP\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath, isValidAETitle } from '../patterns';\nimport { STORESCP_PATTERNS, STORESCP_FATAL_EVENTS } from '../events/storescp';\nimport { DcmrecvEvent } from '../events/dcmrecv';\nimport type {\n AssociationReceivedData,\n AssociationAcknowledgedData,\n CStoreRequestData,\n StoredFileData,\n RefusingAssociationData,\n CannotStartListenerData,\n FileReceivedData,\n AssociationCompleteData,\n} from '../events/dcmrecv';\nimport type { StoringFileData, SubdirectoryCreatedData } from '../events/storescp';\nimport { AssociationTracker } from './AssociationTracker';\n\n// ---------------------------------------------------------------------------\n// Event map type (for documentation — consumers see typed overloads on class)\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the StoreSCP server. */\ninterface StoreSCPEventMap {\n LISTENING: [];\n ASSOCIATION_RECEIVED: [AssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [AssociationAcknowledgedData];\n C_STORE_REQUEST: [CStoreRequestData];\n STORED_FILE: [StoredFileData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n ECHO_REQUEST: [];\n CANNOT_START_LISTENER: [CannotStartListenerData];\n REFUSING_ASSOCIATION: [RefusingAssociationData];\n STORING_FILE: [StoringFileData];\n SUBDIRECTORY_CREATED: [SubdirectoryCreatedData];\n FILE_RECEIVED: [FileReceivedData];\n ASSOCIATION_COMPLETE: [AssociationCompleteData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Preferred transfer syntax for incoming associations. */\nconst PreferredTransferSyntax = {\n LITTLE_ENDIAN: 'little-endian',\n BIG_ENDIAN: 'big-endian',\n IMPLICIT: 'implicit',\n ACCEPT_ALL: 'accept-all',\n} as const;\n\ntype PreferredTransferSyntaxValue = (typeof PreferredTransferSyntax)[keyof typeof PreferredTransferSyntax];\n\n/** Options for creating a StoreSCP server instance. */\ninterface StoreSCPOptions {\n /** Port to listen on (required). */\n readonly port: number;\n /** Application Entity Title. */\n readonly aeTitle?: string | undefined;\n /** Output directory for received files. */\n readonly outputDirectory?: string | undefined;\n /** Path to an association negotiation configuration file. */\n readonly configFile?: string | undefined;\n /** Profile name within the configuration file. */\n readonly configProfile?: string | undefined;\n /** Preferred transfer syntax (not valid with configFile). */\n readonly preferredTransferSyntax?: PreferredTransferSyntaxValue | undefined;\n /** Sort studies into subdirectories. */\n readonly sortByStudy?: boolean | undefined;\n /** Sort by Study Instance UID. */\n readonly sortByStudyUID?: boolean | undefined;\n /** Sort by patient name. */\n readonly sortByPatientName?: boolean | undefined;\n /** Generate unique filenames. */\n readonly uniqueFilenames?: boolean | undefined;\n /** Use bit-preserving mode. */\n readonly bitPreserving?: boolean | undefined;\n /** Execute command on each received file. */\n readonly execOnReception?: string | undefined;\n /** Execute command at end of study. */\n readonly execOnEndOfStudy?: string | undefined;\n /** Timeout for end-of-study detection in seconds (passed to DCMTK as-is). */\n readonly endOfStudyTimeout?: number | undefined;\n /** Rename files at end of study. */\n readonly renameOnEndOfStudy?: boolean | undefined;\n /** Socket timeout in seconds (passed to DCMTK as-is). */\n readonly socketTimeout?: number | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** Filename extension for received files. */\n readonly filenameExtension?: string | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Configuration presets\n// ---------------------------------------------------------------------------\n\n/**\n * Pre-configured option sets for common StoreSCP deployment patterns.\n * Spread a preset into your options to avoid specifying boilerplate.\n *\n * @example\n * ```ts\n * StoreSCP.create({ ...StoreSCPPreset.PRODUCTION, port: 11112, outputDirectory: '/data' });\n * ```\n */\nconst StoreSCPPreset = {\n /** Basic storage: unique filenames to avoid collisions. */\n BASIC_STORAGE: {\n uniqueFilenames: true,\n },\n /** Testing: unique filenames, preserving raw transfer syntax. */\n TESTING: {\n uniqueFilenames: true,\n bitPreserving: true,\n },\n /** Production: unique filenames with reasonable timeouts. */\n PRODUCTION: {\n uniqueFilenames: true,\n acseTimeout: 30,\n dimseTimeout: 60,\n },\n} as const satisfies Record<string, Partial<StoreSCPOptions>>;\n\n/** Names of the available StoreSCP configuration presets. */\ntype StoreSCPPresetName = keyof typeof StoreSCPPreset;\n\nconst StoreSCPOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n aeTitle: z.string().min(1).max(16).refine(isValidAETitle, { message: 'AE Title contains invalid characters' }).optional(),\n outputDirectory: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in outputDirectory' }).optional(),\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }).optional(),\n configProfile: z.string().min(1).optional(),\n preferredTransferSyntax: z.enum(['little-endian', 'big-endian', 'implicit', 'accept-all']).optional(),\n sortByStudy: z.boolean().optional(),\n sortByStudyUID: z.boolean().optional(),\n sortByPatientName: z.boolean().optional(),\n uniqueFilenames: z.boolean().optional(),\n bitPreserving: z.boolean().optional(),\n execOnReception: z.string().min(1).optional(),\n execOnEndOfStudy: z.string().min(1).optional(),\n endOfStudyTimeout: z.number().int().positive().optional(),\n renameOnEndOfStudy: z.boolean().optional(),\n socketTimeout: z.number().int().positive().optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n filenameExtension: z.string().min(1).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builders (each <= 40 lines)\n// ---------------------------------------------------------------------------\n\n/** Builds the full CLI arguments array. */\nfunction buildArgs(options: StoreSCPOptions): string[] {\n const args: string[] = ['--verbose'];\n\n if (options.aeTitle !== undefined) {\n args.push('--aetitle', options.aeTitle);\n }\n if (options.configFile !== undefined && options.configProfile !== undefined) {\n args.push('--config-file', options.configFile, options.configProfile);\n }\n\n buildTransferSyntaxArgs(args, options);\n buildSortArgs(args, options);\n buildOutputArgs(args, options);\n buildNetworkArgs(args, options);\n buildExecArgs(args, options);\n\n args.push(String(options.port));\n return args;\n}\n\n/** Appends transfer syntax CLI flags. */\nfunction buildTransferSyntaxArgs(args: string[], options: StoreSCPOptions): void {\n if (options.preferredTransferSyntax === 'little-endian') {\n args.push('+xe');\n } else if (options.preferredTransferSyntax === 'big-endian') {\n args.push('+xb');\n } else if (options.preferredTransferSyntax === 'implicit') {\n args.push('+xi');\n } else if (options.preferredTransferSyntax === 'accept-all') {\n args.push('+xa');\n }\n}\n\n/** Appends sorting-related CLI flags. */\nfunction buildSortArgs(args: string[], options: StoreSCPOptions): void {\n if (options.sortByStudy === true) {\n args.push('--sort-conc-studies');\n }\n if (options.sortByStudyUID === true) {\n args.push('--sort-on-study-uid');\n }\n if (options.sortByPatientName === true) {\n args.push('--sort-on-patientsname');\n }\n}\n\n/** Appends output-related CLI flags. */\nfunction buildOutputArgs(args: string[], options: StoreSCPOptions): void {\n if (options.outputDirectory !== undefined) {\n args.push('--output-directory', options.outputDirectory);\n }\n if (options.uniqueFilenames === true) {\n args.push('--unique-filenames');\n }\n if (options.bitPreserving === true) {\n args.push('--bit-preserving');\n }\n if (options.filenameExtension !== undefined) {\n args.push('--filename-extension', options.filenameExtension);\n }\n}\n\n/** Appends network-related CLI flags. */\nfunction buildNetworkArgs(args: string[], options: StoreSCPOptions): void {\n if (options.socketTimeout !== undefined) {\n args.push('--socket-timeout', String(options.socketTimeout));\n }\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n}\n\n/** Appends exec-related CLI flags. */\nfunction buildExecArgs(args: string[], options: StoreSCPOptions): void {\n if (options.execOnReception !== undefined) {\n args.push('--exec-on-reception', options.execOnReception);\n }\n if (options.execOnEndOfStudy !== undefined) {\n args.push('--exec-on-eostudy', options.execOnEndOfStudy);\n }\n if (options.endOfStudyTimeout !== undefined) {\n args.push('--eostudy-timeout', String(options.endOfStudyTimeout));\n }\n if (options.renameOnEndOfStudy === true) {\n args.push('--rename-on-eostudy');\n }\n}\n\n// ---------------------------------------------------------------------------\n// StoreSCP class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Storage SCP server wrapping the storescp binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Note: storescp does not print a \"listening\" message, so `start()` resolves\n * on spawn. If the port is busy, storescp exits immediately and `start()`\n * returns an error via the close handler.\n *\n * Server-specific events are emitted dynamically via the LineParser.\n * Use `onEvent()` for typed listeners on server events.\n *\n * @example\n * ```ts\n * const result = StoreSCP.create({ port: 11112, outputDirectory: '/tmp/received' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('STORED_FILE', (data) => console.log('Stored:', data.filePath));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass StoreSCP extends DcmtkProcess {\n private readonly parser: LineParser;\n private readonly tracker: AssociationTracker;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.tracker = new AssociationTracker();\n this.wireParser();\n this.wireTracker();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n /**\n * Registers a typed listener for a storescp-specific event.\n *\n * @param event - The event name from StoreSCPEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof StoreSCPEventMap>(event: K, listener: (...args: StoreSCPEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (...args: StoreSCPEventMap['ASSOCIATION_RECEIVED']) => void): this {\n return this.onEvent('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for files being stored to disk.\n *\n * @param listener - Callback receiving storing file data\n * @returns this for chaining\n */\n onStoringFile(listener: (...args: StoreSCPEventMap['STORING_FILE']) => void): this {\n return this.onEvent('STORING_FILE', listener);\n }\n\n /**\n * Registers a listener for received files enriched with association context.\n *\n * @param listener - Callback receiving tracked file data\n * @returns this for chaining\n */\n onFileReceived(listener: (...args: StoreSCPEventMap['FILE_RECEIVED']) => void): this {\n return this.onEvent('FILE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for completed associations.\n *\n * @param listener - Callback receiving association summary\n * @returns this for chaining\n */\n onAssociationComplete(listener: (...args: StoreSCPEventMap['ASSOCIATION_COMPLETE']) => void): this {\n return this.onEvent('ASSOCIATION_COMPLETE', listener);\n }\n\n /**\n * Creates a new StoreSCP server instance.\n *\n * @param options - Configuration options for the storescp server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: StoreSCPOptions): Result<StoreSCP> {\n const validation = StoreSCPOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('storescp', validation.error));\n }\n\n const binaryResult = resolveBinary('storescp');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of STORESCP_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n // storescp doesn't print \"listening\" — resolve on spawn\n };\n\n return ok(new StoreSCP(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (STORESCP_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires the AssociationTracker to server events. */\n private wireTracker(): void {\n this.onEvent('ASSOCIATION_RECEIVED', data => {\n this.tracker.beginAssociation(data);\n });\n\n // storescp outputs \"storing DICOM file:\" (STORING_FILE), not\n // \"Stored received object to file:\" (STORED_FILE) like dcmrecv.\n // Listen to both so the tracker works regardless of which fires.\n this.onEvent('STORING_FILE', data => {\n const tracked = this.tracker.trackFile(data.filePath);\n this.emit(DcmrecvEvent.FILE_RECEIVED as string, tracked);\n });\n\n this.onEvent('STORED_FILE', data => {\n const tracked = this.tracker.trackFile(data.filePath);\n this.emit(DcmrecvEvent.FILE_RECEIVED as string, tracked);\n });\n\n this.onEvent('ASSOCIATION_RELEASE', () => {\n const summary = this.tracker.endAssociation('release');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n\n this.onEvent('ASSOCIATION_ABORTED', () => {\n const summary = this.tracker.endAssociation('abort');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { StoreSCP, PreferredTransferSyntax, StoreSCPPreset };\nexport type { StoreSCPOptions, StoreSCPEventMap, PreferredTransferSyntaxValue, StoreSCPPresetName };\n","/**\n * Shared filesystem utilities returning Result types.\n *\n * @module utils/fs\n */\n\nimport { mkdir, rename, copyFile, unlink, stat, rm } from 'node:fs/promises';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\n\n/**\n * Ensures a directory exists, creating it recursively if needed.\n *\n * @param dirPath - Directory path to create\n * @returns A Result indicating success or failure\n */\nasync function ensureDirectory(dirPath: string): Promise<Result<void>> {\n try {\n await mkdir(dirPath, { recursive: true });\n return ok(undefined);\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n return err(new Error(`Failed to create directory ${dirPath}: ${msg}`));\n }\n}\n\n/**\n * Moves a file from src to dest, falling back to copy+delete on cross-device.\n *\n * @param src - Source file path\n * @param dest - Destination file path\n * @returns A Result indicating success or failure\n */\nasync function moveFile(src: string, dest: string): Promise<Result<void>> {\n try {\n await rename(src, dest);\n return ok(undefined);\n } catch {\n try {\n await copyFile(src, dest);\n await unlink(src);\n return ok(undefined);\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n return err(new Error(`Failed to move file ${src} → ${dest}: ${msg}`));\n }\n }\n}\n\n/**\n * Returns the file size in bytes, or 0 on error.\n *\n * @param filePath - Path to the file\n * @returns The file size in bytes, or 0 if the file cannot be stat'd\n */\nasync function statFileSafe(filePath: string): Promise<number> {\n try {\n const s = await stat(filePath);\n return s.size;\n } catch {\n /* v8 ignore next */\n return 0;\n }\n}\n\n/**\n * Removes a directory recursively, ignoring errors.\n *\n * @param dirPath - Directory path to remove\n */\nasync function removeDirSafe(dirPath: string): Promise<void> {\n try {\n await rm(dirPath, { recursive: true, force: true });\n } catch {\n /* best-effort cleanup */\n }\n}\n\nexport { ensureDirectory, moveFile, statFileSafe, removeDirSafe };\n","/**\n * Branded types for domain primitives.\n *\n * Branded types use TypeScript's structural type system to prevent accidental\n * mixing of semantically different values that share the same underlying type.\n * A `DicomTag` cannot be used where an `AETitle` is expected, even though both\n * are strings at runtime.\n *\n * @module brands\n */\n\nimport { normalize } from 'node:path';\nimport type { Result } from './types';\nimport { ok, err } from './types';\nimport {\n DICOM_TAG_PATTERN,\n AE_TITLE_PATTERN,\n UID_PATTERN,\n DICOM_TAG_PATH_PATTERN,\n AE_TITLE_MIN_LENGTH,\n AE_TITLE_MAX_LENGTH,\n UID_MAX_LENGTH,\n PORT_MIN,\n PORT_MAX,\n PATH_TRAVERSAL_PATTERN,\n} from './patterns';\n\ndeclare const __brand: unique symbol;\n\n/** Intersects a base type with a phantom brand property for nominal typing. */\ntype Brand<T, TBrand extends string> = T & { readonly [__brand]: TBrand };\n\n// ---------------------------------------------------------------------------\n// Branded types\n// ---------------------------------------------------------------------------\n\n/**\n * A validated DICOM tag string, e.g. `\"(0010,0010)\"`.\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createDicomTag} to obtain a branded value from a raw string.\n */\ntype DicomTag = Brand<string, 'DicomTag'>;\n\n/**\n * A validated AE Title (1-16 chars: uppercase letters, digits, spaces, hyphens).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createAETitle} to obtain a branded value from a raw string.\n */\ntype AETitle = Brand<string, 'AETitle'>;\n\n/**\n * A validated DICOM tag path, e.g. `\"(0040,A730)[0].(0010,0010)\"`.\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createDicomTagPath} to obtain a branded value from a raw string.\n */\ntype DicomTagPath = Brand<string, 'DicomTagPath'>;\n\n/**\n * A validated SOP Class UID (dotted numeric OID, 1-64 chars).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createSOPClassUID} to obtain a branded value from a raw string.\n */\ntype SOPClassUID = Brand<string, 'SOPClassUID'>;\n\n/**\n * A validated Transfer Syntax UID (dotted numeric OID, 1-64 chars).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createTransferSyntaxUID} to obtain a branded value from a raw string.\n */\ntype TransferSyntaxUID = Brand<string, 'TransferSyntaxUID'>;\n\n/**\n * A validated filesystem path to a DICOM file.\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createDicomFilePath} to obtain a branded value from a raw string.\n */\ntype DicomFilePath = Brand<string, 'DicomFilePath'>;\n\n/**\n * A validated network port number (1-65535).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createPort} to obtain a branded value from a raw number.\n */\ntype Port = Brand<number, 'Port'>;\n\n// Validation patterns and constants imported from ./patterns\n\n// ---------------------------------------------------------------------------\n// Factory functions\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a validated DicomTag from a raw string.\n *\n * @param input - A string expected to be in format `(XXXX,XXXX)` where X is a hex digit\n * @returns A Result containing the branded DicomTag or an error\n */\nfunction createDicomTag(input: string): Result<DicomTag> {\n if (!DICOM_TAG_PATTERN.test(input)) {\n return err(new Error(`Invalid DICOM tag: \"${input}\". Expected format (XXXX,XXXX) where X is a hex digit`));\n }\n return ok(input as DicomTag);\n}\n\n/**\n * Creates a validated AETitle from a raw string.\n *\n * @param input - A string expected to be 1-16 printable ASCII chars (no backslash)\n * @returns A Result containing the branded AETitle or an error\n */\nfunction createAETitle(input: string): Result<AETitle> {\n if (input.length < AE_TITLE_MIN_LENGTH || input.length > AE_TITLE_MAX_LENGTH) {\n return err(new Error(`Invalid AE Title: \"${input}\". Must be ${AE_TITLE_MIN_LENGTH}-${AE_TITLE_MAX_LENGTH} characters`));\n }\n if (!AE_TITLE_PATTERN.test(input)) {\n return err(new Error(`Invalid AE Title: \"${input}\". Only printable ASCII characters (no backslash) are allowed`));\n }\n return ok(input as AETitle);\n}\n\n/**\n * Creates a validated DicomTagPath from a raw string.\n *\n * @param input - A dot-separated path of DICOM tags with optional array indices\n * @returns A Result containing the branded DicomTagPath or an error\n */\nfunction createDicomTagPath(input: string): Result<DicomTagPath> {\n // Empty check is duplicated in the Zod DicomTagPathSchema (.min(1)), but\n // kept here for a clearer error message from the brands factory.\n if (input.length === 0) {\n return err(new Error('Invalid DICOM tag path: empty string'));\n }\n if (!DICOM_TAG_PATH_PATTERN.test(input)) {\n return err(new Error(`Invalid DICOM tag path: \"${input}\". Expected format like (XXXX,XXXX) or (XXXX,XXXX)[0].(XXXX,XXXX)`));\n }\n return ok(input as DicomTagPath);\n}\n\n/**\n * Creates a validated SOPClassUID from a raw string.\n *\n * @param input - A dotted numeric OID string, 1-64 characters\n * @returns A Result containing the branded SOPClassUID or an error\n */\nfunction createSOPClassUID(input: string): Result<SOPClassUID> {\n if (input.length === 0 || input.length > UID_MAX_LENGTH) {\n return err(new Error(`Invalid SOP Class UID: \"${input}\". Must be 1-${UID_MAX_LENGTH} characters`));\n }\n if (!UID_PATTERN.test(input)) {\n return err(new Error(`Invalid SOP Class UID: \"${input}\". Must be a dotted numeric OID`));\n }\n return ok(input as SOPClassUID);\n}\n\n/**\n * Creates a validated TransferSyntaxUID from a raw string.\n *\n * @param input - A dotted numeric OID string, 1-64 characters\n * @returns A Result containing the branded TransferSyntaxUID or an error\n */\nfunction createTransferSyntaxUID(input: string): Result<TransferSyntaxUID> {\n if (input.length === 0 || input.length > UID_MAX_LENGTH) {\n return err(new Error(`Invalid Transfer Syntax UID: \"${input}\". Must be 1-${UID_MAX_LENGTH} characters`));\n }\n if (!UID_PATTERN.test(input)) {\n return err(new Error(`Invalid Transfer Syntax UID: \"${input}\". Must be a dotted numeric OID`));\n }\n return ok(input as TransferSyntaxUID);\n}\n\n/**\n * Creates a branded DicomFilePath from a raw string.\n * Validates that the path is non-empty and does not contain path traversal sequences.\n *\n * @param input - A filesystem path string\n * @returns A Result containing the branded DicomFilePath or an error\n */\nfunction createDicomFilePath(input: string): Result<DicomFilePath> {\n if (input.length === 0) {\n return err(new Error('Invalid DICOM file path: empty string'));\n }\n if (PATH_TRAVERSAL_PATTERN.test(input)) {\n return err(new Error(`Invalid DICOM file path: path traversal detected in \"${input}\"`));\n }\n // normalize() resolves `.` segments and trailing separators, ensuring\n // consistent path comparison regardless of input style (e.g., `a//b` → `a/b`).\n const normalized = normalize(input);\n return ok(normalized as DicomFilePath);\n}\n\n/**\n * Creates a validated Port from a raw number.\n *\n * @param input - A number expected to be an integer between 1 and 65535\n * @returns A Result containing the branded Port or an error\n */\nfunction createPort(input: number): Result<Port> {\n if (!Number.isInteger(input) || input < PORT_MIN || input > PORT_MAX) {\n return err(new Error(`Invalid port: ${String(input)}. Must be an integer between ${PORT_MIN} and ${PORT_MAX}`));\n }\n return ok(input as Port);\n}\n\n/**\n * Shorthand for creating a DicomTagPath, throwing on invalid input.\n *\n * Use this when you know the tag path is valid (e.g. hardcoded constants).\n * For user-supplied input, use {@link createDicomTagPath} which returns a Result.\n *\n * @param input - A DICOM tag path string, e.g. `'(0010,0010)'`\n * @returns The branded DicomTagPath\n * @throws Error if the input is not a valid DICOM tag path\n */\nfunction tag(input: string): DicomTagPath {\n const result = createDicomTagPath(input);\n if (!result.ok) throw result.error;\n return result.value;\n}\n\nexport { createDicomTag, createAETitle, createDicomTagPath, createSOPClassUID, createTransferSyntaxUID, createDicomFilePath, createPort, tag };\nexport type { Brand, DicomTag, AETitle, DicomTagPath, SOPClassUID, TransferSyntaxUID, DicomFilePath, Port };\n","/**\n * DICOM tag path parser and serializer.\n *\n * Provides iterative (no recursion) parsing of DICOM tag paths like\n * `(0040,A730)[0].(0040,A160)` into structured segments, and conversion\n * back to dcmodify-compatible strings.\n *\n * Supports wildcard indices `[*]` for use with DicomDataset.findValues.\n *\n * @module dicom/tagPath\n */\n\nimport type { DicomTag, DicomTagPath } from '../brands';\nimport { createDicomTag } from '../brands';\nimport { MAX_TRAVERSAL_DEPTH } from '../constants';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** A single segment of a parsed DICOM tag path. */\ninterface TagSegment {\n /** The DICOM tag for this segment. */\n readonly tag: DicomTag;\n /** The array index for sequence items, or undefined for non-sequence tags. */\n readonly index?: number | undefined;\n /** Whether this segment uses a wildcard index `[*]`. */\n readonly isWildcard?: boolean | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Patterns\n// ---------------------------------------------------------------------------\n\n// Matches a tag segment: (XXXX,XXXX) optionally followed by [N] or [*]\nconst SEGMENT_PATTERN = /^\\(([0-9A-Fa-f]{4}),([0-9A-Fa-f]{4})\\)(?:\\[(\\d+|\\*)\\])?/;\n\n// ---------------------------------------------------------------------------\n// Internal helpers (extracted for complexity/line limits)\n// ---------------------------------------------------------------------------\n\n/** Parses a single regex match into a TagSegment. */\nfunction matchToSegment(match: RegExpExecArray): TagSegment {\n const group = match[1];\n const element = match[2];\n const indexStr = match[3];\n\n /* v8 ignore next 3 */\n if (group === undefined || element === undefined) {\n throw new Error('Failed to parse tag group/element');\n }\n\n const tagResult = createDicomTag(`(${group},${element})`);\n /* v8 ignore next 2 */\n if (!tagResult.ok) throw new Error(`Invalid tag in path: (${group},${element})`);\n\n if (indexStr === '*') return { tag: tagResult.value, isWildcard: true };\n if (indexStr !== undefined) return { tag: tagResult.value, index: Number(indexStr) };\n return { tag: tagResult.value };\n}\n\n/** Advances past the current match and any dot separator. Returns the updated remaining string. */\nfunction advancePastMatch(remaining: string, matchLength: number): string {\n const after = remaining.slice(matchLength);\n if (!after.startsWith('.')) return after;\n if (after.length === 1) throw new Error('Tag path cannot end with a dot separator');\n return after.slice(1);\n}\n\n// ---------------------------------------------------------------------------\n// Parser\n// ---------------------------------------------------------------------------\n\n/**\n * Parses a DICOM tag path into an array of segments.\n *\n * Uses iterative parsing with bounded loop (Rule 8.2: no recursion).\n *\n * @param path - A branded DicomTagPath string\n * @returns An array of TagSegment objects\n * @throws Error if the path is malformed or exceeds MAX_TRAVERSAL_DEPTH\n *\n * @example\n * ```ts\n * tagPathToSegments('(0040,A730)[0].(0040,A160)' as DicomTagPath)\n * // => [\n * // { tag: '(0040,A730)' as DicomTag, index: 0 },\n * // { tag: '(0040,A160)' as DicomTag }\n * // ]\n * ```\n */\nfunction tagPathToSegments(path: DicomTagPath): ReadonlyArray<TagSegment> {\n const segments: TagSegment[] = [];\n let remaining: string = path;\n\n for (let i = 0; i < MAX_TRAVERSAL_DEPTH && remaining.length > 0; i++) {\n const match = SEGMENT_PATTERN.exec(remaining);\n if (match === null) {\n throw new Error(`Invalid tag path segment at position ${path.length - remaining.length}: \"${remaining}\"`);\n }\n segments.push(matchToSegment(match));\n remaining = advancePastMatch(remaining, match[0].length);\n }\n\n if (remaining.length > 0) throw new Error(`Tag path exceeds maximum depth of ${MAX_TRAVERSAL_DEPTH}`);\n if (segments.length === 0) throw new Error('Tag path is empty');\n return segments;\n}\n\n// ---------------------------------------------------------------------------\n// Serializers\n// ---------------------------------------------------------------------------\n\n/**\n * Converts tag segments back to a dcmodify-compatible path string.\n *\n * Format: `(0040,A730)[0].(0040,A160)`\n *\n * @param segments - An array of TagSegment objects\n * @returns A dcmodify-compatible path string\n */\nfunction segmentsToModifyPath(segments: ReadonlyArray<TagSegment>): string {\n const parts: string[] = [];\n for (const seg of segments) {\n let part: string = seg.tag;\n if (seg.isWildcard === true) {\n part += '[*]';\n } else if (seg.index !== undefined) {\n part += `[${seg.index}]`;\n }\n parts.push(part);\n }\n return parts.join('.');\n}\n\n/**\n * Converts tag segments to a canonical display string.\n *\n * Same format as dcmodify path: `(0040,A730)[0].(0040,A160)`\n *\n * @param segments - An array of TagSegment objects\n * @returns A human-readable path string\n */\nfunction segmentsToString(segments: ReadonlyArray<TagSegment>): string {\n return segmentsToModifyPath(segments);\n}\n\nexport { tagPathToSegments, segmentsToModifyPath, segmentsToString };\nexport type { TagSegment };\n","/**\n * Utility for iterating all DICOM tags in a JSON Model dataset.\n *\n * Supports VR filtering and bounded recursion into sequences.\n *\n * @module dicom/walkTags\n */\n\nimport type { DicomJsonElement, DicomJsonModel } from '../tools/_xmlToJson';\n\n/** Maximum default recursion depth for sequence traversal. */\nconst DEFAULT_MAX_DEPTH = 16;\n\n/** Information about a visited DICOM tag. */\ninterface WalkTagEntry {\n /** 8-char hex tag key (e.g., '00100010'). */\n readonly tag: string;\n /** The DICOM JSON element with vr, Value, etc. */\n readonly element: DicomJsonElement;\n /** VR code (e.g., 'PN', 'US', 'SQ'). */\n readonly vr: string;\n /** Nesting depth (0 = top-level). */\n readonly depth: number;\n /** Dot-separated path (e.g., '00081115[0].0020000E'). */\n readonly path: string;\n}\n\n/** Options for walkTags. */\ninterface WalkTagsOptions {\n /** Only visit tags with these VR codes. Omit to visit all. */\n readonly vrFilter?: ReadonlyArray<string> | undefined;\n /** Max recursion depth into sequences. Default: 16. */\n readonly maxDepth?: number | undefined;\n}\n\n/** Internal context passed through recursion to avoid excessive parameters. */\ninterface WalkContext {\n readonly maxDepth: number;\n readonly vrSet: Set<string> | undefined;\n readonly results: WalkTagEntry[];\n}\n\n/**\n * Walks all tags in a DICOM JSON Model dataset.\n *\n * Iterates every tag, optionally filtering by VR and recursing into sequences.\n * Sequences are always recursed into (even if SQ is filtered out) so nested\n * tags can match the VR filter.\n *\n * @param data - A DICOM JSON Model object\n * @param options - Optional VR filter and max depth\n * @returns A readonly array of all matching tag entries\n */\nfunction walkTags(data: DicomJsonModel, options?: WalkTagsOptions): ReadonlyArray<WalkTagEntry> {\n const ctx: WalkContext = {\n maxDepth: options?.maxDepth ?? DEFAULT_MAX_DEPTH,\n vrSet: options?.vrFilter !== undefined ? new Set(options.vrFilter) : undefined,\n results: [],\n };\n walkLevel(data, 0, '', ctx);\n return ctx.results;\n}\n\n/** Recursive helper that walks one level of a DICOM JSON Model. */\nfunction walkLevel(data: DicomJsonModel, depth: number, pathPrefix: string, ctx: WalkContext): void {\n const keys = Object.keys(data);\n for (let i = 0; i < keys.length; i++) {\n const tag = keys[i];\n /* v8 ignore next */\n if (tag === undefined) continue;\n const element = data[tag];\n /* v8 ignore next */\n if (element === undefined) continue;\n const vr = element.vr;\n const path = pathPrefix.length > 0 ? `${pathPrefix}.${tag}` : tag;\n\n if (ctx.vrSet === undefined || ctx.vrSet.has(vr)) {\n ctx.results.push({ tag, element, vr, depth, path });\n }\n\n if (vr === 'SQ' && element.Value !== undefined && depth < ctx.maxDepth) {\n walkSequenceItems(element.Value, depth, path, ctx);\n }\n }\n}\n\n/** Recurses into each item of a sequence Value array. */\nfunction walkSequenceItems(items: ReadonlyArray<unknown>, depth: number, parentPath: string, ctx: WalkContext): void {\n for (let idx = 0; idx < items.length; idx++) {\n const item = items[idx];\n if (typeof item !== 'object' || item === null) continue;\n const itemPath = `${parentPath}[${idx}]`;\n walkLevel(item as DicomJsonModel, depth + 1, itemPath, ctx);\n }\n}\n\nexport { walkTags };\nexport type { WalkTagEntry, WalkTagsOptions };\n","/**\n * Immutable DICOM dataset wrapper with type-safe accessors.\n *\n * Wraps DICOM JSON Model data (PS3.18 F.2) from dcm2json/dcm2xml with\n * convenient read-only accessors. No setters — mutations go through ChangeSet.\n *\n * @module dicom/DicomDataset\n */\n\nimport { stderr } from 'stderr-lib';\nimport type { DicomTag, DicomTagPath, SOPClassUID } from '../brands';\nimport { createSOPClassUID } from '../brands';\nimport { MAX_TRAVERSAL_DEPTH } from '../constants';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport type { TagSegment } from './tagPath';\nimport { tagPathToSegments } from './tagPath';\nimport type { DicomJsonElement, DicomJsonModel } from '../tools/_xmlToJson';\nimport { walkTags as walkTagsFn } from './walkTags';\nimport type { WalkTagEntry, WalkTagsOptions } from './walkTags';\n\n// ---------------------------------------------------------------------------\n// Structural validation\n// ---------------------------------------------------------------------------\n\nconst HEX_TAG_KEY = /^[0-9A-Fa-f]{8}$/;\n\n/**\n * Returns true if the value looks like a DicomJsonElement (has a string `vr` property).\n * This is a lightweight structural check, not a full VR validation.\n */\nfunction isDicomJsonElement(value: unknown): value is DicomJsonElement {\n return typeof value === 'object' && value !== null && 'vr' in value && typeof (value as Record<string, unknown>)['vr'] === 'string';\n}\n\n/**\n * Returns true if the object looks like a DicomJsonModel.\n * Every key must be an 8-char hex string and every value must have { vr: string }.\n */\nfunction isValidDicomJsonModel(obj: Record<string, unknown>): boolean {\n const keys = Object.keys(obj);\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n /* v8 ignore next */\n if (key === undefined) continue;\n if (!HEX_TAG_KEY.test(key)) return false;\n if (!isDicomJsonElement(obj[key])) return false;\n }\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Tag normalization\n// ---------------------------------------------------------------------------\n\nconst TAG_WITH_PARENS = /^\\(([0-9A-Fa-f]{4}),([0-9A-Fa-f]{4})\\)$/;\nconst TAG_HEX_ONLY = /^[0-9A-Fa-f]{8}$/;\n\n/**\n * Normalizes a DICOM tag to 8-char uppercase hex.\n * Accepts `(0010,0010)` or `00100010` formats.\n */\nfunction normalizeTag(tag: DicomTag | string): Result<string> {\n const parenMatch = TAG_WITH_PARENS.exec(tag);\n if (parenMatch !== null) {\n const group = parenMatch[1];\n const element = parenMatch[2];\n /* v8 ignore next */\n if (group === undefined || element === undefined) return err(new Error(`Invalid tag: \"${tag}\"`));\n return ok(`${group}${element}`.toUpperCase());\n }\n if (TAG_HEX_ONLY.test(tag)) {\n return ok(tag.toUpperCase());\n }\n return err(new Error(`Invalid tag format: \"${tag}\". Expected (XXXX,XXXX) or XXXXXXXX`));\n}\n\n// ---------------------------------------------------------------------------\n// Element extraction helpers\n// ---------------------------------------------------------------------------\n\n/** Resolves an element from the data by normalized tag key. */\nfunction resolveElement(data: DicomJsonModel, tagKey: string): DicomJsonElement | undefined {\n return data[tagKey];\n}\n\n/**\n * Extracts the Alphabetic component from a PN (PersonName) value.\n * Returns empty string if the Alphabetic component is missing or the\n * value is not a valid PN object — consistent with DICOM PS3.5 which\n * treats missing components as empty strings.\n */\nfunction extractPNAlphabetic(first: unknown): string {\n if (typeof first !== 'object' || first === null) return '';\n const pn = first as Record<string, unknown>;\n const alphabetic = pn['Alphabetic'];\n return typeof alphabetic === 'string' ? alphabetic : '';\n}\n\n/** Converts a primitive value to string. */\nfunction primitiveToString(value: unknown): string {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n return '';\n}\n\n/** Extracts a string from a DicomJsonElement, handling PN values. */\nfunction extractString(element: DicomJsonElement): string {\n const values = element.Value;\n if (values === undefined || values.length === 0) return '';\n\n const first = values[0];\n if (first === undefined || first === null) return '';\n\n if (element.vr === 'PN') return extractPNAlphabetic(first);\n return primitiveToString(first);\n}\n\n/** Extracts a number from a DicomJsonElement with validation. */\nfunction extractNumber(element: DicomJsonElement): Result<number> {\n const values = element.Value;\n if (values === undefined || values.length === 0) {\n return err(new Error('Element has no Value array'));\n }\n const first = values[0];\n if (typeof first === 'number') return ok(first);\n if (typeof first === 'string') {\n const parsed = Number(first);\n if (Number.isNaN(parsed)) {\n return err(new Error(`Cannot convert \"${first}\" to number`));\n }\n return ok(parsed);\n }\n return err(new Error(`Value is not numeric: ${typeof first}`));\n}\n\n/** Extracts all values as strings from a DicomJsonElement. */\nfunction extractStrings(element: DicomJsonElement): ReadonlyArray<string> {\n const values = element.Value;\n if (values === undefined) return [];\n const result: string[] = [];\n for (const v of values) {\n if (typeof v === 'string') {\n result.push(v);\n } else if (typeof v === 'number' || typeof v === 'boolean') {\n result.push(String(v));\n } else {\n result.push('');\n }\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Path traversal helpers (iterative, no recursion — Rule 8.2)\n// ---------------------------------------------------------------------------\n\n/** Gets the sequence items array from a DicomJsonElement. */\nfunction getSequenceItems(element: DicomJsonElement): ReadonlyArray<unknown> | undefined {\n if (element.vr !== 'SQ' || element.Value === undefined) return undefined;\n return element.Value;\n}\n\n/** Returns true if the value is a plausible DicomJsonModel (non-null object with no array). */\nfunction isPlausibleModel(value: unknown): value is DicomJsonModel {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Descends into a sequence item, returning the nested dataset or an error. */\nfunction descendIntoSequence(element: DicomJsonElement, seg: TagSegment): Result<DicomJsonModel> {\n const items = getSequenceItems(element);\n if (items === undefined) {\n return err(new Error(`Tag ${seg.tag} is not a sequence`));\n }\n const idx = seg.index ?? 0;\n const item = items[idx];\n if (!isPlausibleModel(item)) {\n return err(new Error(`Sequence ${seg.tag} has no valid item at index ${idx}`));\n }\n return ok(item);\n}\n\n/** Traverses a non-wildcard path iteratively through nested sequences. */\nfunction traversePath(data: DicomJsonModel, segments: ReadonlyArray<TagSegment>): Result<DicomJsonElement> {\n let current: DicomJsonModel = data;\n\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i];\n /* v8 ignore next */\n if (seg === undefined) return err(new Error('Unexpected undefined segment'));\n\n const tagResult = normalizeTag(seg.tag);\n if (!tagResult.ok) return err(tagResult.error);\n\n const element = resolveElement(current, tagResult.value);\n if (element === undefined) return err(new Error(`Tag ${seg.tag} not found`));\n\n if (i === segments.length - 1) return ok(element);\n\n const descent = descendIntoSequence(element, seg);\n if (!descent.ok) return err(descent.error);\n current = descent.value;\n }\n\n /* v8 ignore next */\n return err(new Error('Empty path segments'));\n}\n\n// ---------------------------------------------------------------------------\n// Wildcard collection (iterative queue — Rule 8.2)\n// ---------------------------------------------------------------------------\n\ninterface QueueEntry {\n readonly data: DicomJsonModel;\n readonly segmentIndex: number;\n}\n\ninterface WildcardResult {\n readonly values: ReadonlyArray<unknown>;\n readonly truncated: boolean;\n}\n\n/** Collects all values matching a wildcard path using an iterative BFS queue. */\nfunction collectWildcard(data: DicomJsonModel, segments: ReadonlyArray<TagSegment>): WildcardResult {\n const results: unknown[] = [];\n const queue: QueueEntry[] = [{ data, segmentIndex: 0 }];\n const maxIterations = MAX_TRAVERSAL_DEPTH * 100;\n\n let iteration = 0;\n for (; iteration < maxIterations && queue.length > 0; iteration++) {\n const entry = queue.shift();\n /* v8 ignore next */\n if (entry === undefined) break;\n processQueueEntry(entry, segments, results, queue);\n }\n\n return { values: results, truncated: iteration >= maxIterations && queue.length > 0 };\n}\n\n/** Processes a single queue entry for wildcard collection. */\nfunction processQueueEntry(entry: QueueEntry, segments: ReadonlyArray<TagSegment>, results: unknown[], queue: QueueEntry[]): void {\n const seg = segments[entry.segmentIndex];\n /* v8 ignore next */\n if (seg === undefined) return;\n\n const tagResult = normalizeTag(seg.tag);\n if (!tagResult.ok) return;\n\n const element = resolveElement(entry.data, tagResult.value);\n if (element === undefined) return;\n\n const isLast = entry.segmentIndex === segments.length - 1;\n\n if (isLast) {\n collectLeafValues(element, results);\n return;\n }\n\n enqueueSequenceItems(element, seg, entry.segmentIndex, queue);\n}\n\n/** Collects values from a leaf element into the results array. */\nfunction collectLeafValues(element: DicomJsonElement, results: unknown[]): void {\n if (element.Value !== undefined) {\n for (const v of element.Value) {\n results.push(v);\n }\n }\n}\n\n/** Enqueues child sequence items for further wildcard processing. */\nfunction enqueueSequenceItems(element: DicomJsonElement, seg: TagSegment, segmentIndex: number, queue: QueueEntry[]): void {\n const items = getSequenceItems(element);\n if (items === undefined) return;\n\n if (seg.isWildcard === true) {\n for (const item of items) {\n if (isPlausibleModel(item)) {\n queue.push({ data: item, segmentIndex: segmentIndex + 1 });\n }\n }\n } else {\n const idx = seg.index ?? 0;\n const item = items[idx];\n if (isPlausibleModel(item)) {\n queue.push({ data: item, segmentIndex: segmentIndex + 1 });\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Well-known DICOM tag keys (8-char hex, uppercase)\n// ---------------------------------------------------------------------------\n\nconst TAGS = {\n AccessionNumber: '00080050',\n PatientName: '00100010',\n PatientID: '00100020',\n StudyDate: '00080020',\n Modality: '00080060',\n SOPClassUID: '00080016',\n StudyInstanceUID: '0020000D',\n SeriesInstanceUID: '0020000E',\n SOPInstanceUID: '00080018',\n TransferSyntaxUID: '00020010',\n} as const;\n\n// ---------------------------------------------------------------------------\n// DicomDataset class\n// ---------------------------------------------------------------------------\n\n/**\n * Immutable wrapper around DICOM JSON Model data.\n *\n * Provides type-safe read-only accessors for DICOM tag values.\n * Construct via the static {@link DicomDataset.fromJson} factory.\n *\n * @example\n * ```ts\n * const result = DicomDataset.fromJson(jsonData);\n * if (result.ok) {\n * const ds = result.value;\n * console.log(ds.patientName);\n * console.log(ds.modality);\n * }\n * ```\n */\nclass DicomDataset {\n private readonly data: DicomJsonModel;\n\n private constructor(data: DicomJsonModel) {\n this.data = data;\n }\n\n /**\n * Creates a DicomDataset from a DICOM JSON Model object.\n *\n * Performs structural validation only — verifies the input is a non-null object.\n *\n * @param json - A DICOM JSON Model object (typically from dcm2json)\n * @returns A Result containing the DicomDataset or an error\n */\n static fromJson(json: unknown): Result<DicomDataset> {\n if (json === null || json === undefined || typeof json !== 'object' || Array.isArray(json)) {\n return err(new Error('Invalid DICOM JSON: expected a non-null, non-array object'));\n }\n const obj = json as Record<string, unknown>;\n if (!isValidDicomJsonModel(obj)) {\n return err(new Error('Invalid DICOM JSON: every key must be an 8-char hex tag and every value must have a \"vr\" string property'));\n }\n return ok(new DicomDataset(json as DicomJsonModel));\n }\n\n /**\n * Gets the full DICOM JSON element for a tag.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the element or an error if not found\n */\n getElement(tag: DicomTag | string): Result<DicomJsonElement> {\n const norm = normalizeTag(tag);\n if (!norm.ok) return err(norm.error);\n const element = resolveElement(this.data, norm.value);\n if (element === undefined) return err(new Error(`Tag ${tag} not found`));\n return ok(element);\n }\n\n /**\n * Gets the Value array for a tag.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the readonly Value array or an error\n */\n getValue(tag: DicomTag | string): Result<ReadonlyArray<unknown>> {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return err(elemResult.error);\n const values = elemResult.value.Value;\n if (values === undefined) return err(new Error(`Tag ${tag} has no Value`));\n return ok(values);\n }\n\n /**\n * Gets the first element of the Value array for a tag.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the first value or an error\n */\n getFirstValue(tag: DicomTag | string): Result<unknown> {\n const valResult = this.getValue(tag);\n if (!valResult.ok) return err(valResult.error);\n const first = valResult.value[0];\n if (first === undefined) return err(new Error(`Tag ${tag} Value array is empty`));\n return ok(first);\n }\n\n /**\n * Gets a tag value as a string with optional fallback.\n *\n * Returns the fallback (default empty string) if the tag is missing or has no value.\n * Handles PN (PersonName) values by extracting the Alphabetic component.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @param fallback - Value to return if tag is missing (default: `''`)\n * @returns The string value or the fallback\n */\n getString(tag: DicomTag | string, fallback = ''): string {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return fallback;\n const str = extractString(elemResult.value);\n return str.length > 0 ? str : fallback;\n }\n\n /**\n * Gets a tag value as a validated number.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the number or an error\n */\n getNumber(tag: DicomTag | string): Result<number> {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return err(elemResult.error);\n return extractNumber(elemResult.value);\n }\n\n /**\n * Gets all values of a tag as strings.\n *\n * Useful for multi-valued tags like CS (Code String).\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the readonly string array or an error\n */\n getStrings(tag: DicomTag | string): Result<ReadonlyArray<string>> {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return err(elemResult.error);\n return ok(extractStrings(elemResult.value));\n }\n\n /**\n * Checks whether a tag exists in the dataset.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns `true` if the tag is present\n */\n hasTag(tag: DicomTag | string): boolean {\n const norm = normalizeTag(tag);\n if (!norm.ok) return false;\n return resolveElement(this.data, norm.value) !== undefined;\n }\n\n /**\n * Gets an element by traversing a dotted tag path through sequences.\n *\n * @param path - A branded DicomTagPath, e.g. `(0040,A730)[0].(0040,A160)`\n * @returns Result containing the element at the path or an error\n */\n getElementAtPath(path: DicomTagPath): Result<DicomJsonElement> {\n let segments: ReadonlyArray<TagSegment>;\n try {\n segments = tagPathToSegments(path);\n } catch (e: unknown) {\n return err(stderr(e));\n }\n return traversePath(this.data, segments);\n }\n\n /**\n * Finds all values matching a path with wildcard `[*]` indices.\n *\n * Traverses all items in wildcard sequence positions using an iterative BFS queue.\n * The traversal is bounded to {@link MAX_TRAVERSAL_DEPTH} * 100 iterations (5 000).\n * For extremely large datasets this may truncate results silently; callers\n * needing completeness guarantees should verify dataset size independently.\n *\n * @param path - A branded DicomTagPath, e.g. `(0040,A730)[*].(0040,A160)`\n * @returns A readonly array of all matching values (may be empty)\n */\n findValues(path: DicomTagPath): ReadonlyArray<unknown> {\n let segments: ReadonlyArray<TagSegment>;\n try {\n segments = tagPathToSegments(path);\n } catch {\n return [];\n }\n const result = collectWildcard(this.data, segments);\n return result.values;\n }\n\n /**\n * Walks all tags in this dataset, optionally filtering by VR and recursing into sequences.\n *\n * @param options - Optional VR filter and max depth\n * @returns A readonly array of all matching tag entries\n */\n walkTags(options?: WalkTagsOptions): ReadonlyArray<WalkTagEntry> {\n return walkTagsFn(this.data, options);\n }\n\n // -----------------------------------------------------------------------\n // Convenience readonly getters\n // -----------------------------------------------------------------------\n\n /** Accession Number (0008,0050). */\n get accession(): string {\n return this.getString(TAGS.AccessionNumber);\n }\n\n /** Patient's Name (0010,0010). */\n get patientName(): string {\n return this.getString(TAGS.PatientName);\n }\n\n /** Patient ID (0010,0020). */\n get patientID(): string {\n return this.getString(TAGS.PatientID);\n }\n\n /** Study Date (0008,0020). */\n get studyDate(): string {\n return this.getString(TAGS.StudyDate);\n }\n\n /** Modality (0008,0060). */\n get modality(): string {\n return this.getString(TAGS.Modality);\n }\n\n /** SOP Class UID (0008,0016) as a branded SOPClassUID, or undefined if missing/invalid. */\n get sopClassUID(): SOPClassUID | undefined {\n const uid = this.getString(TAGS.SOPClassUID);\n if (uid.length === 0) return undefined;\n const result = createSOPClassUID(uid);\n return result.ok ? result.value : undefined;\n }\n\n /** Study Instance UID (0020,000D). */\n get studyInstanceUID(): string {\n return this.getString(TAGS.StudyInstanceUID);\n }\n\n /** Series Instance UID (0020,000E). */\n get seriesInstanceUID(): string {\n return this.getString(TAGS.SeriesInstanceUID);\n }\n\n /** SOP Instance UID (0008,0018). */\n get sopInstanceUID(): string {\n return this.getString(TAGS.SOPInstanceUID);\n }\n\n /** Transfer Syntax UID (0002,0010). */\n get transferSyntaxUID(): string {\n return this.getString(TAGS.TransferSyntaxUID);\n }\n}\n\nexport { DicomDataset };\n","/**\n * Immutable mutation tracking for DICOM datasets.\n *\n * Every mutation method returns a new ChangeSet instance, preserving immutability.\n * Bridge methods produce dcmodify-compatible arguments for applying changes to files.\n *\n * @module dicom/ChangeSet\n */\n\nimport type { TagModification } from '../tools/dcmodify';\nimport { MAX_CHANGESET_OPERATIONS } from '../constants';\nimport type { DicomTagPath } from '../brands';\nimport { tagPathToSegments } from './tagPath';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Sentinel value in the erasures set to indicate erasing all private tags. */\nconst ERASE_PRIVATE_SENTINEL = '__ERASE_PRIVATE__';\n\n// ---------------------------------------------------------------------------\n// Helpers (extracted for complexity/line limits)\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true if a char code is a control character to strip.\n * Strips 0x00-0x09, 0x0B, 0x0C, 0x0E-0x1F, 0x7F.\n * Preserves LF (0x0A), CR (0x0D), and backslash.\n */\nfunction isControlChar(code: number): boolean {\n if (code <= 0x09) return true;\n if (code === 0x0b || code === 0x0c) return true;\n if (code >= 0x0e && code <= 0x1f) return true;\n return code === 0x7f;\n}\n\n/** Strips control characters from a value while preserving LF, CR, and backslash. */\nfunction sanitizeValue(value: string): string {\n let result = '';\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (!isControlChar(code)) {\n result += value[i];\n }\n }\n return result;\n}\n\n/** Merges two modification maps, with `other` winning conflicts. Removes keys present in erasures. */\nfunction buildMergedModifications(\n base: ReadonlyMap<string, string>,\n other: ReadonlyMap<string, string>,\n erasures: ReadonlySet<string>\n): ReadonlyMap<string, string> {\n const merged = new Map<string, string>(base);\n for (const [key, value] of other) {\n merged.set(key, value);\n }\n for (const key of erasures) {\n merged.delete(key);\n }\n return merged;\n}\n\n/** Iteratively applies all entries to a ChangeSet, returning the final result. */\nfunction applyBatchEntries(initial: ChangeSet, entries: Readonly<Record<string, string>>): ChangeSet {\n const keys = Object.keys(entries);\n let cs = initial;\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n /* v8 ignore next */\n if (key === undefined) continue;\n const value = entries[key];\n /* v8 ignore next */\n if (value === undefined) continue;\n cs = cs.setTag(key, value);\n }\n return cs;\n}\n\n// ---------------------------------------------------------------------------\n// ChangeSet class\n// ---------------------------------------------------------------------------\n\n/**\n * Immutable mutation tracker for DICOM datasets.\n *\n * Every mutation method returns a **new** ChangeSet — the original is never modified.\n * Use {@link ChangeSet.toModifications} and {@link ChangeSet.toErasureArgs} to bridge\n * to the dcmodify tool wrapper.\n *\n * @example\n * ```ts\n * const cs = ChangeSet.empty()\n * .setTag('(0010,0010)' as DicomTagPath, 'Anonymous')\n * .eraseTag('(0010,0020)' as DicomTagPath)\n * .erasePrivateTags();\n * ```\n */\nclass ChangeSet {\n private readonly mods: ReadonlyMap<string, string>;\n private readonly erased: ReadonlySet<string>;\n\n private constructor(mods: ReadonlyMap<string, string>, erasures: ReadonlySet<string>) {\n this.mods = mods;\n this.erased = erasures;\n }\n\n /** Creates an empty ChangeSet with no modifications or erasures. */\n static empty(): ChangeSet {\n return new ChangeSet(new Map(), new Set());\n }\n\n /**\n * Sets a tag value, returning a new ChangeSet.\n *\n * Control characters (except LF/CR) are stripped from the value.\n * If the tag was previously erased, it is removed from the erasure set.\n *\n * @param path - The DICOM tag path to set (e.g. `'(0010,0010)'`)\n * @param value - The new value for the tag\n * @returns A new ChangeSet with the modification applied\n * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS\n */\n setTag(path: string, value: string): ChangeSet {\n const totalOps = this.mods.size + this.erased.size;\n if (totalOps >= MAX_CHANGESET_OPERATIONS) {\n throw new Error(`ChangeSet operation limit (${MAX_CHANGESET_OPERATIONS}) exceeded`);\n }\n tagPathToSegments(path as DicomTagPath);\n const sanitized = sanitizeValue(value);\n const newMods = new Map(this.mods);\n newMods.set(path, sanitized);\n const newErasures = new Set(this.erased);\n newErasures.delete(path);\n return new ChangeSet(newMods, newErasures);\n }\n\n /**\n * Marks a tag for erasure, returning a new ChangeSet.\n *\n * If the tag was previously set, the modification is removed.\n *\n * @param path - The DICOM tag path to erase (e.g. `'(0010,0010)'`)\n * @returns A new ChangeSet with the erasure applied\n * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS\n */\n eraseTag(path: string): ChangeSet {\n const totalOps = this.mods.size + this.erased.size;\n if (totalOps >= MAX_CHANGESET_OPERATIONS) {\n throw new Error(`ChangeSet operation limit (${MAX_CHANGESET_OPERATIONS}) exceeded`);\n }\n tagPathToSegments(path as DicomTagPath);\n const newMods = new Map(this.mods);\n newMods.delete(path);\n const newErasures = new Set(this.erased);\n newErasures.add(path);\n return new ChangeSet(newMods, newErasures);\n }\n\n /**\n * Marks all private tags for erasure, returning a new ChangeSet.\n *\n * @returns A new ChangeSet with the erase-private flag set\n * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS\n */\n erasePrivateTags(): ChangeSet {\n const totalOps = this.mods.size + this.erased.size;\n if (totalOps >= MAX_CHANGESET_OPERATIONS) {\n throw new Error(`ChangeSet operation limit (${MAX_CHANGESET_OPERATIONS}) exceeded`);\n }\n const newErasures = new Set(this.erased);\n newErasures.add(ERASE_PRIVATE_SENTINEL);\n return new ChangeSet(new Map(this.mods), newErasures);\n }\n\n // -----------------------------------------------------------------------\n // Convenience setters for common DICOM tags\n // -----------------------------------------------------------------------\n\n /** Sets Patient's Name (0010,0010). */\n setPatientName(value: string): ChangeSet {\n return this.setTag('(0010,0010)', value);\n }\n\n /** Sets Patient ID (0010,0020). */\n setPatientID(value: string): ChangeSet {\n return this.setTag('(0010,0020)', value);\n }\n\n /** Sets Study Date (0008,0020). */\n setStudyDate(value: string): ChangeSet {\n return this.setTag('(0008,0020)', value);\n }\n\n /** Sets Modality (0008,0060). */\n setModality(value: string): ChangeSet {\n return this.setTag('(0008,0060)', value);\n }\n\n /** Sets Accession Number (0008,0050). */\n setAccessionNumber(value: string): ChangeSet {\n return this.setTag('(0008,0050)', value);\n }\n\n /** Sets Study Description (0008,1030). */\n setStudyDescription(value: string): ChangeSet {\n return this.setTag('(0008,1030)', value);\n }\n\n /** Sets Series Description (0008,103E). */\n setSeriesDescription(value: string): ChangeSet {\n return this.setTag('(0008,103E)', value);\n }\n\n /** Sets Institution Name (0008,0080). */\n setInstitutionName(value: string): ChangeSet {\n return this.setTag('(0008,0080)', value);\n }\n\n /**\n * Sets multiple tags at once, returning a new ChangeSet.\n *\n * @param entries - A record of tag path → value pairs\n * @returns A new ChangeSet with all modifications applied\n */\n setBatch(entries: Readonly<Record<string, string>>): ChangeSet {\n return applyBatchEntries(this, entries);\n }\n\n /** All pending tag modifications as a readonly map of path → value. */\n get modifications(): ReadonlyMap<string, string> {\n return this.mods;\n }\n\n /** All pending tag erasures as a readonly set of paths. */\n get erasures(): ReadonlySet<string> {\n return this.erased;\n }\n\n /** Total number of operations (modifications + erasures) in this ChangeSet. */\n get operationCount(): number {\n return this.mods.size + this.erased.size;\n }\n\n /** Whether the ChangeSet has no modifications and no erasures. */\n get isEmpty(): boolean {\n return this.mods.size === 0 && this.erased.size === 0;\n }\n\n /** Whether the erase-all-private-tags flag is set. */\n get erasePrivate(): boolean {\n return this.erased.has(ERASE_PRIVATE_SENTINEL);\n }\n\n /**\n * Merges another ChangeSet into this one, returning a new ChangeSet.\n *\n * The `other` ChangeSet wins on conflicts: if the same tag is modified in both,\n * `other`'s value is used. Erasures from both sets are unioned. An erasure in\n * `other` removes a modification from `base`.\n *\n * @param other - The ChangeSet to merge in\n * @returns A new ChangeSet with merged modifications and erasures\n */\n merge(other: ChangeSet): ChangeSet {\n const mergedErasures = new Set([...this.erased, ...other.erased]);\n const mergedMods = buildMergedModifications(this.mods, other.mods, mergedErasures);\n return new ChangeSet(mergedMods, mergedErasures);\n }\n\n /**\n * Converts modifications to dcmodify-compatible TagModification array.\n *\n * @returns A readonly array of TagModification objects\n */\n toModifications(): ReadonlyArray<TagModification> {\n const result: TagModification[] = [];\n for (const [tag, value] of this.mods) {\n result.push({ tag, value });\n }\n return result;\n }\n\n /**\n * Converts erasures to dcmodify-compatible argument strings.\n *\n * The erase-private sentinel is excluded — use {@link erasePrivate} to check\n * whether `-ep` should be passed.\n *\n * @returns A readonly array of tag path strings for `-e` arguments\n */\n toErasureArgs(): ReadonlyArray<string> {\n const result: string[] = [];\n for (const path of this.erased) {\n if (path !== ERASE_PRIVATE_SENTINEL) {\n result.push(path);\n }\n }\n return result;\n }\n}\n\nexport { ChangeSet };\n","/**\n * Short-lived DCMTK process execution.\n *\n * Two execution modes:\n * - `execCommand()` — convenience wrapper; uses `spawn()` internally for safety\n * - `spawnCommand()` — uses `child_process.spawn()`, safer for user-supplied values (Rule 7.4)\n *\n * Both enforce mandatory timeouts (Rule 4.2) and return `Result<DcmtkProcessResult>`.\n *\n * @module exec\n */\n\nimport { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport kill from 'tree-kill';\nimport type { Result, DcmtkProcessResult, ExecOptions, SpawnOptions } from './types';\nimport { ok, err } from './types';\nimport { DEFAULT_TIMEOUT_MS, MAX_OUTPUT_BYTES } from './constants';\n\n/**\n * Kills a process tree by PID. Wraps tree-kill in a promise.\n *\n * @param pid - The process ID to kill\n */\nfunction killTree(pid: number): void {\n try {\n kill(pid);\n /* v8 ignore next */\n } catch {\n // Process may already be dead — not exceptional\n }\n}\n\n/**\n * Executes a DCMTK binary as a short-lived process.\n *\n * **Security:** This function uses `child_process.spawn()` internally, passing\n * arguments as an array to avoid shell interpretation. This eliminates shell\n * injection risks regardless of argument content (Rule 7.4).\n *\n * @param binary - Full path to the DCMTK binary\n * @param args - Command-line arguments (passed directly, no shell interpolation)\n * @param options - Execution options (timeout, cwd, signal)\n * @returns A Result containing the process output or an error\n * @throws Never throws for expected failures (Rule 6.1)\n *\n * @example\n * ```ts\n * const result = await execCommand('/usr/local/bin/dcm2json', ['+ll', 'input.dcm']);\n * if (result.ok) {\n * console.log(result.value.stdout);\n * }\n * ```\n */\nasync function execCommand(binary: string, args: readonly string[], options?: ExecOptions): Promise<Result<DcmtkProcessResult>> {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n return new Promise(resolve => {\n const child = spawn(binary, [...args], {\n cwd: options?.cwd,\n windowsHide: true,\n signal: options?.signal,\n });\n wireSpawnListeners(binary, child, timeoutMs, resolve);\n });\n}\n\n/**\n * Wires event listeners on a spawned child process with timeout, bounded buffering, and settle logic.\n */\nfunction wireSpawnListeners(binary: string, child: ChildProcess, timeoutMs: number, resolve: (result: Result<DcmtkProcessResult>) => void): void {\n let stdout = '';\n let stderr = '';\n let settled = false;\n const name = binary.split('/').pop() ?? binary;\n\n const settle = (result: Result<DcmtkProcessResult>): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(result);\n };\n\n const timer = setTimeout(() => {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`${name} timed out after ${timeoutMs}ms (pid: ${String(child.pid ?? 'unknown')})`)));\n }, timeoutMs);\n\n child.stdout?.on('data', (chunk: Buffer | string) => {\n stdout += String(chunk);\n if (stdout.length + stderr.length > MAX_OUTPUT_BYTES) {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`${name} output exceeded ${MAX_OUTPUT_BYTES} bytes`)));\n }\n });\n\n child.stderr?.on('data', (chunk: Buffer | string) => {\n stderr += String(chunk);\n if (stdout.length + stderr.length > MAX_OUTPUT_BYTES) {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`${name} output exceeded ${MAX_OUTPUT_BYTES} bytes`)));\n }\n });\n\n child.on('error', (error: Error) => {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`${name} error: ${error.message}`)));\n });\n\n child.on('close', (code: number | null) => {\n settle(ok({ stdout, stderr, exitCode: code ?? 1 }));\n });\n}\n\n/**\n * Executes a DCMTK binary using `child_process.spawn()`.\n *\n * Like {@link execCommand}, arguments are passed as an array to avoid shell\n * injection (Rule 7.4). This variant additionally supports custom environment\n * variables via the `env` option.\n *\n * @param binary - Full path to the DCMTK binary\n * @param args - Command-line arguments (passed directly, no shell interpolation)\n * @param options - Execution options (timeout, cwd, signal, env)\n * @returns A Result containing the process output or an error\n * @throws Never throws for expected failures (Rule 6.1)\n *\n * @example\n * ```ts\n * const result = await spawnCommand('/usr/local/bin/dcmodify', ['-m', '(0010,0010)=Smith^John', 'input.dcm']);\n * ```\n */\nasync function spawnCommand(binary: string, args: readonly string[], options?: SpawnOptions): Promise<Result<DcmtkProcessResult>> {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n return new Promise(resolve => {\n const child = spawn(binary, [...args], {\n cwd: options?.cwd,\n env: options?.env ? { ...process.env, ...options.env } : undefined,\n windowsHide: true,\n signal: options?.signal,\n });\n wireSpawnListeners(binary, child, timeoutMs, resolve);\n });\n}\n\nexport { execCommand, spawnCommand };\n","/**\n * Converts dcm2xml \"Native DICOM Model\" XML into the DICOM JSON Model (PS3.18 F.2).\n *\n * dcm2xml outputs XML in the DCMTK native format:\n * ```xml\n * <NativeDicomModel>\n * <DicomAttribute tag=\"00100010\" vr=\"PN\" keyword=\"PatientName\">\n * <PersonName number=\"1\">\n * <Alphabetic><FamilyName>Smith</FamilyName></Alphabetic>\n * </PersonName>\n * </DicomAttribute>\n * <DicomAttribute tag=\"00100020\" vr=\"LO\" keyword=\"PatientID\">\n * <Value number=\"1\">12345</Value>\n * </DicomAttribute>\n * </NativeDicomModel>\n * ```\n *\n * The DICOM JSON Model output:\n * ```json\n * {\n * \"00100010\": { \"vr\": \"PN\", \"Value\": [{\"Alphabetic\": \"Smith\"}] },\n * \"00100020\": { \"vr\": \"LO\", \"Value\": [\"12345\"] }\n * }\n * ```\n *\n * @module _xmlToJson\n * @internal\n */\n\nimport { XMLParser } from 'fast-xml-parser';\nimport { stderr } from 'stderr-lib';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\n\n/** DICOM JSON Model element. */\ninterface DicomJsonElement {\n readonly vr: string;\n readonly Value?: ReadonlyArray<unknown>;\n readonly InlineBinary?: string;\n readonly BulkDataURI?: string;\n}\n\n/** Mutable builder for DicomJsonElement during conversion. */\ninterface ElementBuilder {\n vr: string;\n Value?: unknown[];\n InlineBinary?: string;\n BulkDataURI?: string;\n}\n\n/** DICOM JSON Model top-level object. */\ntype DicomJsonModel = Record<string, DicomJsonElement>;\n\n/** Parsed XML attribute node from fast-xml-parser. */\ninterface XmlDicomAttribute {\n readonly '@_tag': string;\n readonly '@_vr': string;\n readonly '@_keyword'?: string;\n readonly Value?: unknown;\n readonly PersonName?: unknown;\n readonly InlineBinary?: unknown;\n readonly BulkDataURI?: unknown;\n readonly Item?: unknown;\n}\n\n/** Person name components from XML. */\ninterface XmlPersonNameComponent {\n readonly FamilyName?: string;\n readonly GivenName?: string;\n readonly MiddleName?: string;\n readonly NamePrefix?: string;\n readonly NameSuffix?: string;\n}\n\n/** PN representation types. */\ntype PnRepType = 'Alphabetic' | 'Ideographic' | 'Phonetic';\nconst PN_REPS: readonly PnRepType[] = ['Alphabetic', 'Ideographic', 'Phonetic'];\n\nconst ARRAY_TAG_NAMES = new Set(['DicomAttribute', 'Value', 'PersonName', 'Item']);\n\n/**\n * The 34 standard DICOM VR codes (PS3.5 Table 6.2-1).\n * Used to validate VR values from DCMTK XML output. Unrecognized VRs\n * (e.g. retired/internal codes like \"xs\", \"ox\") fall back to 'UN'.\n */\nconst KNOWN_VR_CODES = new Set([\n 'AE',\n 'AS',\n 'AT',\n 'CS',\n 'DA',\n 'DS',\n 'DT',\n 'FD',\n 'FL',\n 'IS',\n 'LO',\n 'LT',\n 'OB',\n 'OD',\n 'OF',\n 'OL',\n 'OV',\n 'OW',\n 'PN',\n 'SH',\n 'SL',\n 'SQ',\n 'SS',\n 'ST',\n 'SV',\n 'TM',\n 'UC',\n 'UI',\n 'UL',\n 'UN',\n 'UR',\n 'US',\n 'UT',\n 'UV',\n]);\n\n/**\n * Builds a PN string from name components.\n */\nfunction buildPnString(comp: XmlPersonNameComponent): string {\n const parts = [comp.FamilyName ?? '', comp.GivenName ?? '', comp.MiddleName ?? '', comp.NamePrefix ?? '', comp.NameSuffix ?? ''];\n let last = parts.length - 1;\n for (; last >= 0; last--) {\n if (parts[last] !== '') break;\n }\n return parts.slice(0, last + 1).join('^');\n}\n\n/** Ensures a value is an array. */\nfunction toArray(val: unknown): readonly unknown[] {\n if (Array.isArray(val)) return val;\n if (val === undefined || val === null) return [];\n return [val];\n}\n\n/**\n * Converts a PersonName XML element to DICOM JSON PN format.\n */\nfunction convertPersonName(pnNode: unknown): Record<string, string> {\n const result: Record<string, string> = {};\n /* v8 ignore next -- defensive guard for malformed XML */\n if (typeof pnNode !== 'object' || pnNode === null) return result;\n const pn = pnNode as Record<string, unknown>;\n\n for (const rep of PN_REPS) {\n const repNode = pn[rep];\n if (repNode !== undefined && typeof repNode === 'object' && repNode !== null) {\n const str = buildPnString(repNode as XmlPersonNameComponent);\n if (str.length > 0) {\n result[rep] = str;\n }\n }\n }\n return result;\n}\n\n/** Safely converts an unknown value to a string without risking [object Object]. */\nfunction safeString(val: unknown): string {\n if (typeof val === 'string') return val;\n if (typeof val === 'number' || typeof val === 'boolean') return String(val);\n /* v8 ignore next */\n return '';\n}\n\n/** Handles InlineBinary elements. */\nfunction convertInlineBinary(attr: XmlDicomAttribute, element: ElementBuilder): void {\n element.InlineBinary = safeString(attr.InlineBinary);\n}\n\n/** Handles BulkDataURI elements. */\nfunction convertBulkDataURI(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const bulkArray = toArray(attr.BulkDataURI);\n const firstBulk = bulkArray[0];\n if (typeof firstBulk === 'object' && firstBulk !== null && '@_uri' in firstBulk) {\n element.BulkDataURI = safeString((firstBulk as Record<string, unknown>)['@_uri']);\n } else {\n element.BulkDataURI = safeString(firstBulk);\n }\n}\n\n/** Handles PersonName (PN VR) elements. */\nfunction convertPNValue(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const pnArray = toArray(attr.PersonName);\n const values: Record<string, string>[] = [];\n for (const pn of pnArray) {\n values.push(convertPersonName(pn));\n }\n if (values.length > 0) element.Value = values;\n}\n\n/** Handles Sequence (SQ) elements. */\nfunction convertSequence(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const items = toArray(attr.Item);\n const values: DicomJsonModel[] = [];\n for (const item of items) {\n /* v8 ignore next -- defensive guard for malformed XML */\n if (typeof item !== 'object' || item === null) continue;\n values.push(convertAttributes(item as Record<string, unknown>));\n }\n if (values.length > 0) element.Value = values;\n}\n\n/** VRs whose values MUST be JSON numbers per DICOM PS3.18 F.2.3. */\nconst NUMERIC_JSON_VRS = new Set(['DS', 'FL', 'FD', 'IS', 'SL', 'SS', 'SV', 'UL', 'US', 'UV']);\n\n/** Unwraps fast-xml-parser attribute wrapper objects (e.g., {@_number: \"1\"}). */\nfunction unwrapValue(v: unknown): unknown {\n if (typeof v !== 'object' || v === null) return v;\n const obj = v as Record<string, unknown>;\n if ('#text' in obj) return obj['#text'];\n const keys = Object.keys(obj);\n if (keys.length === 1 && keys[0] !== undefined && keys[0].startsWith('@_')) {\n return obj[keys[0]];\n }\n return v;\n}\n\n/** Coerces a value to a number. Returns the original if not parseable. */\nfunction coerceNumeric(value: unknown): unknown {\n if (typeof value === 'number') return value;\n if (typeof value !== 'string') return value;\n const trimmed = value.trim();\n if (trimmed.length === 0) return value;\n const num = Number(trimmed);\n return Number.isNaN(num) ? value : num;\n}\n\n/** Handles regular Value elements. */\nfunction convertRegularValue(attr: XmlDicomAttribute, element: ElementBuilder, vr: string): void {\n const valArray = toArray(attr.Value);\n const values: unknown[] = [];\n const isNumeric = NUMERIC_JSON_VRS.has(vr);\n for (const v of valArray) {\n const unwrapped = unwrapValue(v);\n values.push(isNumeric ? coerceNumeric(unwrapped) : unwrapped);\n }\n if (values.length > 0) element.Value = values;\n}\n\n/**\n * Converts a single DicomAttribute XML element to its DICOM JSON element.\n */\nfunction convertElement(attr: XmlDicomAttribute): DicomJsonElement {\n const rawVr = attr['@_vr'];\n const vr = KNOWN_VR_CODES.has(rawVr) ? rawVr : 'UN';\n const element: ElementBuilder = { vr };\n\n if (attr.InlineBinary !== undefined) {\n convertInlineBinary(attr, element);\n } else if (attr.BulkDataURI !== undefined) {\n convertBulkDataURI(attr, element);\n } else if (element.vr === 'PN' && attr.PersonName !== undefined) {\n convertPNValue(attr, element);\n } else if (element.vr === 'SQ' && attr.Item !== undefined) {\n convertSequence(attr, element);\n } else if (attr.Value !== undefined) {\n convertRegularValue(attr, element, vr);\n }\n\n return Object.freeze(element) as DicomJsonElement;\n}\n\n/**\n * Converts an object containing DicomAttribute children into a DICOM JSON Model object.\n */\nfunction convertAttributes(obj: Record<string, unknown>): DicomJsonModel {\n const result: Record<string, DicomJsonElement> = {};\n const attrs = toArray(obj['DicomAttribute']);\n\n for (const attr of attrs) {\n if (typeof attr !== 'object' || attr === null) continue;\n const xmlAttr = attr as XmlDicomAttribute;\n const tag = xmlAttr['@_tag'];\n if (tag === undefined) continue;\n result[tag] = convertElement(xmlAttr);\n }\n\n return result;\n}\n\n/** XML parser configured for the DCMTK Native DICOM Model. */\nconst parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: '@_',\n parseTagValue: false,\n isArray: (name: string): boolean => ARRAY_TAG_NAMES.has(name),\n // DICOM XML does not use XML entities. Disable entity processing to avoid\n // the default expansion limit (1000) which rejects files with >1000 tags.\n // Without this, large studies fall through to dcm2json which hangs on\n // compressed pixel data (DCMTK bug).\n processEntities: false,\n});\n\n/**\n * Converts dcm2xml XML output to DICOM JSON Model.\n *\n * @param xml - The XML string from dcm2xml\n * @returns A Result containing the DICOM JSON Model or an error\n */\nfunction xmlToJson(xml: string): Result<DicomJsonModel> {\n try {\n const parsed = parser.parse(xml) as Record<string, unknown>;\n const root = parsed['NativeDicomModel'];\n if (root === undefined) {\n return err(new Error('Invalid dcm2xml output: missing NativeDicomModel root element'));\n }\n // Empty NativeDicomModel produces an empty string from the parser\n if (typeof root !== 'object' || root === null) {\n return ok({});\n }\n return ok(convertAttributes(root as Record<string, unknown>));\n } catch (error: unknown) {\n return err(new Error(`Failed to parse dcm2xml XML: ${stderr(error).message}`));\n }\n}\n\nexport { xmlToJson };\nexport type { DicomJsonModel, DicomJsonElement };\n","/**\n * Repairs malformed JSON output from the dcm2json binary.\n *\n * DCMTK's dcm2json sometimes emits invalid JSON for numeric-string VRs\n * (DS, IS) by producing unquoted numbers in arrays:\n * ```json\n * \"Value\": [1.5, 2.0] // invalid — DS values must be strings\n * \"Value\": [\"1.5\", \"2.0\"] // valid\n * ```\n *\n * This module detects and repairs these patterns before JSON.parse.\n *\n * @module _repairJson\n * @internal\n */\n\n/**\n * Pattern matching \"Value\" arrays in DICOM JSON.\n * Captures: (prefix including `[`)(inner content)(closing `]`).\n */\nconst VALUE_ARRAY_PATTERN = /(\"Value\"\\s*:\\s*\\[)([\\s\\S]*?)(\\])/g;\n\n/**\n * Matches a bare (unquoted) numeric literal.\n * Handles integers, decimals, scientific notation, and negative values.\n */\nconst BARE_NUMBER = /^-?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][+-]?\\d+)?$/;\n\n/**\n * Quotes a bare number token, leaving already-quoted strings unchanged.\n *\n * @param token - A trimmed token from inside a Value array\n * @returns The token, quoted if it was a bare number\n */\nfunction quoteIfBareNumber(token: string): string {\n const trimmed = token.trim();\n if (BARE_NUMBER.test(trimmed)) {\n return `\"${trimmed}\"`;\n }\n return trimmed;\n}\n\n/**\n * Repairs the inner content of a \"Value\" array by quoting bare numbers.\n *\n * @param inner - The content between `[` and `]`\n * @returns Repaired content with bare numbers quoted\n */\nfunction repairInner(inner: string): string {\n const trimmed = inner.trim();\n if (trimmed.length === 0) return inner;\n\n // Split on commas that are not inside quotes\n const tokens: string[] = [];\n let current = '';\n let inString = false;\n\n for (let i = 0; i < trimmed.length; i++) {\n const ch = trimmed[i]!;\n if (ch === '\"' && (i === 0 || trimmed[i - 1] !== '\\\\')) {\n inString = !inString;\n current += ch;\n } else if (ch === ',' && !inString) {\n tokens.push(current);\n current = '';\n } else {\n current += ch;\n }\n }\n tokens.push(current);\n\n return tokens.map(quoteIfBareNumber).join(', ');\n}\n\n/**\n * Repairs malformed dcm2json output by quoting unquoted numeric values in \"Value\" arrays.\n *\n * @param raw - The raw JSON string from dcm2json\n * @returns The repaired JSON string safe for JSON.parse\n */\nfunction repairJson(raw: string): string {\n return raw.replace(VALUE_ARRAY_PATTERN, (_match, prefix: string, inner: string, suffix: string) => {\n return `${prefix}${repairInner(inner)}${suffix}`;\n });\n}\n\nexport { repairJson };\n","/**\n * DICOM to JSON conversion using a two-phase strategy.\n *\n * Primary: dcm2xml → xmlToJson (more reliable output)\n * Fallback: dcm2json binary → repairJson → JSON.parse\n *\n * The result includes a `source` discriminant indicating which strategy succeeded.\n *\n * @module dcm2json\n */\n\nimport { mkdtemp, rm } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { stderr } from 'stderr-lib';\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { execCommand } from '../exec';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport { resolveBinary } from './_resolveBinary';\nimport { createToolError, createValidationError } from './_toolError';\nimport { xmlToJson } from './_xmlToJson';\nimport { repairJson } from './_repairJson';\nimport type { DicomJsonModel } from './_xmlToJson';\nimport type { ToolBaseOptions } from './_toolTypes';\n\n/** Indicates which conversion strategy produced the result. */\ntype Dcm2jsonSource = 'xml' | 'direct';\n\n/** Options for {@link dcm2json}. */\ninterface Dcm2jsonOptions extends ToolBaseOptions {\n /** Skip the XML primary path and use direct dcm2json only. Defaults to false. */\n readonly directOnly?: boolean | undefined;\n /** Assume the specified character set when SpecificCharacterSet (0008,0005) is absent. Passed to dcm2xml as `+Ca`. Only effective on the XML path (dcm2json binary does not support this flag). */\n readonly charsetAssume?: string | undefined;\n /** Fallback charset to retry with when UTF-8 conversion fails. On charset error, the XML path retries with `+Ca <fallback>`. `'Latin1'` recommended — maps every byte to a valid character. */\n readonly charsetFallback?: string | undefined;\n /** Verbosity level for diagnostic output. `'verbose'` maps to `-v`, `'debug'` maps to `-d`. */\n readonly verbosity?: 'verbose' | 'debug' | undefined;\n}\n\n/** Result of a successful dcm2json conversion. */\ninterface Dcm2jsonResult {\n /** The DICOM JSON Model object. */\n readonly data: DicomJsonModel;\n /** Which conversion strategy produced this result. */\n readonly source: Dcm2jsonSource;\n}\n\nconst Dcm2jsonOptionsSchema = z\n .object({\n timeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n directOnly: z.boolean().optional(),\n charsetAssume: z.string().min(1).optional(),\n charsetFallback: z.string().min(1).optional(),\n verbosity: z.enum(['verbose', 'debug']).optional(),\n })\n .strict()\n .optional();\n\n/** Options forwarded to the XML conversion path. */\ntype XmlPathOpts = { readonly verbosity?: 'verbose' | 'debug'; readonly charsetAssume?: string; readonly charsetFallback?: string };\n\n/** Maps verbosity level to command-line flag. */\nconst VERBOSITY_FLAGS: Record<'verbose' | 'debug', string> = { verbose: '-v', debug: '-d' };\n\n/**\n * Builds verbosity args for internal calls.\n */\nfunction buildVerbosityArgs(verbosity?: 'verbose' | 'debug'): string[] {\n if (verbosity !== undefined) {\n return [VERBOSITY_FLAGS[verbosity]];\n }\n return [];\n}\n\n/** Builds XML-path options, omitting undefined values for exactOptionalPropertyTypes. */\nfunction buildXmlOpts(options?: Dcm2jsonOptions): XmlPathOpts {\n const result: Record<string, string> = {};\n if (options?.verbosity !== undefined) result['verbosity'] = options.verbosity;\n if (options?.charsetAssume !== undefined) result['charsetAssume'] = options.charsetAssume;\n if (options?.charsetFallback !== undefined) result['charsetFallback'] = options.charsetFallback;\n return result;\n}\n\n/** Returns true if dcm2xml failed due to a charset conversion error. */\nfunction isCharsetError(stderrOutput: string): boolean {\n return stderrOutput.includes('convert character encoding') || stderrOutput.includes('Illegal byte sequence');\n}\n\n/** Runs dcm2xml with given args, parses output to DICOM JSON. */\nasync function runXmlAndParse(binary: string, args: string[], execOpts: { timeoutMs: number; signal?: AbortSignal }): Promise<Result<Dcm2jsonResult>> {\n const xmlResult = await execCommand(binary, args, execOpts);\n if (!xmlResult.ok) return err(xmlResult.error);\n if (xmlResult.value.exitCode !== 0) {\n return err(createToolError('dcm2xml', args, xmlResult.value.exitCode, xmlResult.value.stderr));\n }\n const jsonResult = xmlToJson(xmlResult.value.stdout);\n if (!jsonResult.ok) return err(jsonResult.error);\n return ok({ data: jsonResult.value, source: 'xml' as const });\n}\n\n/**\n * Attempts XML-primary conversion: dcm2xml → xmlToJson.\n * If charset conversion fails and a fallback charset is configured, retries with `+Ca <fallback>`.\n */\nasync function tryXmlPath(inputPath: string, timeoutMs: number, signal?: AbortSignal, opts?: XmlPathOpts): Promise<Result<Dcm2jsonResult>> {\n const xmlBinary = resolveBinary('dcm2xml');\n if (!xmlBinary.ok) return err(xmlBinary.error);\n\n const charsetArgs = opts?.charsetAssume !== undefined ? ['+Ca', opts.charsetAssume] : [];\n const xmlArgs = [...buildVerbosityArgs(opts?.verbosity), ...charsetArgs, '-nat', inputPath];\n const execOpts = signal !== undefined ? { timeoutMs, signal } : { timeoutMs };\n\n const result = await runXmlAndParse(xmlBinary.value, xmlArgs, execOpts);\n\n // On charset conversion failure, retry with the fallback charset\n if (!result.ok && opts?.charsetFallback !== undefined && isCharsetError(result.error.message)) {\n const fallbackArgs = [...buildVerbosityArgs(opts.verbosity), '+Ca', opts.charsetFallback, '-nat', inputPath];\n return runXmlAndParse(xmlBinary.value, fallbackArgs, execOpts);\n }\n\n return result;\n}\n\n/**\n * Attempts direct conversion: dcm2json binary → repairJson → JSON.parse.\n *\n * Uses `+b +bd <tmpdir>` to redirect bulk pixel data to a temp directory\n * (discarded after parsing) so compressed pixel data does not cause failures.\n */\nasync function tryDirectPath(inputPath: string, timeoutMs: number, signal?: AbortSignal, verbosity?: 'verbose' | 'debug'): Promise<Result<Dcm2jsonResult>> {\n const jsonBinary = resolveBinary('dcm2json');\n if (!jsonBinary.ok) {\n return err(jsonBinary.error);\n }\n\n const bulkDir = await createBulkTempDir();\n const directArgs = [...buildVerbosityArgs(verbosity), '+b', '+bd', bulkDir, inputPath];\n\n try {\n const execOpts = signal !== undefined ? { timeoutMs, signal } : { timeoutMs };\n return await execAndParse(jsonBinary.value, directArgs, inputPath, execOpts);\n } finally {\n rm(bulkDir, { recursive: true, force: true }).catch(() => {});\n }\n}\n\n/** Creates a temporary directory for dcm2json bulk data output. */\nasync function createBulkTempDir(): Promise<string> {\n return mkdtemp(join(tmpdir(), 'dcm2json-bulk-'));\n}\n\n/** Runs dcm2json and parses the output. */\nasync function execAndParse(\n binary: string,\n args: string[],\n inputPath: string,\n execOpts: { timeoutMs: number; signal?: AbortSignal }\n): Promise<Result<Dcm2jsonResult>> {\n const result = await execCommand(binary, args, execOpts);\n if (!result.ok) {\n return err(result.error);\n }\n\n if (result.value.exitCode !== 0) {\n return err(createToolError('dcm2json', args, result.value.exitCode, result.value.stderr));\n }\n\n try {\n const repaired = repairJson(result.value.stdout);\n const data = JSON.parse(repaired) as DicomJsonModel;\n return ok({ data, source: 'direct' as const });\n } catch (parseError: unknown) {\n return err(createToolError('dcm2json', [inputPath], 1, `Parse error: ${stderr(parseError).message}`));\n }\n}\n\n/**\n * Converts a DICOM file to the DICOM JSON Model.\n *\n * Uses a two-phase strategy:\n * 1. Primary: dcm2xml → XML-to-JSON conversion (more reliable)\n * 2. Fallback: direct dcm2json binary with JSON repair\n *\n * @param inputPath - Path to the DICOM input file\n * @param options - Conversion options\n * @returns A Result containing the DICOM JSON Model with source discriminant\n *\n * @example\n * ```ts\n * const result = await dcm2json('/path/to/study.dcm');\n * if (result.ok) {\n * console.log(result.value.source); // 'xml' or 'direct'\n * console.log(result.value.data['00100010']); // Patient Name\n * }\n * ```\n */\nasync function dcm2json(inputPath: string, options?: Dcm2jsonOptions): Promise<Result<Dcm2jsonResult>> {\n const validation = Dcm2jsonOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcm2json', validation.error));\n }\n\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const signal = options?.signal;\n\n const verbosity = options?.verbosity;\n\n // Direct-only mode: skip XML path\n if (options?.directOnly === true) {\n return tryDirectPath(inputPath, timeoutMs, signal, verbosity);\n }\n\n // Try XML path first\n const xmlResult = await tryXmlPath(inputPath, timeoutMs, signal, buildXmlOpts(options));\n if (xmlResult.ok) {\n return xmlResult;\n }\n\n // Fall back to direct path\n return tryDirectPath(inputPath, timeoutMs, signal, verbosity);\n}\n\nexport { dcm2json };\nexport type { Dcm2jsonOptions, Dcm2jsonResult, Dcm2jsonSource, DicomJsonModel };\n","/**\n * Modify DICOM tags using the dcmodify binary.\n *\n * Uses spawnCommand instead of execCommand because user-supplied DICOM values\n * could contain shell metacharacters. Spawn passes args as an array with no\n * shell interpolation (Rule 7.4).\n *\n * @module dcmodify\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { spawnCommand } from '../exec';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport { resolveBinary } from './_resolveBinary';\nimport { createToolError, createValidationError } from './_toolError';\nimport type { ToolBaseOptions } from './_toolTypes';\n\n/** A single tag modification. */\ninterface TagModification {\n /** DICOM tag to modify, e.g. \"(0010,0010)\". */\n readonly tag: string;\n /** New value for the tag. */\n readonly value: string;\n}\n\n/** Options for {@link dcmodify}. */\ninterface DcmodifyOptions extends ToolBaseOptions {\n /** Tag modifications to apply. */\n readonly modifications?: readonly TagModification[] | undefined;\n /** Tag paths to erase (passed as `-e path`). */\n readonly erasures?: readonly string[] | undefined;\n /** Erase all private tags (uses `-ep` flag). */\n readonly erasePrivateTags?: boolean | undefined;\n /** Do not create backup (.bak) file. Defaults to true. */\n readonly noBackup?: boolean | undefined;\n /** Insert tag if it doesn't exist (uses -i flag). Defaults to false. */\n readonly insertIfMissing?: boolean | undefined;\n /** Treat 'tag not found' as success when erasing (uses -imt flag). Defaults to false. */\n readonly ignoreMissingTags?: boolean | undefined;\n /** Verbosity level for diagnostic output. `'verbose'` maps to `-v`, `'debug'` maps to `-d`. */\n readonly verbosity?: 'verbose' | 'debug' | undefined;\n}\n\n/** Result of a successful dcmodify operation. */\ninterface DcmodifyResult {\n /** Path to the modified DICOM file. */\n readonly filePath: string;\n}\n\n/** Matches a single tag or a dotted tag path: (XXXX,XXXX) or (XXXX,XXXX)[N].(XXXX,XXXX) — [N] required before every dot. */\nconst TAG_OR_PATH_PATTERN = /^\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)(\\[\\d+\\]\\.\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\))*(\\[\\d+\\])?$/;\n\nconst TagModificationSchema = z.object({\n tag: z.string().regex(TAG_OR_PATH_PATTERN),\n value: z.string(),\n});\n\n/** Maps verbosity level to command-line flag. */\nconst VERBOSITY_FLAGS: Record<'verbose' | 'debug', string> = { verbose: '-v', debug: '-d' };\n\nconst DcmodifyOptionsSchema = z\n .object({\n timeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n modifications: z.array(TagModificationSchema).optional().default([]),\n erasures: z.array(z.string()).optional(),\n erasePrivateTags: z.boolean().optional(),\n noBackup: z.boolean().optional(),\n insertIfMissing: z.boolean().optional(),\n ignoreMissingTags: z.boolean().optional(),\n verbosity: z.enum(['verbose', 'debug']).optional(),\n })\n .strict()\n .refine(data => data.modifications.length > 0 || (data.erasures !== undefined && data.erasures.length > 0) || data.erasePrivateTags === true, {\n message: 'At least one of modifications, erasures, or erasePrivateTags is required',\n });\n\n/**\n * Builds dcmodify command-line arguments from validated options.\n */\nfunction buildArgs(inputPath: string, options: DcmodifyOptions): string[] {\n const args: string[] = [];\n\n if (options.verbosity !== undefined) {\n args.push(VERBOSITY_FLAGS[options.verbosity]);\n }\n\n if (options.noBackup !== false) {\n args.push('-nb');\n }\n\n if (options.ignoreMissingTags === true) {\n args.push('-imt');\n }\n\n const flag = options.insertIfMissing === true ? '-i' : '-m';\n const modifications = options.modifications ?? [];\n\n for (const mod of modifications) {\n args.push(flag, `${mod.tag}=${mod.value}`);\n }\n\n if (options.erasures !== undefined) {\n for (const erasure of options.erasures) {\n args.push('-e', erasure);\n }\n }\n\n if (options.erasePrivateTags === true) {\n args.push('-ep');\n }\n\n args.push(inputPath);\n\n return args;\n}\n\n/**\n * Modifies DICOM tags in a file using the dcmodify binary.\n *\n * Uses spawn (not exec) for safety with user-supplied values.\n *\n * @param inputPath - Path to the DICOM file to modify (modified in-place)\n * @param options - Modification options\n * @returns A Result containing the file path or an error\n *\n * @example\n * ```ts\n * const result = await dcmodify('/path/to/study.dcm', {\n * modifications: [\n * { tag: '(0010,0010)', value: 'Anonymous' },\n * { tag: '(0010,0020)', value: 'ANON001' },\n * ],\n * });\n * ```\n */\nasync function dcmodify(inputPath: string, options: DcmodifyOptions): Promise<Result<DcmodifyResult>> {\n const validation = DcmodifyOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmodify', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmodify');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(inputPath, options);\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n const result = await spawnCommand(binaryResult.value, args, {\n timeoutMs,\n signal: options.signal,\n });\n\n if (!result.ok) {\n return err(result.error);\n }\n\n if (result.value.exitCode !== 0) {\n return err(createToolError('dcmodify', args, result.value.exitCode, result.value.stderr));\n }\n\n return ok({ filePath: inputPath });\n}\n\nexport { dcmodify };\nexport type { DcmodifyOptions, DcmodifyResult, TagModification };\n","/**\n * File operation helpers for DicomInstance.\n *\n * Extracted to keep DicomInstance methods under line-count limits.\n *\n * @module dicom/_fileHelpers\n */\n\nimport { copyFile, stat, unlink } from 'node:fs/promises';\nimport { tryCatch } from 'stderr-lib';\nimport type { DicomFilePath } from '../brands';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport type { ChangeSet } from './ChangeSet';\nimport { dcmodify } from '../tools/dcmodify';\n\n/** Options for file I/O operations. */\ninterface FileIOOptions {\n /** Timeout in milliseconds. Defaults to DEFAULT_TIMEOUT_MS. */\n readonly timeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n/** Options for opening a DICOM file. Extends FileIOOptions with read-specific settings. */\ninterface DicomOpenOptions extends FileIOOptions {\n /** Assume the specified character set when SpecificCharacterSet (0008,0005) is absent. Maps to dcm2xml `+Ca`. */\n readonly charsetAssume?: string | undefined;\n /** Fallback charset to retry with when UTF-8 conversion fails due to illegal byte sequences. Maps to dcm2xml `+Ca`. When set, a charset conversion failure triggers an automatic retry with this charset assumed. `'Latin1'` is recommended — it maps every byte 0x00-0xFF to a valid character, so conversion never fails. */\n readonly charsetFallback?: string | undefined;\n}\n\n/** Bridges a ChangeSet to a dcmodify call on the given file. */\nasync function applyModifications(filePath: DicomFilePath, changeset: ChangeSet, options: FileIOOptions): Promise<Result<void>> {\n const modifications = changeset.toModifications();\n const erasures = changeset.toErasureArgs();\n\n const hasErasures = erasures.length > 0 || changeset.erasePrivate;\n\n const result = await dcmodify(filePath, {\n modifications: modifications.length > 0 ? modifications : undefined,\n erasures: erasures.length > 0 ? erasures : undefined,\n erasePrivateTags: changeset.erasePrivate || undefined,\n insertIfMissing: true,\n ignoreMissingTags: hasErasures || undefined,\n timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n signal: options.signal,\n });\n\n if (!result.ok) return err(result.error);\n return ok(undefined);\n}\n\n/** Wraps fs.copyFile in a Result. */\nasync function copyFileSafe(source: string, dest: string): Promise<Result<void>> {\n return tryCatch(\n () => copyFile(source, dest),\n e => new Error(`Failed to copy file: ${e.message}`)\n );\n}\n\n/** Wraps fs.stat in a Result, returning file size. */\nasync function statFileSize(path: string): Promise<Result<number>> {\n return tryCatch(\n async () => (await stat(path)).size,\n e => new Error(`Failed to stat file: ${e.message}`)\n );\n}\n\n/** Wraps fs.unlink in a Result. */\nasync function unlinkFile(path: string): Promise<Result<void>> {\n return tryCatch(\n () => unlink(path),\n e => new Error(`Failed to delete file: ${e.message}`)\n );\n}\n\nexport { applyModifications, copyFileSafe, statFileSize, unlinkFile };\nexport type { FileIOOptions, DicomOpenOptions };\n","/**\n * Unified DICOM object composing DicomDataset + ChangeSet + file I/O.\n *\n * Every setter returns a new DicomInstance — the original is never modified.\n * Designed for ergonomic DICOM workflows that combine reading, modifying,\n * and writing DICOM data in a single fluent API.\n *\n * @module dicom/DicomInstance\n */\n\nimport type { DicomFilePath, DicomTag, DicomTagPath, SOPClassUID } from '../brands';\nimport { createDicomFilePath } from '../brands';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport type { Result } from '../types';\nimport { err, ok } from '../types';\nimport { ChangeSet } from './ChangeSet';\nimport { DicomDataset } from './DicomDataset';\nimport { dcm2json } from '../tools';\nimport type { DicomOpenOptions, FileIOOptions } from './_fileHelpers';\nimport { applyModifications, copyFileSafe, statFileSize, unlinkFile } from './_fileHelpers';\n\n// ---------------------------------------------------------------------------\n// DicomInstance class\n// ---------------------------------------------------------------------------\n\n/**\n * Unified DICOM object composing dataset, change tracking, file path, and metadata.\n *\n * Every setter returns a new immutable instance — the original is never modified.\n * Use the static factories {@link DicomInstance.open} or {@link DicomInstance.fromDataset}\n * to create instances.\n *\n * @example\n * ```ts\n * const result = await DicomInstance.open('/path/to/file.dcm');\n * if (!result.ok) { console.error(result.error.message); return; }\n * const modified = result.value\n * .setPatientName('DOE^JOHN')\n * .setPatientID('PAT001')\n * .erasePrivateTags();\n * await modified.writeAs('/path/to/output.dcm');\n * ```\n */\nclass DicomInstance {\n private readonly dicomDataset: DicomDataset;\n private readonly changeSet: ChangeSet;\n private readonly filepath: DicomFilePath | undefined;\n private readonly meta: ReadonlyMap<string, unknown>;\n\n private constructor(dataset: DicomDataset, changes: ChangeSet, filePath: DicomFilePath | undefined, metadata: ReadonlyMap<string, unknown>) {\n this.dicomDataset = dataset;\n this.changeSet = changes;\n this.filepath = filePath;\n this.meta = metadata;\n }\n\n // -----------------------------------------------------------------------\n // Factories\n // -----------------------------------------------------------------------\n\n /**\n * Opens a DICOM file and creates a DicomInstance.\n *\n * @param path - Filesystem path to the DICOM file\n * @param options - Timeout, abort, and charset options\n * @returns A Result containing the DicomInstance or an error\n */\n static async open(path: string, options?: DicomOpenOptions): Promise<Result<DicomInstance>> {\n const filePathResult = createDicomFilePath(path);\n if (!filePathResult.ok) return err(filePathResult.error);\n\n const jsonResult = await dcm2json(path, {\n timeoutMs: options?.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n signal: options?.signal,\n charsetAssume: options?.charsetAssume,\n charsetFallback: options?.charsetFallback,\n });\n if (!jsonResult.ok) return err(jsonResult.error);\n\n const datasetResult = DicomDataset.fromJson(jsonResult.value.data);\n if (!datasetResult.ok) return err(datasetResult.error);\n\n return ok(new DicomInstance(datasetResult.value, ChangeSet.empty(), filePathResult.value, new Map()));\n }\n\n /**\n * Creates a DicomInstance from an existing DicomDataset.\n *\n * @param dataset - The DicomDataset to wrap\n * @param filePath - Optional file path (e.g. if the dataset came from a file)\n * @returns A Result containing the DicomInstance\n */\n static fromDataset(dataset: DicomDataset, filePath?: string): Result<DicomInstance> {\n let fp: DicomFilePath | undefined;\n if (filePath !== undefined) {\n const fpResult = createDicomFilePath(filePath);\n if (!fpResult.ok) return err(fpResult.error);\n fp = fpResult.value;\n }\n return ok(new DicomInstance(dataset, ChangeSet.empty(), fp, new Map()));\n }\n\n // -----------------------------------------------------------------------\n // Read accessors (delegate to DicomDataset)\n // -----------------------------------------------------------------------\n\n /** The underlying immutable DICOM dataset. */\n get dataset(): DicomDataset {\n return this.dicomDataset;\n }\n\n /** The pending change set. */\n get changes(): ChangeSet {\n return this.changeSet;\n }\n\n /** Whether there are unsaved changes. */\n get hasUnsavedChanges(): boolean {\n return !this.changeSet.isEmpty;\n }\n\n /** The file path, or undefined if this instance has no associated file. */\n get filePath(): string | undefined {\n return this.filepath;\n }\n\n /** Patient's Name (0010,0010). */\n get patientName(): string {\n return this.dicomDataset.patientName;\n }\n\n /** Patient ID (0010,0020). */\n get patientID(): string {\n return this.dicomDataset.patientID;\n }\n\n /** Study Date (0008,0020). */\n get studyDate(): string {\n return this.dicomDataset.studyDate;\n }\n\n /** Modality (0008,0060). */\n get modality(): string {\n return this.dicomDataset.modality;\n }\n\n /** Accession Number (0008,0050). */\n get accession(): string {\n return this.dicomDataset.accession;\n }\n\n /** SOP Class UID (0008,0016). */\n get sopClassUID(): SOPClassUID | undefined {\n return this.dicomDataset.sopClassUID;\n }\n\n /** Study Instance UID (0020,000D). */\n get studyInstanceUID(): string {\n return this.dicomDataset.studyInstanceUID;\n }\n\n /** Series Instance UID (0020,000E). */\n get seriesInstanceUID(): string {\n return this.dicomDataset.seriesInstanceUID;\n }\n\n /** SOP Instance UID (0008,0018). */\n get sopInstanceUID(): string {\n return this.dicomDataset.sopInstanceUID;\n }\n\n /** Transfer Syntax UID (0002,0010). */\n get transferSyntaxUID(): string {\n return this.dicomDataset.transferSyntaxUID;\n }\n\n /**\n * Gets a tag value as a string with optional fallback.\n *\n * @param tag - A DICOM tag, e.g. `'(0010,0010)'` or `'00100010'`\n * @param fallback - Value to return if tag is missing (default: `''`)\n */\n getString(tag: DicomTag | string, fallback = ''): string {\n return this.dicomDataset.getString(tag, fallback);\n }\n\n /**\n * Gets a tag value as a number.\n *\n * @param tag - A DICOM tag, e.g. `'(0020,0013)'`\n */\n getNumber(tag: DicomTag | string): Result<number> {\n return this.dicomDataset.getNumber(tag);\n }\n\n /** Checks whether a tag exists in the dataset. */\n hasTag(tag: DicomTag | string): boolean {\n return this.dicomDataset.hasTag(tag);\n }\n\n /**\n * Finds all values matching a wildcard path.\n *\n * @param path - A DicomTagPath with optional wildcard indices\n */\n findValues(path: DicomTagPath): ReadonlyArray<unknown> {\n return this.dicomDataset.findValues(path);\n }\n\n // -----------------------------------------------------------------------\n // Write methods (return new instance)\n // -----------------------------------------------------------------------\n\n /**\n * Sets a tag value, returning a new DicomInstance.\n *\n * @param path - The DICOM tag path (e.g. `'(0010,0010)'`)\n * @param value - The new value\n */\n setTag(path: string, value: string): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.setTag(path, value), this.filepath, this.meta);\n }\n\n /**\n * Erases a tag, returning a new DicomInstance.\n *\n * @param path - The DICOM tag path to erase\n */\n eraseTag(path: string): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.eraseTag(path), this.filepath, this.meta);\n }\n\n /** Erases all private tags, returning a new DicomInstance. */\n erasePrivateTags(): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.erasePrivateTags(), this.filepath, this.meta);\n }\n\n /** Sets Patient's Name (0010,0010). */\n setPatientName(value: string): DicomInstance {\n return this.setTag('(0010,0010)', value);\n }\n\n /** Sets Patient ID (0010,0020). */\n setPatientID(value: string): DicomInstance {\n return this.setTag('(0010,0020)', value);\n }\n\n /** Sets Study Date (0008,0020). */\n setStudyDate(value: string): DicomInstance {\n return this.setTag('(0008,0020)', value);\n }\n\n /** Sets Modality (0008,0060). */\n setModality(value: string): DicomInstance {\n return this.setTag('(0008,0060)', value);\n }\n\n /** Sets Accession Number (0008,0050). */\n setAccessionNumber(value: string): DicomInstance {\n return this.setTag('(0008,0050)', value);\n }\n\n /** Sets Study Description (0008,1030). */\n setStudyDescription(value: string): DicomInstance {\n return this.setTag('(0008,1030)', value);\n }\n\n /** Sets Series Description (0008,103E). */\n setSeriesDescription(value: string): DicomInstance {\n return this.setTag('(0008,103E)', value);\n }\n\n /** Sets Institution Name (0008,0080). */\n setInstitutionName(value: string): DicomInstance {\n return this.setTag('(0008,0080)', value);\n }\n\n /**\n * Transforms a tag value using a function.\n *\n * The function receives the current string value (or undefined if tag is missing)\n * and returns the new value. Returns a new DicomInstance with the modification.\n *\n * @param path - The DICOM tag path\n * @param fn - Transform function receiving the current value\n */\n transformTag(path: string, fn: (current: string | undefined) => string): DicomInstance {\n const current = this.dicomDataset.getString(path);\n const newValue = fn(current.length > 0 ? current : undefined);\n return this.setTag(path, newValue);\n }\n\n /**\n * Sets multiple tags at once, returning a new DicomInstance.\n *\n * @param entries - A record of tag path → value pairs\n */\n setBatch(entries: Readonly<Record<string, string>>): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.setBatch(entries), this.filepath, this.meta);\n }\n\n /**\n * Returns a new DicomInstance with the given changes merged into pending changes.\n *\n * @param changes - A ChangeSet to merge with existing pending changes\n * @returns A new DicomInstance with accumulated changes\n */\n withChanges(changes: ChangeSet): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.merge(changes), this.filepath, this.meta);\n }\n\n /**\n * Returns a new DicomInstance pointing to a different file path.\n *\n * Preserves the dataset, pending changes, and metadata.\n *\n * @param newPath - The new filesystem path (validated via createDicomFilePath)\n * @returns A new DicomInstance with the updated path\n * @throws If the path is invalid\n */\n withFilePath(newPath: string): DicomInstance {\n const result = createDicomFilePath(newPath);\n if (!result.ok) throw result.error;\n return new DicomInstance(this.dicomDataset, this.changeSet, result.value, this.meta);\n }\n\n // -----------------------------------------------------------------------\n // File I/O\n // -----------------------------------------------------------------------\n\n /**\n * Applies pending changes to the file in-place.\n *\n * Requires that the instance has an associated file path.\n *\n * @param options - Timeout and abort options\n */\n async applyChanges(options?: FileIOOptions): Promise<Result<void>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n if (this.changeSet.isEmpty) return ok(undefined);\n return applyModifications(this.filepath, this.changeSet, options ?? {});\n }\n\n /**\n * Copies the file to a new path and applies pending changes to the copy.\n *\n * Returns a new DicomInstance pointing to the output path.\n *\n * @param outputPath - Destination filesystem path\n * @param options - Timeout and abort options\n */\n async writeAs(outputPath: string, options?: FileIOOptions): Promise<Result<DicomInstance>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n\n const outPathResult = createDicomFilePath(outputPath);\n if (!outPathResult.ok) return err(outPathResult.error);\n\n const copyResult = await copyFileSafe(this.filepath, outputPath);\n if (!copyResult.ok) return err(copyResult.error);\n\n if (!this.changeSet.isEmpty) {\n const applyResult = await applyModifications(outPathResult.value, this.changeSet, options ?? {});\n if (!applyResult.ok) {\n await unlinkFile(outputPath);\n return err(applyResult.error);\n }\n }\n\n return ok(new DicomInstance(this.dicomDataset, ChangeSet.empty(), outPathResult.value, this.meta));\n }\n\n /**\n * Gets the file size in bytes.\n *\n * @returns A Result containing the size or an error\n */\n async fileSize(): Promise<Result<number>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n return statFileSize(this.filepath);\n }\n\n /**\n * Deletes the associated file from the filesystem.\n *\n * @returns A Result indicating success or failure\n */\n async unlink(): Promise<Result<void>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n return unlinkFile(this.filepath);\n }\n\n // -----------------------------------------------------------------------\n // Metadata (non-DICOM app context)\n // -----------------------------------------------------------------------\n\n /**\n * Returns a new DicomInstance with application metadata attached.\n *\n * Metadata is not stored in the DICOM file — it's for application context\n * (e.g. tracking source association, processing status, etc.).\n *\n * @param key - Metadata key\n * @param value - Metadata value\n */\n withMetadata(key: string, value: unknown): DicomInstance {\n const newMeta = new Map(this.meta);\n newMeta.set(key, value);\n return new DicomInstance(this.dicomDataset, this.changeSet, this.filepath, newMeta);\n }\n\n /**\n * Gets application metadata by key.\n *\n * @param key - Metadata key\n * @returns The metadata value or undefined\n */\n getMetadata(key: string): unknown {\n return this.meta.get(key);\n }\n}\n\nexport { DicomInstance };\n","/**\n * Pooled DICOM receiver with auto-scaling.\n *\n * Manages a pool of long-lived `Dcmrecv` workers behind a TCP proxy,\n * routing incoming connections to idle workers. Workers are reused\n * across associations — they are only stopped during scale-down or\n * shutdown.\n *\n * @module servers/DicomReceiver\n */\n\nimport * as net from 'node:net';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { setTimeout as delay } from 'node:timers/promises';\nimport { EventEmitter } from 'node:events';\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { isSafePath, isValidAETitle } from '../patterns';\nimport { createValidationError } from '../tools/_toolError';\nimport { ensureDirectory, moveFile, statFileSafe, removeDirSafe } from '../utils';\nimport { Dcmrecv } from './Dcmrecv';\nimport type { FilenameModeValue, StorageModeValue } from './Dcmrecv';\nimport type { AssociationCompleteData } from '../events/dcmrecv';\nimport { DicomInstance } from '../dicom';\nimport type { DicomOpenOptions } from '../dicom/_fileHelpers';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_MIN_POOL_SIZE = 2;\nconst DEFAULT_MAX_POOL_SIZE = 10;\nconst DEFAULT_CONNECTION_TIMEOUT_MS = 10_000;\nconst CONNECTION_RETRY_INTERVAL_MS = 500;\nconst MAX_CONNECTION_RETRIES = 200;\nconst MAX_OUTPUT_LINES_PER_ASSOCIATION = 500;\n\n// ---------------------------------------------------------------------------\n// Public interfaces\n// ---------------------------------------------------------------------------\n\n/** Snapshot of the worker pool state. */\ninterface PoolStatus {\n /** Number of idle workers ready for connections. */\n readonly idle: number;\n /** Number of workers currently handling associations. */\n readonly busy: number;\n /** Total number of workers (idle + busy). */\n readonly total: number;\n}\n\n/** Data emitted with FILE_RECEIVED events (raw from dcmrecv, before processing). */\ninterface ReceiverFileReceivedData {\n readonly filePath: string;\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Data emitted with FILE_STORED events (file moved to association dir). */\ninterface ReceiverFileStoredData {\n readonly filePath: string;\n readonly fileSize: number;\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Data emitted with INSTANCE_RECEIVED events (parsed DicomInstance available). */\ninterface ReceiverInstanceData {\n readonly filePath: string;\n readonly fileSize: number;\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly instance: DicomInstance;\n}\n\n/** Data emitted with ASSOCIATION_COMPLETE events. */\ninterface ReceiverAssociationData {\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly durationMs: number;\n readonly endReason: 'release' | 'abort';\n readonly totalBytes: number;\n readonly bytesPerSecond: number;\n readonly startAt: number;\n readonly endAt: number;\n /** Captured stdout/stderr lines from the worker during this association. */\n readonly output: readonly string[];\n}\n\n/** Data emitted with ASSOCIATION_RECEIVED events (bubbled from worker). */\ninterface PoolAssociationReceivedData {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Data emitted with C_STORE_REQUEST events (bubbled from worker). */\ninterface PoolCStoreRequestData {\n readonly associationId: string;\n readonly raw: string;\n}\n\n/** Data emitted with ECHO_REQUEST events (bubbled from worker). */\ninterface PoolEchoRequestData {\n readonly associationId: string;\n}\n\n/** Data emitted with REFUSING_ASSOCIATION events (bubbled from worker). */\ninterface PoolRefusingAssociationData {\n readonly reason: string;\n}\n\n/** Data emitted with INSTANCE_ERROR events when DicomInstance.open fails. */\ninterface ReceiverInstanceErrorData {\n readonly error: Error;\n /** Whether this was a thrown exception (true) or a Result error (false). */\n readonly thrown: boolean;\n readonly filePath: string;\n readonly fileSize: number;\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Data emitted with ASSOCIATION_FINALIZED — all work (including parsing) is done. */\ninterface ReceiverAssociationFinalizedData {\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly instancesReceived: number;\n readonly instanceErrors: number;\n}\n\n/** Data emitted with error events. */\ninterface ReceiverErrorData {\n readonly error: Error;\n readonly filePath?: string;\n readonly associationId?: string;\n readonly associationDir?: string;\n readonly callingAE?: string;\n readonly calledAE?: string;\n readonly source?: string;\n}\n\n/** Typed event map for DicomReceiver. */\ninterface DicomReceiverEventMap {\n FILE_RECEIVED: [ReceiverFileReceivedData];\n FILE_STORED: [ReceiverFileStoredData];\n INSTANCE_RECEIVED: [ReceiverInstanceData];\n INSTANCE_ERROR: [ReceiverInstanceErrorData];\n ASSOCIATION_COMPLETE: [ReceiverAssociationData];\n ASSOCIATION_FINALIZED: [ReceiverAssociationFinalizedData];\n ASSOCIATION_RECEIVED: [PoolAssociationReceivedData];\n C_STORE_REQUEST: [PoolCStoreRequestData];\n ECHO_REQUEST: [PoolEchoRequestData];\n REFUSING_ASSOCIATION: [PoolRefusingAssociationData];\n error: [ReceiverErrorData];\n}\n\n/** Options for creating a DicomReceiver instance. */\ninterface DicomReceiverOptions {\n /** External port to listen on (required). */\n readonly port: number;\n /** Root directory for association subdirectories (required). */\n readonly storageDir: string;\n /** Application Entity Title for workers. */\n readonly aeTitle?: string | undefined;\n /** Minimum number of idle workers to maintain. */\n readonly minPoolSize?: number | undefined;\n /** Maximum total workers allowed. */\n readonly maxPoolSize?: number | undefined;\n /** Timeout for waiting for an idle worker (milliseconds). */\n readonly connectionTimeoutMs?: number | undefined;\n /** Path to a dcmrecv association negotiation configuration file. */\n readonly configFile?: string | undefined;\n /** Profile name within the configuration file. */\n readonly configProfile?: string | undefined;\n /** ACSE timeout in seconds (passed through to Dcmrecv workers). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed through to Dcmrecv workers). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum PDU receive size (passed through to Dcmrecv workers). */\n readonly maxPdu?: number | undefined;\n /** Filename generation mode for received files (passed through to Dcmrecv workers). */\n readonly filenameMode?: FilenameModeValue | undefined;\n /** Extension appended to received filenames, e.g. `'.dcm'` (passed through to Dcmrecv workers). */\n readonly filenameExtension?: string | undefined;\n /** Storage mode for received files (passed through to Dcmrecv workers). */\n readonly storageMode?: StorageModeValue | undefined;\n /** Options passed to DicomInstance.open() for each received file. Defaults charsetFallback to `'Latin1'`. */\n readonly instanceOpenOptions?: DicomOpenOptions | undefined;\n /** Whether to parse received files into DicomInstance. When false, INSTANCE_RECEIVED and INSTANCE_ERROR events are not emitted. Defaults to true. */\n readonly parseInstances?: boolean | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Zod validation schema\n// ---------------------------------------------------------------------------\n\nconst DicomReceiverOptionsSchema = z\n .object({\n port: z.number().int().min(0).max(65535),\n storageDir: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in storageDir' }),\n aeTitle: z.string().min(1).max(16).refine(isValidAETitle, { message: 'AE Title contains invalid characters' }).optional(),\n minPoolSize: z.number().int().min(1).max(100).optional(),\n maxPoolSize: z.number().int().min(1).max(100).optional(),\n connectionTimeoutMs: z.number().int().positive().optional(),\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }).optional(),\n configProfile: z.string().min(1).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n filenameMode: z.enum(['default', 'unique', 'short-unique', 'system-time']).optional(),\n filenameExtension: z.string().min(1).optional(),\n storageMode: z.enum(['normal', 'bit-preserving', 'ignore']).optional(),\n instanceOpenOptions: z\n .object({\n timeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n charsetAssume: z.string().min(1).optional(),\n charsetFallback: z.string().min(1).optional(),\n })\n .strict()\n .optional(),\n parseInstances: z.boolean().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict()\n .refine(data => (data.minPoolSize ?? DEFAULT_MIN_POOL_SIZE) <= (data.maxPoolSize ?? DEFAULT_MAX_POOL_SIZE), {\n message: 'minPoolSize must be <= maxPoolSize',\n });\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\n/** Frozen context for a single association, captured synchronously at connection time. */\ninterface AssociationContext {\n readonly associationId: string;\n readonly associationDir: string;\n readonly startAt: number;\n}\n\n// ---------------------------------------------------------------------------\n// Internal Worker class\n// ---------------------------------------------------------------------------\n\n/** Encapsulates a single Dcmrecv worker and its per-association state. */\nclass Worker {\n readonly dcmrecv: Dcmrecv;\n readonly port: number;\n readonly tempDir: string;\n private _state: 'idle' | 'busy' = 'idle';\n private _context: AssociationContext | undefined;\n private readonly _pending = new Set<Promise<void>>();\n private readonly _instancePending = new Set<Promise<void>>();\n private _instancesReceived = 0;\n private _instanceErrors = 0;\n private readonly _files: string[] = [];\n private readonly _fileSizes: number[] = [];\n private readonly _outputLines: string[] = [];\n private _remoteSocket: net.Socket | undefined;\n private _workerSocket: net.Socket | undefined;\n\n constructor(dcmrecv: Dcmrecv, port: number, tempDir: string) {\n this.dcmrecv = dcmrecv;\n this.port = port;\n this.tempDir = tempDir;\n }\n\n /** Current worker state. */\n get state(): 'idle' | 'busy' {\n return this._state;\n }\n\n /** Active association context, or undefined when idle. */\n get context(): AssociationContext | undefined {\n return this._context;\n }\n\n /** Files moved to the association directory during the current association. */\n get files(): readonly string[] {\n return this._files;\n }\n\n /** Byte sizes parallel to files[], for transfer stats. */\n get fileSizes(): readonly number[] {\n return this._fileSizes;\n }\n\n /** Captured output lines during the current association. */\n get outputLines(): readonly string[] {\n return this._outputLines;\n }\n\n /** Marks the worker busy with a new association context. */\n beginAssociation(ctx: AssociationContext): void {\n this._state = 'busy';\n this._context = ctx;\n this._files.length = 0;\n this._fileSizes.length = 0;\n this._outputLines.length = 0;\n this._pending.clear();\n this._instancePending.clear();\n this._instancesReceived = 0;\n this._instanceErrors = 0;\n }\n\n /**\n * Returns the worker to idle. Context is intentionally preserved so that\n * late FILE_RECEIVED events (arriving in a subsequent pipe chunk after\n * ASSOCIATION_RELEASE) still have valid association info. Context is\n * cleared on the next {@link beginAssociation} call.\n */\n endAssociation(): void {\n this._state = 'idle';\n // NOTE: _context is NOT cleared here — see JSDoc above\n this._files.length = 0;\n this._fileSizes.length = 0;\n this._outputLines.length = 0;\n this._pending.clear();\n this._instancePending.clear();\n this._instancesReceived = 0;\n this._instanceErrors = 0;\n this._remoteSocket = undefined;\n this._workerSocket = undefined;\n }\n\n /** Tracks an in-flight file handling promise; auto-removes on completion. */\n trackFile(promise: Promise<void>): void {\n this._pending.add(promise);\n void promise.finally(() => {\n this._pending.delete(promise);\n });\n }\n\n /** Tracks an in-flight instance parsing promise; auto-removes on completion. */\n trackInstance(promise: Promise<void>): void {\n this._instancePending.add(promise);\n void promise.finally(() => {\n this._instancePending.delete(promise);\n });\n }\n\n /** Records a successful instance parse. */\n recordInstanceSuccess(): void {\n this._instancesReceived++;\n }\n\n /** Records a failed instance parse. */\n recordInstanceError(): void {\n this._instanceErrors++;\n }\n\n /** Awaits all in-flight instance parsing promises. */\n async drainInstancePending(): Promise<void> {\n if (this._instancePending.size > 0) {\n await Promise.all(this._instancePending);\n }\n }\n\n /** Number of successfully parsed instances in this association. */\n get instancesReceived(): number {\n return this._instancesReceived;\n }\n\n /** Number of failed instance parses in this association. */\n get instanceErrors(): number {\n return this._instanceErrors;\n }\n\n /** Records a successfully received file path and its size. */\n recordFile(filePath: string, size: number): void {\n this._files.push(filePath);\n this._fileSizes.push(size);\n }\n\n /** Awaits all in-flight file handling promises. */\n async drainPendingFiles(): Promise<void> {\n if (this._pending.size > 0) {\n await Promise.all(this._pending);\n }\n }\n\n /** Appends a line to the output buffer, respecting the cap. */\n captureOutput(text: string): void {\n if (this._outputLines.length < MAX_OUTPUT_LINES_PER_ASSOCIATION) {\n this._outputLines.push(text);\n }\n }\n\n /** Stores the remote and worker sockets for later cleanup. */\n setSockets(remote: net.Socket, worker: net.Socket): void {\n this._remoteSocket = remote;\n this._workerSocket = worker;\n }\n\n /** Destroys both sockets if they exist and are not already destroyed. */\n destroySockets(): void {\n if (this._remoteSocket !== undefined && !this._remoteSocket.destroyed) {\n this._remoteSocket.destroy();\n }\n if (this._workerSocket !== undefined && !this._workerSocket.destroyed) {\n this._workerSocket.destroy();\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Port allocation helper\n// ---------------------------------------------------------------------------\n\n/** Allocates a free ephemeral port by binding to port 0. */\nfunction allocatePort(): Promise<Result<number>> {\n return new Promise(resolve => {\n const server = net.createServer();\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address();\n if (addr === null || typeof addr === 'string') {\n server.close(() => resolve(err(new Error('Failed to allocate port'))));\n return;\n }\n const port = addr.port;\n server.close(() => resolve(ok(port)));\n });\n server.on('error', e => {\n resolve(err(new Error(`Port allocation failed: ${e.message}`)));\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Trivial helpers\n// ---------------------------------------------------------------------------\n\n/** Sums an array of numbers iteratively. */\nfunction sumArray(arr: readonly number[]): number {\n let total = 0;\n for (let i = 0; i < arr.length; i++) {\n total += arr[i] ?? 0;\n }\n return total;\n}\n\n// ---------------------------------------------------------------------------\n// DicomReceiver class\n// ---------------------------------------------------------------------------\n\n/**\n * Pooled DICOM receiver with auto-scaling.\n *\n * Manages a pool of long-lived `Dcmrecv` workers behind a TCP proxy.\n * Incoming connections are routed to idle workers. Workers are reused\n * across associations and only stopped during scale-down or shutdown.\n *\n * @example\n * ```ts\n * const result = DicomReceiver.create({\n * port: 4242,\n * storageDir: '/data/received',\n * minPoolSize: 2,\n * maxPoolSize: 8,\n * });\n * if (!result.ok) { console.error(result.error.message); return; }\n * const receiver = result.value;\n *\n * receiver.onFileReceived(data => console.log('File:', data.filePath));\n * receiver.onAssociationComplete(data => console.log('Done:', data.associationDir));\n *\n * await receiver.start();\n * ```\n */\nclass DicomReceiver extends EventEmitter<DicomReceiverEventMap> {\n private readonly options: DicomReceiverOptions;\n private readonly minPoolSize: number;\n private readonly maxPoolSize: number;\n private readonly connectionTimeoutMs: number;\n private readonly resolvedInstanceOpenOptions: DicomOpenOptions;\n private readonly parseInstances: boolean;\n private readonly workers: Map<number, Worker> = new Map();\n private tcpServer: net.Server | undefined;\n private associationCounter = 0;\n private started = false;\n private stopping = false;\n private abortHandler: (() => void) | undefined;\n\n private constructor(options: DicomReceiverOptions) {\n super();\n this.setMaxListeners(20);\n this.options = options;\n this.minPoolSize = options.minPoolSize ?? DEFAULT_MIN_POOL_SIZE;\n this.maxPoolSize = options.maxPoolSize ?? DEFAULT_MAX_POOL_SIZE;\n this.connectionTimeoutMs = options.connectionTimeoutMs ?? DEFAULT_CONNECTION_TIMEOUT_MS;\n this.resolvedInstanceOpenOptions = { charsetFallback: 'Latin1', ...options.instanceOpenOptions };\n this.parseInstances = options.parseInstances ?? true;\n }\n\n // -----------------------------------------------------------------------\n // Public API\n // -----------------------------------------------------------------------\n\n /**\n * Creates a new DicomReceiver instance.\n *\n * @param options - Configuration options\n * @returns A Result containing the instance or a validation error\n */\n static create(options: DicomReceiverOptions): Result<DicomReceiver> {\n const validation = DicomReceiverOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('DicomReceiver', validation.error));\n }\n return ok(new DicomReceiver(options));\n }\n\n /**\n * Starts the TCP proxy and spawns the initial worker pool.\n *\n * @returns A Result indicating success or failure\n */\n async start(): Promise<Result<void>> {\n if (this.started) {\n return err(new Error('DicomReceiver: already started'));\n }\n this.started = true;\n\n const storageDirResult = await ensureDirectory(this.options.storageDir);\n if (!storageDirResult.ok) return storageDirResult;\n\n const spawnResults = await this.spawnWorkers(this.minPoolSize);\n if (!spawnResults.ok) return spawnResults;\n\n const listenResult = await this.startTcpProxy();\n if (!listenResult.ok) return listenResult;\n\n if (this.options.signal !== undefined) {\n this.wireAbortSignal(this.options.signal);\n }\n\n return ok(undefined);\n }\n\n /**\n * Stops the TCP proxy and all workers.\n */\n async stop(): Promise<void> {\n if (!this.started || this.stopping) {\n return;\n }\n this.stopping = true;\n\n if (this.options.signal !== undefined && this.abortHandler !== undefined) {\n this.options.signal.removeEventListener('abort', this.abortHandler);\n }\n\n await this.closeTcpProxy();\n\n const stopPromises: Promise<void>[] = [];\n for (const worker of this.workers.values()) {\n stopPromises.push(this.stopWorker(worker));\n }\n await Promise.all(stopPromises);\n this.workers.clear();\n\n this.started = false;\n this.stopping = false;\n }\n\n /**\n * Registers a typed listener for a DicomReceiver-specific event.\n *\n * @param event - The event name from DicomReceiverEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof DicomReceiverEventMap>(event: K, listener: (...args: DicomReceiverEventMap[K]) => void): this {\n return this.on(event, listener as never);\n }\n\n /**\n * Registers a listener for files received by dcmrecv (before move/parse).\n *\n * @param listener - Callback receiving raw file data\n * @returns this for chaining\n */\n onFileReceived(listener: (data: ReceiverFileReceivedData) => void): this {\n return this.on('FILE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for files stored in the association directory.\n *\n * @param listener - Callback receiving stored file data with size\n * @returns this for chaining\n */\n onFileStored(listener: (data: ReceiverFileStoredData) => void): this {\n return this.on('FILE_STORED', listener);\n }\n\n /**\n * Registers a listener for parsed DicomInstance availability.\n *\n * @param listener - Callback receiving instance data\n * @returns this for chaining\n */\n onInstanceReceived(listener: (data: ReceiverInstanceData) => void): this {\n return this.on('INSTANCE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for DicomInstance.open failures.\n *\n * @param listener - Callback receiving instance error data\n * @returns this for chaining\n */\n onInstanceError(listener: (data: ReceiverInstanceErrorData) => void): this {\n return this.on('INSTANCE_ERROR', listener);\n }\n\n /**\n * Registers a listener for completed associations (file moves done).\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationComplete(listener: (data: ReceiverAssociationData) => void): this {\n return this.on('ASSOCIATION_COMPLETE', listener);\n }\n\n /**\n * Registers a listener for fully finalized associations (all parsing done).\n *\n * @param listener - Callback receiving finalized data with instance counts\n * @returns this for chaining\n */\n onAssociationFinalized(listener: (data: ReceiverAssociationFinalizedData) => void): this {\n return this.on('ASSOCIATION_FINALIZED', listener);\n }\n\n /**\n * Registers a listener for new associations (bubbled from workers).\n *\n * @param listener - Callback receiving association received data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (data: PoolAssociationReceivedData) => void): this {\n return this.on('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for C-STORE requests (bubbled from workers).\n *\n * @param listener - Callback receiving C-STORE request data\n * @returns this for chaining\n */\n onCStoreRequest(listener: (data: PoolCStoreRequestData) => void): this {\n return this.on('C_STORE_REQUEST', listener);\n }\n\n /**\n * Registers a listener for C-ECHO requests (bubbled from workers).\n *\n * @param listener - Callback receiving echo request data\n * @returns this for chaining\n */\n onEchoRequest(listener: (data: PoolEchoRequestData) => void): this {\n return this.on('ECHO_REQUEST', listener);\n }\n\n /**\n * Registers a listener for refused associations (bubbled from workers).\n *\n * @param listener - Callback receiving refusing association data\n * @returns this for chaining\n */\n onRefusingAssociation(listener: (data: PoolRefusingAssociationData) => void): this {\n return this.on('REFUSING_ASSOCIATION', listener);\n }\n\n /**\n * Routes an external socket to an idle worker.\n *\n * The pool must be started via `start()` before calling this method.\n * Use this when managing your own TCP listener (e.g., protocol router).\n *\n * @param socket - An incoming net.Socket to route to a worker\n */\n handleSocket(socket: net.Socket): void {\n if (!this.started) {\n socket.destroy(new Error('DicomReceiver: not started'));\n return;\n }\n void this.handleConnection(socket);\n }\n\n /** Current pool status. */\n get poolStatus(): PoolStatus {\n let idle = 0;\n let busy = 0;\n for (const w of this.workers.values()) {\n if (w.state === 'idle') idle++;\n else busy++;\n }\n return { idle, busy, total: this.workers.size };\n }\n\n // -----------------------------------------------------------------------\n // TCP proxy\n // -----------------------------------------------------------------------\n\n /** Starts the TCP proxy on the configured port. Skips if port is 0. */\n private startTcpProxy(): Promise<Result<void>> {\n if (this.options.port === 0) {\n return Promise.resolve(ok(undefined));\n }\n return new Promise(resolve => {\n this.tcpServer = net.createServer(socket => {\n void this.handleConnection(socket);\n });\n this.tcpServer.on('error', e => {\n if (!this.started) {\n resolve(err(new Error(`DicomReceiver: TCP proxy failed: ${e.message}`)));\n } else {\n this.emit('error', { error: e instanceof Error ? e : new Error(String(e)) });\n }\n });\n this.tcpServer.listen(this.options.port, () => {\n resolve(ok(undefined));\n });\n });\n }\n\n /** Closes the TCP proxy server. */\n private closeTcpProxy(): Promise<void> {\n return new Promise(resolve => {\n if (this.tcpServer === undefined) {\n resolve();\n return;\n }\n this.tcpServer.close(() => resolve());\n });\n }\n\n // -----------------------------------------------------------------------\n // Connection routing\n // -----------------------------------------------------------------------\n\n /** Routes an incoming connection to an idle worker. */\n private async handleConnection(remoteSocket: net.Socket): Promise<void> {\n remoteSocket.pause();\n\n const worker = await this.findIdleWorker();\n if (worker === undefined) {\n remoteSocket.destroy(new Error('DicomReceiver: no idle worker available'));\n this.emit('error', { error: new Error('DicomReceiver: connection rejected — pool exhausted') });\n return;\n }\n\n this.associationCounter++;\n const associationId = `assoc-${String(this.associationCounter)}`;\n const associationDir = path.join(this.options.storageDir, associationId);\n\n const mkdirResult = await ensureDirectory(associationDir);\n if (!mkdirResult.ok) {\n remoteSocket.destroy();\n this.emit('error', { error: mkdirResult.error });\n return;\n }\n\n const ctx: AssociationContext = {\n associationId,\n associationDir,\n startAt: Date.now(),\n };\n\n worker.beginAssociation(ctx);\n this.pipeConnection(worker, remoteSocket);\n void this.replenishPool();\n }\n\n /** Finds an idle worker, retrying up to connectionTimeoutMs. */\n private async findIdleWorker(): Promise<Worker | undefined> {\n const idle = this.getIdleWorker();\n if (idle !== undefined) return idle;\n\n const maxRetries = Math.min(Math.ceil(this.connectionTimeoutMs / CONNECTION_RETRY_INTERVAL_MS), MAX_CONNECTION_RETRIES);\n\n for (let i = 0; i < maxRetries; i++) {\n await delay(CONNECTION_RETRY_INTERVAL_MS);\n const found = this.getIdleWorker();\n if (found !== undefined) return found;\n if (this.stopping) return undefined;\n }\n return undefined;\n }\n\n /** Returns the first idle worker, or undefined. */\n private getIdleWorker(): Worker | undefined {\n for (const w of this.workers.values()) {\n if (w.state === 'idle') return w;\n }\n return undefined;\n }\n\n /** Pipes remote socket bidirectionally to the worker's port. */\n private pipeConnection(worker: Worker, remoteSocket: net.Socket): void {\n const workerSocket = net.createConnection({ port: worker.port, host: '127.0.0.1' });\n\n worker.setSockets(remoteSocket, workerSocket);\n\n const cleanup = (): void => {\n remoteSocket.unpipe(workerSocket);\n workerSocket.unpipe(remoteSocket);\n if (!remoteSocket.destroyed) remoteSocket.destroy();\n if (!workerSocket.destroyed) workerSocket.destroy();\n };\n\n // Wait for the worker connection to be established before piping.\n // Writing to a socket before 'connect' buffers data in userland;\n // on Windows and some container runtimes this buffered data is\n // silently lost, causing the DICOM association handshake to hang.\n workerSocket.on('connect', () => {\n remoteSocket.pipe(workerSocket);\n workerSocket.pipe(remoteSocket);\n remoteSocket.resume();\n });\n\n remoteSocket.on('error', cleanup);\n workerSocket.on('error', cleanup);\n remoteSocket.on('close', cleanup);\n workerSocket.on('close', cleanup);\n }\n\n // -----------------------------------------------------------------------\n // Worker pool management\n // -----------------------------------------------------------------------\n\n /** Spawns `count` new workers and adds them to the pool. */\n private async spawnWorkers(count: number): Promise<Result<void>> {\n const promises: Promise<Result<Worker>>[] = [];\n for (let i = 0; i < count; i++) {\n promises.push(this.spawnWorker());\n }\n const results = await Promise.all(promises);\n for (const result of results) {\n if (!result.ok) return err(result.error);\n }\n return ok(undefined);\n }\n\n /** Creates a Dcmrecv instance with the pool's shared options. */\n private createDcmrecv(port: number, tempDir: string): Result<Dcmrecv> {\n return Dcmrecv.create({\n port,\n aeTitle: this.options.aeTitle,\n outputDirectory: tempDir,\n configFile: this.options.configFile,\n configProfile: this.options.configProfile,\n acseTimeout: this.options.acseTimeout,\n dimseTimeout: this.options.dimseTimeout,\n maxPdu: this.options.maxPdu,\n filenameMode: this.options.filenameMode ?? 'unique',\n filenameExtension: this.options.filenameExtension,\n storageMode: this.options.storageMode,\n });\n }\n\n /** Spawns a single Dcmrecv worker with an ephemeral port. */\n private async spawnWorker(): Promise<Result<Worker>> {\n const portResult = await allocatePort();\n if (!portResult.ok) return portResult;\n const port = portResult.value;\n\n const tempDir = path.join(os.tmpdir(), `dcmrecv-pool-${String(port)}-${String(Date.now())}`);\n const mkdirResult = await ensureDirectory(tempDir);\n if (!mkdirResult.ok) return mkdirResult;\n\n const createResult = this.createDcmrecv(port, tempDir);\n if (!createResult.ok) return createResult;\n\n const dcmrecv = createResult.value;\n const worker = new Worker(dcmrecv, port, tempDir);\n\n this.wireWorkerEvents(worker);\n const startResult = await dcmrecv.start();\n if (!startResult.ok) {\n return err(new Error(`DicomReceiver: worker start failed on port ${String(port)}: ${startResult.error.message}`));\n }\n\n this.workers.set(port, worker);\n return ok(worker);\n }\n\n /** Stops a single worker: destroy sockets, stop process, clean temp dir, remove from pool. */\n private async stopWorker(worker: Worker): Promise<void> {\n worker.destroySockets();\n await worker.dcmrecv.stop();\n worker.dcmrecv[Symbol.dispose]();\n await removeDirSafe(worker.tempDir);\n this.workers.delete(worker.port);\n }\n\n /** Pre-emptively spawns workers to keep idle count >= minPoolSize. */\n private async replenishPool(): Promise<void> {\n const status = this.poolStatus;\n const needed = this.minPoolSize - status.idle;\n const capacity = this.maxPoolSize - status.total;\n const toSpawn = Math.min(needed, capacity);\n\n if (toSpawn <= 0) return;\n\n const promises: Promise<Result<Worker>>[] = [];\n for (let i = 0; i < toSpawn; i++) {\n promises.push(this.spawnWorker());\n }\n const results = await Promise.all(promises);\n for (const result of results) {\n if (!result.ok) {\n this.emit('error', { error: result.error });\n }\n }\n }\n\n /** Stops excess idle workers when idle count > minPoolSize + 2. */\n private async scaleDown(): Promise<void> {\n const idleWorkers: Worker[] = [];\n for (const w of this.workers.values()) {\n if (w.state === 'idle') idleWorkers.push(w);\n }\n const excess = idleWorkers.length - (this.minPoolSize + 2);\n if (excess <= 0) return;\n\n const toStop = idleWorkers.slice(0, excess);\n const promises: Promise<void>[] = [];\n for (const w of toStop) {\n promises.push(this.stopWorker(w));\n }\n await Promise.all(promises);\n }\n\n // -----------------------------------------------------------------------\n // Worker event wiring\n // -----------------------------------------------------------------------\n\n /** Wires all events on a worker: file handling, association lifecycle, output capture. */\n private wireWorkerEvents(worker: Worker): void {\n this.wireFileReceived(worker);\n this.wireAssociationComplete(worker);\n this.wireAssociationReceived(worker);\n this.wireCStoreRequest(worker);\n this.wireEchoRequest(worker);\n this.wireRefusingAssociation(worker);\n this.wireOutputCapture(worker);\n }\n\n /** Wires FILE_RECEIVED from dcmrecv worker — captures context synchronously. */\n private wireFileReceived(worker: Worker): void {\n worker.dcmrecv.onFileReceived(data => {\n const ctx = worker.context;\n if (ctx === undefined) {\n this.emit('error', {\n error: new Error(`DicomReceiver: FILE_RECEIVED with no active association (worker state: ${worker.state})`),\n filePath: data.filePath,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n });\n return;\n }\n\n // FILE_RECEIVED: raw notification from dcmrecv, before any processing\n this.emit('FILE_RECEIVED', {\n filePath: data.filePath,\n associationId: ctx.associationId,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n });\n\n const promise = this.handleFileReceived(worker, data, ctx);\n worker.trackFile(promise);\n });\n }\n\n /** Moves file to association dir, emits FILE_STORED, then parses instance. */\n private async handleFileReceived(\n worker: Worker,\n data: { filePath: string; callingAE: string; calledAE: string; source: string },\n ctx: AssociationContext\n ): Promise<void> {\n try {\n await this.moveAndEmitFile(worker, data, ctx);\n } catch (thrown: unknown) {\n const error = thrown instanceof Error ? thrown : new Error(String(thrown));\n this.emit('error', {\n error,\n filePath: data.filePath,\n associationId: ctx.associationId,\n associationDir: ctx.associationDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n });\n }\n }\n\n /** Inner handler: move file, emit FILE_STORED, parse DICOM, emit INSTANCE_RECEIVED. */\n private async moveAndEmitFile(\n worker: Worker,\n data: { filePath: string; callingAE: string; calledAE: string; source: string },\n ctx: AssociationContext\n ): Promise<void> {\n const srcPath = data.filePath;\n const destPath = path.join(ctx.associationDir, path.basename(srcPath));\n\n const moveResult = await moveFile(srcPath, destPath);\n const finalPath = moveResult.ok ? destPath : srcPath;\n const fileSize = await statFileSafe(finalPath);\n worker.recordFile(finalPath, fileSize);\n\n // FILE_STORED: file is safely on disk in the association directory\n this.emit('FILE_STORED', {\n filePath: finalPath,\n fileSize,\n associationId: ctx.associationId,\n associationDir: ctx.associationDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n });\n\n if (this.parseInstances) {\n const instanceCtx = {\n filePath: finalPath,\n fileSize,\n associationId: ctx.associationId,\n associationDir: ctx.associationDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n };\n worker.trackInstance(this.parseAndEmitInstance(worker, instanceCtx));\n }\n }\n\n /** Parses a DICOM file and emits INSTANCE_RECEIVED or INSTANCE_ERROR. */\n private async parseAndEmitInstance(worker: Worker, ctx: ReceiverFileStoredData): Promise<void> {\n try {\n const openResult = await DicomInstance.open(ctx.filePath, this.resolvedInstanceOpenOptions);\n if (!openResult.ok) {\n worker.recordInstanceError();\n this.emit('INSTANCE_ERROR', { error: openResult.error, thrown: false, ...ctx });\n return;\n }\n worker.recordInstanceSuccess();\n this.emit('INSTANCE_RECEIVED', { ...ctx, instance: openResult.value });\n } catch (thrown: unknown) {\n const error = thrown instanceof Error ? thrown : new Error(String(thrown));\n worker.recordInstanceError();\n this.emit('INSTANCE_ERROR', { error, thrown: true, ...ctx });\n }\n }\n\n /** Returns worker to idle pool on association complete, emits summary. */\n private wireAssociationComplete(worker: Worker): void {\n worker.dcmrecv.onAssociationComplete((data: AssociationCompleteData) => {\n // Defer finalization to the check phase (after I/O callbacks) so that\n // any remaining FILE_RECEIVED events in pending pipe chunks are processed\n // before the worker resets. Without this, the last STORED_FILE and\n // ASSOCIATION_RELEASE can arrive in separate pipe chunks — microtasks from\n // finalizeAssociation run between them, resetting the worker before the\n // last file is handled. (#25)\n setImmediate(() => {\n void this.finalizeAssociation(worker, data);\n });\n });\n }\n\n /** Awaits file ops, emits ASSOCIATION_COMPLETE, awaits parsing, emits ASSOCIATION_FINALIZED. */\n private async finalizeAssociation(worker: Worker, data: AssociationCompleteData): Promise<void> {\n await worker.drainPendingFiles();\n this.emitAssociationComplete(worker, data);\n\n await worker.drainInstancePending();\n this.emitAssociationFinalized(worker, data);\n\n worker.endAssociation();\n void this.scaleDown();\n }\n\n /** Emits the ASSOCIATION_COMPLETE event with transfer stats. */\n private emitAssociationComplete(worker: Worker, data: AssociationCompleteData): void {\n const ctx = worker.context;\n const assocId = ctx?.associationId ?? data.associationId;\n const assocDir = ctx?.associationDir ?? '';\n const startAt = ctx?.startAt ?? Date.now();\n const files = [...worker.files];\n const output = [...worker.outputLines];\n\n const endAt = Date.now();\n const totalBytes = sumArray(worker.fileSizes);\n const elapsedMs = endAt - startAt;\n const bytesPerSecond = elapsedMs > 0 ? Math.round((totalBytes / elapsedMs) * 1000) : 0;\n\n this.emit('ASSOCIATION_COMPLETE', {\n associationId: assocId,\n associationDir: assocDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n files,\n durationMs: data.durationMs,\n endReason: data.endReason,\n totalBytes,\n bytesPerSecond,\n startAt,\n endAt,\n output,\n });\n }\n\n /** Emits ASSOCIATION_FINALIZED after all instance parsing is done. */\n private emitAssociationFinalized(worker: Worker, data: AssociationCompleteData): void {\n const ctx = worker.context;\n this.emit('ASSOCIATION_FINALIZED', {\n associationId: ctx?.associationId ?? data.associationId,\n associationDir: ctx?.associationDir ?? '',\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n files: [...worker.files],\n instancesReceived: worker.instancesReceived,\n instanceErrors: worker.instanceErrors,\n });\n }\n\n /** Bubbles ASSOCIATION_RECEIVED from dcmrecv worker. */\n private wireAssociationReceived(worker: Worker): void {\n worker.dcmrecv.onEvent('ASSOCIATION_RECEIVED', (data: { callingAE: string; calledAE: string; source: string }) => {\n this.emit('ASSOCIATION_RECEIVED', {\n associationId: worker.context?.associationId ?? '',\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n });\n });\n }\n\n /** Bubbles C_STORE_REQUEST from dcmrecv worker. */\n private wireCStoreRequest(worker: Worker): void {\n worker.dcmrecv.onEvent('C_STORE_REQUEST', (data: { raw: string }) => {\n this.emit('C_STORE_REQUEST', {\n associationId: worker.context?.associationId ?? '',\n raw: data.raw,\n });\n });\n }\n\n /** Bubbles ECHO_REQUEST from dcmrecv worker. */\n private wireEchoRequest(worker: Worker): void {\n worker.dcmrecv.onEvent('ECHO_REQUEST', () => {\n this.emit('ECHO_REQUEST', {\n associationId: worker.context?.associationId ?? '',\n });\n });\n }\n\n /** Bubbles REFUSING_ASSOCIATION from dcmrecv worker. */\n private wireRefusingAssociation(worker: Worker): void {\n worker.dcmrecv.onEvent('REFUSING_ASSOCIATION', (data: { reason: string }) => {\n this.emit('REFUSING_ASSOCIATION', {\n reason: data.reason,\n });\n });\n }\n\n /** Captures worker output lines during busy associations. */\n private wireOutputCapture(worker: Worker): void {\n worker.dcmrecv.on('line', ({ text }: { text: string }) => {\n if (worker.state === 'busy') {\n worker.captureOutput(text);\n }\n });\n }\n\n // -----------------------------------------------------------------------\n // Abort signal\n // -----------------------------------------------------------------------\n\n /** Wires an AbortSignal to stop the receiver. */\n private wireAbortSignal(signal: AbortSignal): void {\n /* v8 ignore next 4 */\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\n/** @deprecated Use ReceiverFileStoredData instead. */\ntype ReceiverFileData = ReceiverFileStoredData;\n\nexport { DicomReceiver };\nexport type {\n DicomReceiverOptions,\n DicomReceiverEventMap,\n ReceiverFileReceivedData,\n ReceiverFileStoredData,\n ReceiverInstanceData,\n ReceiverInstanceErrorData,\n ReceiverAssociationFinalizedData,\n ReceiverFileData,\n ReceiverAssociationData,\n ReceiverErrorData,\n PoolStatus,\n PoolAssociationReceivedData,\n PoolCStoreRequestData,\n PoolEchoRequestData,\n PoolRefusingAssociationData,\n};\n","/**\n * Event patterns and types for dcmprscp output parsing.\n *\n * Defines regex patterns that match DCMTK dcmprscp (print management SCP)\n * verbose output, along with typed event data interfaces for each event.\n *\n * @module events/dcmprscp\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmprscp process output. */\nconst DcmprscpEvent = {\n DATABASE_READY: 'DATABASE_READY',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n CONFIG_ERROR: 'CONFIG_ERROR',\n} as const;\n\ntype DcmprscpEventValue = (typeof DcmprscpEvent)[keyof typeof DcmprscpEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for DATABASE_READY event. */\ninterface DatabaseReadyData {\n readonly directory: string;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface PrintAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface PrintAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface PrintCannotStartListenerData {\n readonly message: string;\n}\n\n/** Data for CONFIG_ERROR event. */\ninterface ConfigErrorData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmprscp verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmprscp verbose output. */\nconst DCMPRSCP_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmprscpEvent.DATABASE_READY,\n pattern: /Using database in directory\\s+'([^']+)'/,\n processor: (match): DatabaseReadyData => ({\n directory: match[1] ?? '',\n }),\n },\n {\n event: DcmprscpEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{0,20}\\(([^)]+)\\)/,\n processor: (match): PrintAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmprscpEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): PrintAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmprscpEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmprscpEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmprscpEvent.CANNOT_START_LISTENER,\n pattern: /cannot initialise network|cannot listen/i,\n processor: (match): PrintCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmprscpEvent.CONFIG_ERROR,\n pattern: /can't open configuration file|no (?:default )?print scp/i,\n processor: (match): ConfigErrorData => ({\n message: match[0] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMPRSCP_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmprscpEvent.CANNOT_START_LISTENER, DcmprscpEvent.CONFIG_ERROR]);\n\nexport { DcmprscpEvent, DCMPRSCP_PATTERNS, DCMPRSCP_FATAL_EVENTS };\nexport type {\n DcmprscpEventValue,\n DatabaseReadyData,\n PrintAssociationReceivedData,\n PrintAssociationAcknowledgedData,\n PrintCannotStartListenerData,\n ConfigErrorData,\n};\n","/**\n * DICOM Print Management SCP server wrapping the dcmprscp binary.\n *\n * Provides a type-safe, event-driven API for the Basic Grayscale Print\n * Management SCP. Uses a static factory pattern because binary resolution\n * and validation must happen before the constructor call.\n *\n * @module servers/DcmprsCP\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { DCMPRSCP_PATTERNS, DCMPRSCP_FATAL_EVENTS } from '../events/dcmprscp';\nimport type {\n DatabaseReadyData,\n PrintAssociationReceivedData,\n PrintAssociationAcknowledgedData,\n PrintCannotStartListenerData,\n ConfigErrorData,\n} from '../events/dcmprscp';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the DcmprsCP server. */\ninterface DcmprsCPEventMap {\n DATABASE_READY: [DatabaseReadyData];\n ASSOCIATION_RECEIVED: [PrintAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [PrintAssociationAcknowledgedData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n CANNOT_START_LISTENER: [PrintCannotStartListenerData];\n CONFIG_ERROR: [ConfigErrorData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a DcmprsCP server instance. */\ninterface DcmprsCPOptions {\n /** Path to the dcmpstat configuration file (required). */\n readonly configFile: string;\n /** Printer identifier from the config file (optional, defaults to first printer). */\n readonly printer?: string | undefined;\n /** Enable DIMSE message dumping. */\n readonly dump?: boolean | undefined;\n /** Log level override. */\n readonly logLevel?: 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace' | undefined;\n /** Path to a log configuration file. */\n readonly logConfig?: string | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmprsCPOptionsSchema = z\n .object({\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }),\n printer: z.string().min(1).optional(),\n dump: z.boolean().optional(),\n logLevel: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).optional(),\n logConfig: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in logConfig' }).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmprsCPOptions): string[] {\n const args: string[] = ['--verbose', '--config', options.configFile];\n\n if (options.printer !== undefined) {\n args.push('--printer', options.printer);\n }\n if (options.dump === true) {\n args.push('--dump');\n }\n if (options.logLevel !== undefined) {\n args.push('--log-level', options.logLevel);\n }\n if (options.logConfig !== undefined) {\n args.push('--log-config', options.logConfig);\n }\n\n return args;\n}\n\n// ---------------------------------------------------------------------------\n// DcmprsCP class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Print Management SCP server wrapping the dcmprscp binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Note: dcmprscp does not print a \"listening\" message. The `start()` method\n * resolves either when the DATABASE_READY event is detected or on spawn.\n *\n * @example\n * ```ts\n * const result = DcmprsCP.create({ configFile: '/etc/dcmpstat.cfg' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('DATABASE_READY', (data) => console.log('DB:', data.directory));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass DcmprsCP extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /**\n * Registers a typed listener for a dcmprscp-specific event.\n *\n * @param event - The event name from DcmprsCPEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n onEvent<K extends keyof DcmprsCPEventMap>(event: K, listener: (...args: DcmprsCPEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for when the database is ready.\n *\n * @param listener - Callback receiving database ready data\n * @returns this for chaining\n */\n onDatabaseReady(listener: (...args: DcmprsCPEventMap['DATABASE_READY']) => void): this {\n return this.onEvent('DATABASE_READY', listener);\n }\n\n /**\n * Registers a listener for incoming associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (...args: DcmprsCPEventMap['ASSOCIATION_RECEIVED']) => void): this {\n return this.onEvent('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Creates a new DcmprsCP server instance.\n *\n * @param options - Configuration options for the dcmprscp server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmprsCPOptions): Result<DcmprsCP> {\n const validation = DcmprsCPOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmprscp', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmprscp');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMPRSCP_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n isStartedPredicate: line => /Using database in directory/i.test(line),\n };\n\n return ok(new DcmprsCP(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMPRSCP_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { DcmprsCP };\nexport type { DcmprsCPOptions, DcmprsCPEventMap };\n","/**\n * Event patterns and types for dcmpsrcv output parsing.\n *\n * Defines regex patterns that match DCMTK dcmpsrcv (viewer network receiver)\n * verbose output. Shares several patterns with dcmrecv/storescp since\n * dcmpsrcv handles incoming DICOM associations and C-STORE operations.\n *\n * @module events/dcmpsrcv\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmpsrcv process output. */\nconst DcmpsrcvEvent = {\n LISTENING: 'LISTENING',\n DATABASE_READY: 'DATABASE_READY',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n ECHO_REQUEST: 'ECHO_REQUEST',\n C_STORE_REQUEST: 'C_STORE_REQUEST',\n FILE_DELETED: 'FILE_DELETED',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n CONFIG_ERROR: 'CONFIG_ERROR',\n TERMINATING: 'TERMINATING',\n} as const;\n\ntype DcmpsrcvEventValue = (typeof DcmpsrcvEvent)[keyof typeof DcmpsrcvEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for LISTENING event. */\ninterface ReceiverListeningData {\n readonly receiverId: string;\n readonly port: number;\n}\n\n/** Data for DATABASE_READY event. */\ninterface ReceiverDatabaseReadyData {\n readonly directory: string;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface ReceiverAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface ReceiverAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for ECHO_REQUEST event. */\ninterface ReceiverEchoRequestData {\n readonly messageId: number;\n}\n\n/** Data for C_STORE_REQUEST event. */\ninterface ReceiverCStoreRequestData {\n readonly raw: string;\n}\n\n/** Data for FILE_DELETED event. */\ninterface FileDeletedData {\n readonly filePath: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface ReceiverCannotStartListenerData {\n readonly message: string;\n}\n\n/** Data for CONFIG_ERROR event. */\ninterface ReceiverConfigErrorData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmpsrcv verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmpsrcv verbose output. */\nconst DCMPSRCV_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmpsrcvEvent.LISTENING,\n pattern: /Receiver\\s{1,20}(\\S+)\\s{1,20}on port\\s{1,20}(\\d+)/,\n processor: (match): ReceiverListeningData => ({\n receiverId: match[1] ?? '',\n port: Number(match[2]),\n }),\n },\n {\n event: DcmpsrcvEvent.DATABASE_READY,\n pattern: /Using database in directory\\s+'([^']+)'/,\n processor: (match): ReceiverDatabaseReadyData => ({\n directory: match[1] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s*\\(([^)]+)\\)/,\n processor: (match): ReceiverAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): ReceiverAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmpsrcvEvent.ECHO_REQUEST,\n pattern: /Received Echo SCP RQ:\\s*MsgID\\s+(\\d+)/,\n processor: (match): ReceiverEchoRequestData => ({\n messageId: Number(match[1]),\n }),\n },\n {\n event: DcmpsrcvEvent.C_STORE_REQUEST,\n pattern: /Received Store SCP/i,\n processor: (match): ReceiverCStoreRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.FILE_DELETED,\n pattern: /Deleting Image File:\\s{0,20}(.{1,1024})/,\n processor: (match): FileDeletedData => ({\n filePath: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmpsrcvEvent.CANNOT_START_LISTENER,\n pattern: /cannot listen on port/i,\n processor: (match): ReceiverCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.CONFIG_ERROR,\n pattern: /can't open configuration file|missing configuration file|no application entity title|no or invalid port number/i,\n processor: (match): ReceiverConfigErrorData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.TERMINATING,\n pattern: /Terminating all receivers/i,\n processor: () => undefined,\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMPSRCV_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmpsrcvEvent.CANNOT_START_LISTENER, DcmpsrcvEvent.CONFIG_ERROR]);\n\nexport { DcmpsrcvEvent, DCMPSRCV_PATTERNS, DCMPSRCV_FATAL_EVENTS };\nexport type {\n DcmpsrcvEventValue,\n ReceiverListeningData,\n ReceiverDatabaseReadyData,\n ReceiverAssociationReceivedData,\n ReceiverAssociationAcknowledgedData,\n ReceiverEchoRequestData,\n ReceiverCStoreRequestData,\n FileDeletedData,\n ReceiverCannotStartListenerData,\n ReceiverConfigErrorData,\n};\n","/**\n * DICOM Viewer Network Receiver wrapping the dcmpsrcv binary.\n *\n * Provides a type-safe, event-driven API for the DICOMscope network\n * receiver component. Accepts incoming DICOM associations for storage\n * and C-ECHO verification.\n *\n * @module servers/Dcmpsrcv\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { DCMPSRCV_PATTERNS, DCMPSRCV_FATAL_EVENTS } from '../events/dcmpsrcv';\nimport type {\n ReceiverListeningData,\n ReceiverDatabaseReadyData,\n ReceiverAssociationReceivedData,\n ReceiverAssociationAcknowledgedData,\n ReceiverEchoRequestData,\n ReceiverCStoreRequestData,\n FileDeletedData,\n ReceiverCannotStartListenerData,\n ReceiverConfigErrorData,\n} from '../events/dcmpsrcv';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the Dcmpsrcv server. */\ninterface DcmpsrcvEventMap {\n LISTENING: [ReceiverListeningData];\n DATABASE_READY: [ReceiverDatabaseReadyData];\n ASSOCIATION_RECEIVED: [ReceiverAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [ReceiverAssociationAcknowledgedData];\n ECHO_REQUEST: [ReceiverEchoRequestData];\n C_STORE_REQUEST: [ReceiverCStoreRequestData];\n FILE_DELETED: [FileDeletedData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n CANNOT_START_LISTENER: [ReceiverCannotStartListenerData];\n CONFIG_ERROR: [ReceiverConfigErrorData];\n TERMINATING: [];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a Dcmpsrcv server instance. */\ninterface DcmpsrcvOptions {\n /** Path to the dcmpstat configuration file (required). */\n readonly configFile: string;\n /** Receiver identifier from the config file (optional, defaults to first receiver). */\n readonly receiverId?: string | undefined;\n /** Log level override. */\n readonly logLevel?: 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace' | undefined;\n /** Path to a log configuration file. */\n readonly logConfig?: string | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmpsrcvOptionsSchema = z\n .object({\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }),\n receiverId: z.string().min(1).optional(),\n logLevel: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).optional(),\n logConfig: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in logConfig' }).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmpsrcvOptions): string[] {\n const args: string[] = ['--verbose'];\n\n if (options.logLevel !== undefined) {\n args.push('--log-level', options.logLevel);\n }\n if (options.logConfig !== undefined) {\n args.push('--log-config', options.logConfig);\n }\n\n args.push(options.configFile);\n\n if (options.receiverId !== undefined) {\n args.push(options.receiverId);\n }\n\n return args;\n}\n\n// ---------------------------------------------------------------------------\n// Dcmpsrcv class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Viewer Network Receiver wrapping the dcmpsrcv binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * The `start()` method resolves when the LISTENING event is detected\n * (i.e., \"Receiver <id> on port <port>\").\n *\n * @example\n * ```ts\n * const result = Dcmpsrcv.create({ configFile: '/etc/dcmpstat.cfg', receiverId: 'RECEIVE_1' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('LISTENING', (data) => console.log(`Listening on port ${data.port}`));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass Dcmpsrcv extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /**\n * Registers a typed listener for a dcmpsrcv-specific event.\n *\n * @param event - The event name from DcmpsrcvEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n onEvent<K extends keyof DcmpsrcvEventMap>(event: K, listener: (...args: DcmpsrcvEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for when the receiver starts listening.\n *\n * @param listener - Callback receiving listening data (receiver ID and port)\n * @returns this for chaining\n */\n onListening(listener: (...args: DcmpsrcvEventMap['LISTENING']) => void): this {\n return this.onEvent('LISTENING', listener);\n }\n\n /**\n * Registers a listener for incoming C-STORE requests.\n *\n * @param listener - Callback receiving C-STORE request data\n * @returns this for chaining\n */\n onCStoreRequest(listener: (...args: DcmpsrcvEventMap['C_STORE_REQUEST']) => void): this {\n return this.onEvent('C_STORE_REQUEST', listener);\n }\n\n /**\n * Creates a new Dcmpsrcv server instance.\n *\n * @param options - Configuration options for the dcmpsrcv server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmpsrcvOptions): Result<Dcmpsrcv> {\n const validation = DcmpsrcvOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmpsrcv', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmpsrcv');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMPSRCV_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n isStartedPredicate: line => /Receiver\\s+\\S+\\s+on port/i.test(line),\n };\n\n return ok(new Dcmpsrcv(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMPSRCV_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { Dcmpsrcv };\nexport type { DcmpsrcvOptions, DcmpsrcvEventMap };\n","/**\n * Event patterns and types for dcmqrscp output parsing.\n *\n * Defines regex patterns that match DCMTK dcmqrscp (Query/Retrieve SCP)\n * verbose output, along with typed event data interfaces for each event.\n *\n * @module events/dcmqrscp\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmqrscp process output. */\nconst DcmqrscpEvent = {\n LISTENING: 'LISTENING',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n C_FIND_REQUEST: 'C_FIND_REQUEST',\n C_MOVE_REQUEST: 'C_MOVE_REQUEST',\n C_GET_REQUEST: 'C_GET_REQUEST',\n C_STORE_REQUEST: 'C_STORE_REQUEST',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n} as const;\n\ntype DcmqrscpEventValue = (typeof DcmqrscpEvent)[keyof typeof DcmqrscpEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for LISTENING event. */\ninterface QRListeningData {\n readonly port: number;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface QRAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface QRAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for C_FIND_REQUEST event. */\ninterface QRCFindRequestData {\n readonly raw: string;\n}\n\n/** Data for C_MOVE_REQUEST event. */\ninterface QRCMoveRequestData {\n readonly raw: string;\n}\n\n/** Data for C_GET_REQUEST event. */\ninterface QRCGetRequestData {\n readonly raw: string;\n}\n\n/** Data for C_STORE_REQUEST event. */\ninterface QRCStoreRequestData {\n readonly raw: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface QRCannotStartListenerData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmqrscp verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmqrscp verbose output. */\nconst DCMQRSCP_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmqrscpEvent.LISTENING,\n pattern: /listening on port\\s{1,20}(\\d+)/i,\n processor: (match): QRListeningData => ({\n port: Number(match[1]),\n }),\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{0,20}([^\\r\\n]+)/,\n processor: (match): QRAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): QRAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmqrscpEvent.C_FIND_REQUEST,\n pattern: /Received Find (?:SCP )?Request/i,\n processor: (match): QRCFindRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.C_MOVE_REQUEST,\n pattern: /Received Move (?:SCP )?Request/i,\n processor: (match): QRCMoveRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.C_GET_REQUEST,\n pattern: /Received Get (?:SCP )?Request/i,\n processor: (match): QRCGetRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.C_STORE_REQUEST,\n pattern: /Received Store (?:SCP )?Request/i,\n processor: (match): QRCStoreRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmqrscpEvent.CANNOT_START_LISTENER,\n pattern: /cannot listen|cannot initialise network/i,\n processor: (match): QRCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMQRSCP_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmqrscpEvent.CANNOT_START_LISTENER]);\n\nexport { DcmqrscpEvent, DCMQRSCP_PATTERNS, DCMQRSCP_FATAL_EVENTS };\nexport type {\n DcmqrscpEventValue,\n QRListeningData,\n QRAssociationReceivedData,\n QRAssociationAcknowledgedData,\n QRCFindRequestData,\n QRCMoveRequestData,\n QRCGetRequestData,\n QRCStoreRequestData,\n QRCannotStartListenerData,\n};\n","/**\n * DICOM Query/Retrieve SCP server wrapping the dcmqrscp binary.\n *\n * Provides a type-safe, event-driven API for the Q/R SCP that supports\n * C-FIND, C-MOVE, C-GET, and C-STORE operations. Uses a static factory\n * pattern because binary resolution and validation must happen before\n * the constructor call.\n *\n * @module servers/DcmQRSCP\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { DCMQRSCP_PATTERNS, DCMQRSCP_FATAL_EVENTS } from '../events/dcmqrscp';\nimport type {\n QRListeningData,\n QRAssociationReceivedData,\n QRAssociationAcknowledgedData,\n QRCFindRequestData,\n QRCMoveRequestData,\n QRCGetRequestData,\n QRCStoreRequestData,\n QRCannotStartListenerData,\n} from '../events/dcmqrscp';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the DcmQRSCP server. */\ninterface DcmQRSCPEventMap {\n LISTENING: [QRListeningData];\n ASSOCIATION_RECEIVED: [QRAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [QRAssociationAcknowledgedData];\n C_FIND_REQUEST: [QRCFindRequestData];\n C_MOVE_REQUEST: [QRCMoveRequestData];\n C_GET_REQUEST: [QRCGetRequestData];\n C_STORE_REQUEST: [QRCStoreRequestData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n CANNOT_START_LISTENER: [QRCannotStartListenerData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a DcmQRSCP server instance. */\ninterface DcmQRSCPOptions {\n /** Path to the dcmqrscp configuration file (required). */\n readonly configFile: string;\n /** Override port from config (positional arg). */\n readonly port?: number | undefined;\n /** Single-process mode (-s flag, recommended on Windows). */\n readonly singleProcess?: boolean | undefined;\n /** Check Find responses (-XF). */\n readonly checkFind?: boolean | undefined;\n /** Check Move responses (-XM). */\n readonly checkMove?: boolean | undefined;\n /** Disable C-GET support (--disable-get). */\n readonly disableGet?: boolean | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Enable verbose mode (default true for event detection). */\n readonly verbose?: boolean | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmQRSCPOptionsSchema = z\n .object({\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }),\n port: z.number().int().min(1).max(65535).optional(),\n singleProcess: z.boolean().optional(),\n checkFind: z.boolean().optional(),\n checkMove: z.boolean().optional(),\n disableGet: z.boolean().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n verbose: z.boolean().optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmQRSCPOptions): string[] {\n const args: string[] = [];\n\n if (options.verbose !== false) {\n args.push('--verbose');\n }\n\n args.push('--config', options.configFile);\n\n if (options.singleProcess === true) {\n args.push('-s');\n }\n if (options.checkFind === true) {\n args.push('-XF');\n }\n if (options.checkMove === true) {\n args.push('-XM');\n }\n if (options.disableGet === true) {\n args.push('--disable-get');\n }\n\n buildNetworkArgs(args, options);\n\n if (options.port !== undefined) {\n args.push(String(options.port));\n }\n\n return args;\n}\n\n/** Appends network-related CLI flags. */\nfunction buildNetworkArgs(args: string[], options: DcmQRSCPOptions): void {\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n}\n\n// ---------------------------------------------------------------------------\n// DcmQRSCP class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Query/Retrieve SCP server wrapping the dcmqrscp binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * @example\n * ```ts\n * const result = DcmQRSCP.create({ configFile: '/etc/dcmqrscp.cfg', port: 11112 });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('C_FIND_REQUEST', (data) => console.log('Find:', data.raw));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass DcmQRSCP extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n /**\n * Registers a typed listener for a dcmqrscp-specific event.\n *\n * @param event - The event name from DcmQRSCPEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof DcmQRSCPEventMap>(event: K, listener: (...args: DcmQRSCPEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming C-FIND requests.\n *\n * @param listener - Callback receiving C-FIND request data\n * @returns this for chaining\n */\n onCFindRequest(listener: (...args: DcmQRSCPEventMap['C_FIND_REQUEST']) => void): this {\n return this.onEvent('C_FIND_REQUEST', listener);\n }\n\n /**\n * Registers a listener for incoming C-MOVE requests.\n *\n * @param listener - Callback receiving C-MOVE request data\n * @returns this for chaining\n */\n onCMoveRequest(listener: (...args: DcmQRSCPEventMap['C_MOVE_REQUEST']) => void): this {\n return this.onEvent('C_MOVE_REQUEST', listener);\n }\n\n /**\n * Creates a new DcmQRSCP server instance.\n *\n * @param options - Configuration options for the dcmqrscp server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmQRSCPOptions): Result<DcmQRSCP> {\n const validation = DcmQRSCPOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmqrscp', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmqrscp');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMQRSCP_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n // dcmqrscp v3.7.0+ does not print a \"listening on port\" message even\n // in verbose/debug mode, so we resolve on spawn (like StoreSCP) and\n // rely on a short warmup delay in callers that need the socket ready.\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n };\n\n return ok(new DcmQRSCP(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMQRSCP_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { DcmQRSCP };\nexport type { DcmQRSCPOptions, DcmQRSCPEventMap };\n","/**\n * Event patterns and types for wlmscpfs output parsing.\n *\n * Defines regex patterns that match DCMTK wlmscpfs (Worklist Management SCP)\n * verbose output, along with typed event data interfaces for each event.\n *\n * @module events/wlmscpfs\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by wlmscpfs process output. */\nconst WlmscpfsEvent = {\n LISTENING: 'LISTENING',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n C_FIND_REQUEST: 'C_FIND_REQUEST',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n ECHO_REQUEST: 'ECHO_REQUEST',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n} as const;\n\ntype WlmscpfsEventValue = (typeof WlmscpfsEvent)[keyof typeof WlmscpfsEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for LISTENING event. */\ninterface WlmListeningData {\n readonly port: number;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface WlmAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface WlmAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for C_FIND_REQUEST event. */\ninterface WlmCFindRequestData {\n readonly raw: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface WlmCannotStartListenerData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for wlmscpfs verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing wlmscpfs verbose output. */\nconst WLMSCPFS_PATTERNS: readonly EventPattern[] = [\n {\n event: WlmscpfsEvent.LISTENING,\n pattern: /listening on port\\s{1,20}(\\d+)/i,\n processor: (match): WlmListeningData => ({\n port: Number(match[1]),\n }),\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{0,20}([^\\r\\n]+)/,\n processor: (match): WlmAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): WlmAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: WlmscpfsEvent.C_FIND_REQUEST,\n pattern: /Received (?:C-FIND|Find) Request/i,\n processor: (match): WlmCFindRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: WlmscpfsEvent.ECHO_REQUEST,\n pattern: /Received (?:C-ECHO|Echo) Request/i,\n processor: () => undefined,\n },\n {\n event: WlmscpfsEvent.CANNOT_START_LISTENER,\n pattern: /cannot listen|cannot initialise network/i,\n processor: (match): WlmCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst WLMSCPFS_FATAL_EVENTS: ReadonlySet<string> = new Set([WlmscpfsEvent.CANNOT_START_LISTENER]);\n\nexport { WlmscpfsEvent, WLMSCPFS_PATTERNS, WLMSCPFS_FATAL_EVENTS };\nexport type {\n WlmscpfsEventValue,\n WlmListeningData,\n WlmAssociationReceivedData,\n WlmAssociationAcknowledgedData,\n WlmCFindRequestData,\n WlmCannotStartListenerData,\n};\n","/**\n * DICOM Worklist Management SCP server wrapping the wlmscpfs binary.\n *\n * Provides a type-safe, event-driven API for serving worklist data\n * from a file-system based database. Uses a static factory pattern\n * because binary resolution and validation must happen before the\n * constructor call.\n *\n * @module servers/Wlmscpfs\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { WLMSCPFS_PATTERNS, WLMSCPFS_FATAL_EVENTS } from '../events/wlmscpfs';\nimport type {\n WlmListeningData,\n WlmAssociationReceivedData,\n WlmAssociationAcknowledgedData,\n WlmCFindRequestData,\n WlmCannotStartListenerData,\n} from '../events/wlmscpfs';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the Wlmscpfs server. */\ninterface WlmscpfsEventMap {\n LISTENING: [WlmListeningData];\n ASSOCIATION_RECEIVED: [WlmAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [WlmAssociationAcknowledgedData];\n C_FIND_REQUEST: [WlmCFindRequestData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n ECHO_REQUEST: [];\n CANNOT_START_LISTENER: [WlmCannotStartListenerData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a Wlmscpfs server instance. */\ninterface WlmscpfsOptions {\n /** Port to listen on (required, positional arg). */\n readonly port: number;\n /** Worklist data directory (required, -dfp flag). */\n readonly worklistDirectory: string;\n /** Enable file rejection (default true). Maps to -efr / -dfr. */\n readonly enableFileRejection?: boolean | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum simultaneous associations. */\n readonly maxAssociations?: number | undefined;\n /** Enable verbose mode (default true for event detection). */\n readonly verbose?: boolean | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst WlmscpfsOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n worklistDirectory: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in worklistDirectory' }),\n enableFileRejection: z.boolean().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxAssociations: z.number().int().positive().optional(),\n verbose: z.boolean().optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: WlmscpfsOptions): string[] {\n const args: string[] = [];\n\n if (options.verbose !== false) {\n args.push('--verbose');\n }\n\n args.push('-dfp', options.worklistDirectory);\n\n if (options.enableFileRejection === false) {\n args.push('-dfr');\n } else {\n args.push('-efr');\n }\n\n buildNetworkArgs(args, options);\n\n args.push(String(options.port));\n\n return args;\n}\n\n/** Appends network-related CLI flags. */\nfunction buildNetworkArgs(args: string[], options: WlmscpfsOptions): void {\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n if (options.maxAssociations !== undefined) {\n args.push('--max-associations', String(options.maxAssociations));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Wlmscpfs class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Worklist Management SCP server wrapping the wlmscpfs binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Note: wlmscpfs does not print a reliable \"listening\" message in all\n * DCMTK versions, so `start()` resolves on spawn (like StoreSCP).\n *\n * @example\n * ```ts\n * const result = Wlmscpfs.create({ port: 2005, worklistDirectory: '/var/worklists' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('C_FIND_REQUEST', (data) => console.log('Find:', data.raw));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass Wlmscpfs extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n /**\n * Registers a typed listener for a wlmscpfs-specific event.\n *\n * @param event - The event name from WlmscpfsEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof WlmscpfsEventMap>(event: K, listener: (...args: WlmscpfsEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming C-FIND requests.\n *\n * @param listener - Callback receiving C-FIND request data\n * @returns this for chaining\n */\n onCFindRequest(listener: (...args: WlmscpfsEventMap['C_FIND_REQUEST']) => void): this {\n return this.onEvent('C_FIND_REQUEST', listener);\n }\n\n /**\n * Registers a listener for when the server starts listening.\n *\n * @param listener - Callback receiving listening data (port)\n * @returns this for chaining\n */\n onListening(listener: (...args: WlmscpfsEventMap['LISTENING']) => void): this {\n return this.onEvent('LISTENING', listener);\n }\n\n /**\n * Creates a new Wlmscpfs server instance.\n *\n * @param options - Configuration options for the wlmscpfs server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: WlmscpfsOptions): Result<Wlmscpfs> {\n const validation = WlmscpfsOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('wlmscpfs', validation.error));\n }\n\n const binaryResult = resolveBinary('wlmscpfs');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of WLMSCPFS_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n // wlmscpfs doesn't reliably print \"listening\" — resolve on spawn\n };\n\n return ok(new Wlmscpfs(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (WLMSCPFS_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { Wlmscpfs };\nexport type { WlmscpfsOptions, WlmscpfsEventMap };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/constants.ts","../src/DcmtkProcess.ts","../src/parsers/LineParser.ts","../src/patterns.ts","../src/findDcmtkPath.ts","../src/tools/_resolveBinary.ts","../src/tools/_toolError.ts","../src/events/dcmrecv.ts","../src/servers/AssociationTracker.ts","../src/servers/Dcmrecv.ts","../src/events/storescp.ts","../src/servers/StoreSCP.ts","../src/utils/fs.ts","../src/brands.ts","../src/dicom/tagPath.ts","../src/dicom/walkTags.ts","../src/dicom/DicomDataset.ts","../src/dicom/ChangeSet.ts","../src/exec.ts","../src/tools/_xmlToJson.ts","../src/tools/_repairJson.ts","../src/tools/dcm2json.ts","../src/tools/dcmodify.ts","../src/dicom/_fileHelpers.ts","../src/dicom/DicomInstance.ts","../src/servers/DicomReceiver.ts","../src/events/dcmprscp.ts","../src/servers/DcmprsCP.ts","../src/events/dcmpsrcv.ts","../src/servers/Dcmpsrcv.ts","../src/events/dcmqrscp.ts","../src/servers/DcmQRSCP.ts","../src/events/wlmscpfs.ts","../src/servers/Wlmscpfs.ts"],"names":["EventEmitter","stderr","isWindows","binaryName","join","path","parser","z","buildArgs","kill","spawn","rm","VERBOSITY_FLAGS","copyFile","stat","unlink","delay","buildNetworkArgs"],"mappings":";;;;;;;;;;;;;;;;;;;;AAqCA,SAAS,GAAM,KAAA,EAA4B;AACvC,EAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,KAAA,EAAM;AAC7B;AAcA,SAAS,IAAO,KAAA,EAA4B;AACxC,EAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAM;AAC9B;;;ACzCA,IAAM,kBAAA,GAAqB,GAAA;AAG3B,IAAM,wBAAA,GAA2B,GAAA;AAGjC,IAAM,wBAAA,GAA2B,GAAA;AAGjC,IAAM,wBAAA,GAA2B,GAAA;AAwBjC,IAAM,oBAAA,GAAuB,CAAC,+BAAA,EAAiC,qCAAA,EAAuC,kCAAkC,CAAA;AAGxI,IAAM,iBAAA,GAAoB,CAAC,gBAAA,EAAkB,UAAA,EAAY,kBAAkB,mBAAmB,CAAA;AAO9F,IAAM,iBAAA,GAAoB,CAAC,UAAA,EAAY,SAAA,EAAW,YAAY,SAAA,EAAW,SAAA,EAAW,WAAW,SAAS,CAAA;AAOxG,IAAM,eAAA,GAAkB,GAAA;AAGxB,IAAM,kBAAA,GAAqB,GAAA;AAG3B,IAAM,mBAAA,GAAsB,EAAA;AAG5B,IAAM,wBAAA,GAA2B,GAAA;AAGjC,IAAM,gBAAA,GAAmB,MAAM,IAAA,GAAO,IAAA;;;ACpBtC,IAAM,YAAA,GAAe;AAAA,EACjB,IAAA,EAAM,MAAA;AAAA,EACN,QAAA,EAAU,UAAA;AAAA,EACV,OAAA,EAAS,SAAA;AAAA,EACT,QAAA,EAAU,UAAA;AAAA,EACV,OAAA,EAAS;AACb;AA4BA,IAAM,YAAA,GAAN,cAA2B,YAAA,CAAmC;AAAA,EAO1D,YAAY,MAAA,EAA4B;AACpC,IAAA,KAAA,EAAM;AAPV,IAAA,aAAA,CAAA,IAAA,EAAQ,SAA2B,YAAA,CAAa,IAAA,CAAA;AAChD,IAAA,aAAA,CAAA,IAAA,EAAQ,OAAA,EAA6B,IAAA,CAAA;AACrC,IAAA,aAAA,CAAA,IAAA,EAAQ,cAAA,EAAe,EAAA,CAAA;AACvB,IAAA,aAAA,CAAA,IAAA,EAAQ,cAAA,EAAe,EAAA,CAAA;AACvB,IAAA,aAAA,CAAA,IAAA,EAAiB,QAAA,CAAA;AAMb,IAAA,IAAA,CAAK,gBAAgB,EAAE,CAAA;AACvB,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAKd,IAAA,IAAA,CAAK,EAAA,CAAG,SAAS,MAAM;AAAA,IAAC,CAAC,CAAA;AAAA,EAC7B;AAAA;AAAA,EAGA,IAAI,SAAA,GAAqB;AACrB,IAAA,OAAO,IAAA,CAAK,UAAU,YAAA,CAAa,OAAA;AAAA,EACvC;AAAA;AAAA,EAGA,IAAI,YAAA,GAAkC;AAClC,IAAA,OAAO,IAAA,CAAK,KAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,KAAA,GAA+B;AACjC,IAAA,IAAI,IAAA,CAAK,KAAA,KAAU,YAAA,CAAa,IAAA,EAAM;AAClC,MAAA,OAAO,IAAI,IAAI,KAAA,CAAM,sCAAsC,IAAA,CAAK,KAAK,GAAG,CAAC,CAAA;AAAA,IAC7E;AACA,IAAA,IAAA,CAAK,QAAQ,YAAA,CAAa,QAAA;AAC1B,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,MAAA,CAAO,cAAA,IAAkB,wBAAA;AAEhD,IAAA,OAAO,IAAI,QAAsB,CAAA,OAAA,KAAW;AACxC,MAAA,IAAI,OAAA,GAAU,KAAA;AACd,MAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC3B,QAAA,IAAI,OAAA,EAAS;AACb,QAAA,OAAA,GAAU,IAAA;AACV,QAAA,IAAA,CAAK,QAAQ,YAAA,CAAa,OAAA;AAC1B,QAAA,IAAA,CAAK,SAAA,EAAU;AACf,QAAA,OAAA,CAAQ,IAAI,IAAI,KAAA,CAAM,kCAAkC,SAAS,CAAA,EAAA,CAAI,CAAC,CAAC,CAAA;AAAA,MAC3E,GAAG,SAAS,CAAA;AAIZ,MAAA,MAAM,MAAA,GAAS,CAAC,MAAA,KAA+B;AAC3C,QAAA,IAAI,OAAA,EAAS;AACb,QAAA,OAAA,GAAU,IAAA;AACV,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,OAAA,CAAQ,MAAM,CAAA;AAAA,MAClB,CAAA;AAEA,MAAA,IAAI;AACA,QAAA,IAAA,CAAK,KAAA,GAAQ,KAAA,CAAM,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,CAAC,GAAG,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA,EAAG;AAAA,UAC1D,GAAA,EAAK,KAAK,MAAA,CAAO,GAAA;AAAA,UACjB,WAAA,EAAa;AAAA,SAChB,CAAA;AAAA,MAEL,SAAS,CAAA,EAAY;AACjB,QAAA,MAAA,CAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,MAAA,CAAO,CAAC,CAAA,CAAE,OAAO,CAAA,CAAE,CAAC,CAAC,CAAA;AACtE,QAAA;AAAA,MACJ;AAEA,MAAA,IAAA,CAAK,gBAAgB,MAAM,CAAA;AAAA,IAC/B,CAAC,CAAA;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAA,GAAsB;AACxB,IAAA,IAAI,KAAK,KAAA,KAAU,YAAA,CAAa,WAAW,IAAA,CAAK,KAAA,KAAU,aAAa,IAAA,EAAM;AACzE,MAAA;AAAA,IACJ;AAEA,IAAA,IAAA,CAAK,QAAQ,YAAA,CAAa,QAAA;AAC1B,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,MAAA,CAAO,cAAA,IAAkB,wBAAA;AAE9C,IAAA,OAAO,IAAI,QAAc,CAAA,OAAA,KAAW;AAEhC,MAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC3B,QAAA,IAAA,CAAK,SAAA,EAAU;AACf,QAAA,IAAA,CAAK,QAAQ,YAAA,CAAa,OAAA;AAC1B,QAAA,OAAA,EAAQ;AAAA,MACZ,GAAG,OAAO,CAAA;AAMV,MAAA,IAAI,KAAK,KAAA,EAAO;AACZ,QAAA,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,OAAA,EAAS,MAAM;AAC3B,UAAA,YAAA,CAAa,KAAK,CAAA;AAClB,UAAA,IAAA,CAAK,QAAQ,YAAA,CAAa,OAAA;AAC1B,UAAA,OAAA,EAAQ;AAAA,QACZ,CAAC,CAAA;AACD,QAAA,IAAA,CAAK,SAAA,EAAU;AAAA,MAEnB,CAAA,MAAO;AACH,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,IAAA,CAAK,QAAQ,YAAA,CAAa,OAAA;AAC1B,QAAA,OAAA,EAAQ;AAAA,MACZ;AAAA,IAEJ,CAAC,CAAA;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,CAAC,MAAA,CAAO,OAAO,CAAA,GAAU;AACrB,IAAA,IAAI,KAAK,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,SAAA,EAAU;AACf,MAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AAAA,IACjB;AACA,IAAA,IAAA,CAAK,QAAQ,YAAA,CAAa,OAAA;AAC1B,IAAA,IAAA,CAAK,kBAAA,EAAmB;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAMQ,SAAA,GAAkB;AACtB,IAAA,IAAI,KAAK,KAAA,EAAO,GAAA,KAAQ,UAAa,IAAA,CAAK,KAAA,CAAM,QAAQ,IAAA,EAAM;AAC1D,MAAA,IAAI;AACA,QAAA,IAAA,CAAK,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,MAEvB,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,MAAA,EAA8C;AAClE,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AACnB,IAAA,IAAI,CAAC,KAAA,EAAO;AAEZ,IAAA,KAAA,CAAM,EAAA,CAAG,OAAA,EAAS,CAAC,KAAA,KAAiB;AAChC,MAAA,IAAA,CAAK,KAAK,OAAA,EAAS,EAAE,KAAA,EAAO,KAAA,EAAO,MAAM,CAAA;AACzC,MAAA,IAAI,IAAA,CAAK,KAAA,KAAU,YAAA,CAAa,QAAA,EAAU;AACtC,QAAA,IAAA,CAAK,QAAQ,YAAA,CAAa,OAAA;AAC1B,QAAA,MAAA,CAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,4BAAA,EAA+B,MAAM,OAAO,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,MACzE;AAAA,IACJ,CAAC,CAAA;AAED,IAAA,KAAA,CAAM,EAAA,CAAG,OAAA,EAAS,CAAC,IAAA,KAAwB;AACvC,MAAA,MAAM,YAAY,IAAA,CAAK,KAAA;AACvB,MAAA,IAAA,CAAK,QAAQ,YAAA,CAAa,OAAA;AAC1B,MAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,MAAA,MAAM,MAAA,GAAS,CAAA,yBAAA,EAA4B,MAAA,CAAO,IAAA,IAAQ,MAAM,CAAC,CAAA,CAAA;AACjE,MAAA,IAAA,CAAK,IAAA,CAAK,SAAA,EAAW,EAAE,MAAA,EAAQ,CAAA;AAC/B,MAAA,IAAI,SAAA,KAAc,aAAa,QAAA,EAAU,MAAA,CAAO,IAAI,IAAI,KAAA,CAAM,MAAM,CAAC,CAAC,CAAA;AAAA,IAC1E,CAAC,CAAA;AAED,IAAA,KAAA,CAAM,MAAA,EAAQ,EAAA,CAAG,MAAA,EAAQ,CAAC,KAAA,KAA2B;AACjD,MAAA,IAAA,CAAK,UAAA,CAAW,UAAU,KAAK,CAAA;AAAA,IACnC,CAAC,CAAA;AACD,IAAA,KAAA,CAAM,MAAA,EAAQ,EAAA,CAAG,MAAA,EAAQ,CAAC,KAAA,KAA2B;AACjD,MAAA,IAAA,CAAK,UAAA,CAAW,UAAU,KAAK,CAAA;AAAA,IACnC,CAAC,CAAA;AAED,IAAA,KAAA,CAAM,EAAA,CAAG,SAAS,MAAM;AACpB,MAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,kBAAA,EAAoB;AACjC,QAAA,IAAA,CAAK,QAAQ,YAAA,CAAa,OAAA;AAC1B,QAAA,IAAA,CAAK,KAAK,SAAS,CAAA;AACnB,QAAA,MAAA,CAAO,EAAA,CAAG,MAAS,CAAC,CAAA;AAAA,MACxB;AAAA,IACJ,CAAC,CAAA;AAED,IAAA,IAAI,IAAA,CAAK,OAAO,kBAAA,EAAoB;AAChC,MAAA,IAAA,CAAK,qBAAqB,MAAM,CAAA;AAAA,IACpC;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,MAAA,EAA8C;AACvE,IAAA,MAAM,MAAA,GAAS,CAAC,EAAE,IAAA,EAAK,KAAoE;AACvF,MAAA,IAAI,IAAA,CAAK,MAAA,CAAO,kBAAA,GAAqB,IAAI,CAAA,EAAG;AACxC,QAAA,IAAA,CAAK,cAAA,CAAe,QAAQ,MAAM,CAAA;AAClC,QAAA,IAAA,CAAK,QAAQ,YAAA,CAAa,OAAA;AAC1B,QAAA,IAAA,CAAK,KAAK,SAAS,CAAA;AACnB,QAAA,MAAA,CAAO,EAAA,CAAG,MAAS,CAAC,CAAA;AAAA,MACxB;AAAA,IACJ,CAAA;AACA,IAAA,IAAA,CAAK,EAAA,CAAG,QAAQ,MAAM,CAAA;AAAA,EAC1B;AAAA,EAEQ,UAAA,CAAW,QAAoB,KAAA,EAA8B;AACjE,IAAA,IAAI,WAAW,QAAA,EAAU;AACrB,MAAA,IAAA,CAAK,YAAA,IAAgB,OAAO,KAAK,CAAA;AAAA,IACrC,CAAA,MAAO;AACH,MAAA,IAAA,CAAK,YAAA,IAAgB,OAAO,KAAK,CAAA;AAAA,IACrC;AAEA,IAAA,IAAI,KAAK,YAAA,CAAa,MAAA,GAAS,IAAA,CAAK,YAAA,CAAa,SAAS,gBAAA,EAAkB;AACxE,MAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,EAAE,KAAA,EAAO,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,gBAAgB,CAAA,MAAA,CAAQ,CAAA,EAAG,KAAA,EAAO,IAAA,EAAM,CAAA;AACzG,MAAA,IAAA,CAAK,SAAA,EAAU;AACf,MAAA;AAAA,IACJ;AAEA,IAAA,IAAA,CAAK,YAAA,CAAa,MAAA,EAAQ,MAAA,KAAW,QAAA,GAAW,iBAAiB,cAAc,CAAA;AAAA,EACnF;AAAA,EAEQ,YAAA,CAAa,QAAoB,SAAA,EAAkD;AAEvF,IAAA,IAAA,CAAK,SAAS,CAAA,GAAI,IAAA,CAAK,SAAS,CAAA,CAAE,OAAA,CAAQ,aAAa,IAAI,CAAA;AAE3D,IAAA,IAAI,UAAA,GAAa,IAAA,CAAK,SAAS,CAAA,CAAE,QAAQ,IAAI,CAAA;AAG7C,IAAA,OAAO,eAAe,EAAA,EAAI;AACtB,MAAA,MAAM,OAAA,GAAU,KAAK,SAAS,CAAA;AAC9B,MAAA,MAAM,IAAA,GAAO,QAAQ,SAAA,CAAU,CAAA,EAAG,UAAU,CAAA,CAAE,OAAA,CAAQ,OAAO,EAAE,CAAA;AAC/D,MAAA,IAAA,CAAK,SAAS,CAAA,GAAI,OAAA,CAAQ,SAAA,CAAU,aAAa,CAAC,CAAA;AAClD,MAAA,IAAA,CAAK,KAAK,MAAA,EAAQ,EAAE,MAAA,EAAQ,IAAA,EAAM,MAAM,CAAA;AACxC,MAAA,UAAA,GAAa,IAAA,CAAK,SAAS,CAAA,CAAE,OAAA,CAAQ,IAAI,CAAA;AAAA,IAC7C;AAAA,EACJ;AACJ;ACzQA,IAAM,UAAA,GAAN,cAAyBA,YAAAA,CAAiC;AAAA,EAItD,WAAA,GAAc;AACV,IAAA,KAAA,EAAM;AAJV,IAAA,aAAA,CAAA,IAAA,EAAiB,YAA2B,EAAC,CAAA;AAC7C,IAAA,aAAA,CAAA,IAAA,EAAQ,aAAA,EAAiC,IAAA,CAAA;AAOrC,IAAA,IAAA,CAAK,gBAAgB,CAAC,CAAA;AAGtB,IAAA,IAAA,CAAK,EAAA,CAAG,SAAS,MAAM;AAAA,IAAC,CAAC,CAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,OAAA,EAAqC;AAC5C,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAA,IAAU,kBAAA,EAAoB;AAC5C,MAAA,OAAO,IAAI,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,kBAAkB,YAAY,CAAC,CAAA;AAAA,IACnF;AACA,IAAA,IAAA,CAAK,QAAA,CAAS,KAAK,OAAO,CAAA;AAC1B,IAAA,OAAO,GAAG,MAAS,CAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,KAAK,IAAA,EAAoB;AAErB,IAAA,IAAI,IAAA,CAAK,gBAAgB,IAAA,EAAM;AAC3B,MAAA,IAAA,CAAK,YAAY,IAAI,CAAA;AACrB,MAAA;AAAA,IACJ;AAGA,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,QAAA,CAAS,QAAQ,CAAA,EAAA,EAAK;AAC3C,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,QAAA,CAAS,CAAC,CAAA;AAE/B,MAAA,IAAI,YAAY,MAAA,EAAW;AAE3B,MAAA,IAAI,QAAQ,SAAA,EAAW;AACnB,QAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,SAAA,CAAU,MAAA,CAAO,KAAK,IAAI,CAAA;AACtD,QAAA,IAAI,WAAA,EAAa;AACb,UAAA,IAAA,CAAK,UAAA,CAAW,SAAS,IAAI,CAAA;AAC7B,UAAA;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAGA,IAAA,IAAA,CAAK,gBAAgB,IAAI,CAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU,KAAA,EAAgC;AACtC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACnC,MAAA,MAAM,IAAA,GAAO,MAAM,CAAC,CAAA;AACpB,MAAA,IAAI,SAAS,MAAA,EAAW;AACpB,QAAA,IAAA,CAAK,KAAK,IAAI,CAAA;AAAA,MAClB;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,GAAc;AACV,IAAA,IAAI,IAAA,CAAK,gBAAgB,IAAA,EAAM;AAC3B,MAAA,YAAA,CAAa,IAAA,CAAK,YAAY,KAAK,CAAA;AACnC,MAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAAA,IACvB;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,CAAC,MAAA,CAAO,OAAO,CAAA,GAAU;AACrB,IAAA,IAAA,CAAK,KAAA,EAAM;AACX,IAAA,IAAA,CAAK,kBAAA,EAAmB;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAMQ,gBAAgB,IAAA,EAAoB;AACxC,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,QAAA,CAAS,QAAQ,CAAA,EAAA,EAAK;AAC3C,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,QAAA,CAAS,CAAC,CAAA;AAE/B,MAAA,IAAI,YAAY,MAAA,EAAW;AAG3B,MAAA,IAAI,QAAQ,SAAA,EAAW;AAEvB,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAA;AACvC,MAAA,IAAI,KAAA,EAAO;AACP,QAAA,IAAI;AACA,UAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,SAAA,CAAU,KAAK,CAAA;AACpC,UAAA,IAAA,CAAK,KAAK,OAAA,EAAS,EAAE,OAAO,OAAA,CAAQ,KAAA,EAAO,MAAM,CAAA;AAAA,QACrD,SAAS,MAAA,EAAiB;AACtB,UAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAASC,MAAAA,CAAO,MAAM,CAAC,CAAA;AAAA,QACrC;AACA,QAAA;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAAA,EAEQ,UAAA,CAAW,SAAuB,UAAA,EAA0B;AAEhE,IAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,SAAA,EAAW,SAAA,IAAa,wBAAA;AAElD,IAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC3B,MAAA,IAAI,IAAA,CAAK,gBAAgB,IAAA,EAAM;AAC3B,QAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,IAAA,CAAK,YAAY,KAAK,CAAA;AACxC,QAAA,MAAM,GAAA,GAAM,IAAA,CAAK,WAAA,CAAY,OAAA,CAAQ,KAAA;AACrC,QAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AACnB,QAAA,IAAA,CAAK,KAAK,cAAA,EAAgB,EAAE,KAAA,EAAO,GAAA,EAAK,OAAO,CAAA;AAAA,MACnD;AAAA,IACJ,GAAG,SAAS,CAAA;AAEZ,IAAA,IAAA,CAAK,WAAA,GAAc;AAAA,MACf,OAAA;AAAA,MACA,KAAA,EAAO,CAAC,UAAU,CAAA;AAAA,MAClB;AAAA,KACJ;AAAA,EACJ;AAAA,EAEQ,YAAY,IAAA,EAAoB;AAEpC,IAAA,IAAI,IAAA,CAAK,gBAAgB,IAAA,EAAM;AAE/B,IAAA,MAAM,EAAE,OAAA,EAAS,KAAA,EAAO,KAAA,KAAU,IAAA,CAAK,WAAA;AAEvC,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,SAAA,EAAW,QAAA,IAAY,eAAA;AAEhD,IAAA,KAAA,CAAM,KAAK,IAAI,CAAA;AAGf,IAAA,IAAI,OAAA,CAAQ,SAAA,EAAW,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,EAAG;AACtC,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,MAAM,SAAA,GAAY,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AACjC,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,OAAA,CAAQ,IAAA,CAAK,SAAS,CAAA;AAC5C,MAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAEnB,MAAA,IAAI,KAAA,EAAO;AACP,QAAA,IAAI;AACA,UAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,SAAA,CAAU,KAAK,CAAA;AACpC,UAAA,IAAA,CAAK,KAAK,OAAA,EAAS,EAAE,OAAO,OAAA,CAAQ,KAAA,EAAO,MAAM,CAAA;AAAA,QACrD,SAAS,MAAA,EAAiB;AACtB,UAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAASA,MAAAA,CAAO,MAAM,CAAC,CAAA;AAAA,QACrC;AAAA,MACJ;AACA,MAAA;AAAA,IACJ;AAGA,IAAA,IAAI,KAAA,CAAM,UAAU,QAAA,EAAU;AAC1B,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,MAAM,MAAM,OAAA,CAAQ,KAAA;AACpB,MAAA,MAAM,WAAA,GAAc,CAAC,GAAG,KAAK,CAAA;AAC7B,MAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AACnB,MAAA,IAAA,CAAK,KAAK,cAAA,EAAgB,EAAE,OAAO,GAAA,EAAK,KAAA,EAAO,aAAa,CAAA;AAAA,IAChE;AAAA,EACJ;AACJ;;;ACnOA,IAAM,iBAAA,GAAoB,qCAAA;AAG1B,IAAM,gBAAA,GAAmB,yBAAA;AAUzB,IAAM,WAAA,GAAc,qBAAA;AAmBpB,IAAM,cAAA,GAAiB,EAAA;AAsCvB,IAAM,sBAAA,GAAyB,4BAAA;AAK/B,SAAS,eAAe,KAAA,EAAwB;AAC5C,EAAA,OAAO,gBAAA,CAAiB,KAAK,KAAK,CAAA;AACtC;AAQA,SAAS,WAAW,CAAA,EAAoB;AACpC,EAAA,OAAO,CAAC,sBAAA,CAAuB,IAAA,CAAK,CAAC,CAAA;AACzC;;;AClFA,IAAI,UAAA;AAEJ,IAAM,SAAA,GAAY,QAAQ,QAAA,KAAa,OAAA;AAQvC,SAAS,WAAW,IAAA,EAAsB;AAEtC,EAAA,OAAO,SAAA,GAAY,CAAA,EAAG,IAAI,CAAA,IAAA,CAAA,GAAS,IAAA;AACvC;AAQA,SAAS,oBAAoB,GAAA,EAAsB;AAC/C,EAAA,KAAA,MAAW,OAAO,iBAAA,EAAmB;AACjC,IAAA,IAAI,CAAC,WAAW,IAAA,CAAK,GAAA,EAAK,WAAW,GAAG,CAAC,CAAC,CAAA,EAAG;AACzC,MAAA,OAAO,KAAA;AAAA,IACX;AAAA,EACJ;AACA,EAAA,OAAO,IAAA;AACX;AAQA,SAAS,kBAAkB,IAAA,EAAkC;AACzD,EAAA,IAAI;AAEA,IAAA,MAAM,GAAA,GAAM,YAAY,CAAA,MAAA,EAAS,UAAA,CAAW,IAAI,CAAC,CAAA,CAAA,GAAK,SAAS,IAAI,CAAA,CAAA;AACnE,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,GAAA,EAAK,EAAE,QAAA,EAAU,OAAA,EAAS,OAAA,EAAS,GAAA,EAAO,WAAA,EAAa,IAAA,EAAM,CAAA,CAAE,IAAA,EAAK;AAC5F,IAAA,MAAM,YAAY,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,CAAE,CAAC,GAAG,IAAA,EAAK;AAC9C,IAAA,IAAI,SAAA,EAAW;AAEX,MAAA,MAAM,OAAA,GAAU,SAAA,CAAU,WAAA,CAAY,SAAA,GAAY,OAAO,GAAG,CAAA;AAC5D,MAAA,IAAI,WAAW,CAAA,EAAG;AACd,QAAA,OAAO,SAAA,CAAU,SAAA,CAAU,CAAA,EAAG,OAAO,CAAA;AAAA,MACzC;AAAA,IACJ;AAAA,EACJ,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,OAAO,MAAA;AACX;AAOA,SAAS,aAAA,GAA4C;AACjD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,YAAY,CAAA;AACxC,EAAA,IAAI,OAAA,KAAY,MAAA,IAAa,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG;AAC/C,IAAA,OAAO,MAAA;AAAA,EACX;AACA,EAAA,IAAI,CAAC,UAAA,CAAW,OAAO,CAAA,EAAG;AACtB,IAAA,OAAO,IAAI,IAAI,KAAA,CAAM,CAAA,YAAA,EAAe,OAAO,qCAAqC,CAAC,CAAA;AAAA,EACrF;AACA,EAAA,IAAI,mBAAA,CAAoB,OAAO,CAAA,EAAG;AAC9B,IAAA,OAAO,GAAG,OAAO,CAAA;AAAA,EACrB;AACA,EAAA,OAAO,IAAI,IAAI,KAAA,CAAM,CAAA,YAAA,EAAe,OAAO,4CAA4C,CAAC,CAAA;AAC5F;AAOA,SAAS,gBAAA,GAAuC;AAE5C,EAAA,MAAM,WAAA,GAAc,YAAY,oBAAA,GAAuB,iBAAA;AACvD,EAAA,KAAA,MAAW,aAAa,WAAA,EAAa;AACjC,IAAA,IAAI,mBAAA,CAAoB,SAAS,CAAA,EAAG;AAChC,MAAA,OAAO,SAAA;AAAA,IACX;AAAA,EACJ;AACA,EAAA,OAAO,MAAA;AACX;AAOA,SAAS,gBAAA,GAAuC;AAE5C,EAAA,MAAM,SAAA,GAAY,iBAAA,CAAkB,iBAAA,CAAkB,CAAC,KAAK,UAAU,CAAA;AACtE,EAAA,IAAI,SAAA,KAAc,MAAA,IAAa,mBAAA,CAAoB,SAAS,CAAA,EAAG;AAC3D,IAAA,OAAO,SAAA;AAAA,EACX;AACA,EAAA,OAAO,MAAA;AACX;AAmCA,SAAS,cAAc,OAAA,EAAgD;AACnE,EAAA,IAAI,UAAA,KAAe,MAAA,IAAa,IAAU,EAAS;AAC/C,IAAA,OAAO,GAAG,UAAU,CAAA;AAAA,EACxB;AAEA,EAAA,MAAM,YAAY,aAAA,EAAc;AAChC,EAAA,IAAI,cAAc,MAAA,EAAW;AACzB,IAAA,IAAI,UAAU,EAAA,EAAI;AACd,MAAA,UAAA,GAAa,SAAA,CAAU,KAAA;AAAA,IAC3B;AACA,IAAA,OAAO,SAAA;AAAA,EACX;AAEA,EAAA,MAAM,YAAY,gBAAA,EAAiB;AACnC,EAAA,IAAI,cAAc,MAAA,EAAW;AACzB,IAAA,UAAA,GAAa,SAAA;AACb,IAAA,OAAO,GAAG,SAAS,CAAA;AAAA,EACvB;AAEA,EAAA,MAAM,aAAa,gBAAA,EAAiB;AACpC,EAAA,IAAI,eAAe,MAAA,EAAW;AAC1B,IAAA,UAAA,GAAa,UAAA;AACb,IAAA,OAAO,GAAG,UAAU,CAAA;AAAA,EACxB;AAEA,EAAA,OAAO,GAAA;AAAA,IACH,IAAI,KAAA;AAAA,MACA;AAAA;AAIJ,GACJ;AACJ;;;AChLA,IAAMC,UAAAA,GAAY,QAAQ,QAAA,KAAa,OAAA;AAQvC,SAAS,cAAc,QAAA,EAAkC;AACrD,EAAA,MAAM,aAAa,aAAA,EAAc;AACjC,EAAA,IAAI,CAAC,WAAW,EAAA,EAAI;AAChB,IAAA,OAAO,GAAA,CAAI,WAAW,KAAK,CAAA;AAAA,EAC/B;AAEA,EAAA,MAAMC,WAAAA,GAAaD,UAAAA,GAAY,CAAA,EAAG,QAAQ,CAAA,IAAA,CAAA,GAAS,QAAA;AACnD,EAAA,OAAO,EAAA,CAAGE,IAAAA,CAAK,UAAA,CAAW,KAAA,EAAOD,WAAU,CAAC,CAAA;AAChD;;;ACnBA,IAAM,eAAA,GAAkB,GAAA;AAGxB,IAAM,iBAAA,GAAoB,GAAA;AAS1B,SAAS,QAAA,CAAS,OAAe,SAAA,EAA2B;AACxD,EAAA,IAAI,KAAA,CAAM,UAAU,SAAA,EAAW;AAC3B,IAAA,OAAO,KAAA;AAAA,EACX;AACA,EAAA,OAAO,CAAA,EAAG,KAAA,CAAM,SAAA,CAAU,CAAA,EAAG,SAAS,CAAC,CAAA,GAAA,CAAA;AAC3C;AAQA,IAAM,kBAAA,GAAN,cAAiC,KAAA,CAAM;AAAA,EAKnC,WAAA,CAAY,SAAiB,OAAA,EAA0F;AACnH,IAAA,KAAA,CAAM,OAAO,CAAA;AALjB,IAAA,aAAA,CAAA,IAAA,EAAS,QAAA,CAAA;AACT,IAAA,aAAA,CAAA,IAAA,EAAS,QAAA,CAAA;AACT,IAAA,aAAA,CAAA,IAAA,EAAS,UAAA,CAAA;AAIL,IAAA,IAAA,CAAK,IAAA,GAAO,oBAAA;AACZ,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AACtB,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AACtB,IAAA,IAAA,CAAK,WAAW,OAAA,CAAQ,QAAA;AAAA,EAC5B;AACJ,CAAA;AAiBA,SAAS,gBAAgB,QAAA,EAAkB,IAAA,EAAyB,QAAA,EAAkBF,OAAAA,EAAgB,SAAiB,EAAA,EAAwB;AAC3I,EAAA,MAAM,UAAU,QAAA,CAAS,IAAA,CAAK,IAAA,CAAK,GAAG,GAAG,eAAe,CAAA;AACxD,EAAA,MAAM,SAAA,GAAY,QAAA,CAASA,OAAAA,CAAO,IAAA,IAAQ,iBAAiB,CAAA;AAC3D,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,EAAG,QAAQ,sBAAsB,MAAA,CAAO,QAAQ,CAAC,CAAA,CAAA,CAAG,CAAA;AACnE,EAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACpB,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,MAAA,EAAS,OAAO,CAAA,CAAE,CAAA;AAAA,EACjC;AACA,EAAA,IAAI,SAAA,CAAU,SAAS,CAAA,EAAG;AACtB,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,QAAA,EAAW,SAAS,CAAA,CAAE,CAAA;AAAA,EACrC;AACA,EAAA,OAAO,IAAI,kBAAA,CAAmB,KAAA,CAAM,IAAA,CAAK,KAAK,CAAA,EAAG,EAAE,MAAA,EAAQ,MAAA,EAAAA,OAAAA,EAAQ,QAAA,EAAU,CAAA;AACjF;AAYA,SAAS,qBAAA,CACL,UACA,QAAA,EACK;AACL,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AAC7C,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA;AAE/B,IAAA,IAAI,UAAU,MAAA,EAAW;AACzB,IAAA,MAAMI,KAAAA,GAAO,KAAA,CAAM,IAAA,CAAK,MAAA,GAAS,CAAA,GAAI,KAAA,CAAM,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,GAAI,QAAA;AACxE,IAAA,KAAA,CAAM,KAAK,CAAA,EAAGA,KAAI,CAAA,EAAA,EAAK,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AAAA,EAC1C;AACA,EAAA,MAAM,SAAS,KAAA,CAAM,MAAA,GAAS,IAAI,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA,GAAI,0BAAA;AACrD,EAAA,OAAO,IAAI,KAAA,CAAM,CAAA,EAAG,QAAQ,CAAA,yBAAA,EAAuB,MAAM,CAAA,CAAE,CAAA;AAC/D;;;ACtFA,IAAM,YAAA,GAAe;AAAA,EACjB,SAAA,EAAW,WAAA;AAAA,EACX,oBAAA,EAAsB,sBAAA;AAAA,EACtB,wBAAA,EAA0B,0BAAA;AAAA,EAC1B,eAAA,EAAiB,iBAAA;AAAA,EACjB,WAAA,EAAa,aAAA;AAAA,EACb,mBAAA,EAAqB,qBAAA;AAAA,EACrB,mBAAA,EAAqB,qBAAA;AAAA,EACrB,YAAA,EAAc,cAAA;AAAA,EACd,qBAAA,EAAuB,uBAAA;AAAA,EACvB,oBAAA,EAAsB,sBAAA;AAAA;AAAA,EAEtB,aAAA,EAAe,eAAA;AAAA;AAAA,EAEf,oBAAA,EAAsB;AAC1B;AAiEA,IAAM,gBAAA,GAA4C;AAAA,EAC9C;AAAA,IACI,OAAO,YAAA,CAAa,SAAA;AAAA,IACpB,OAAA,EAAS,YAAA;AAAA,IACT,WAAW,MAAM;AAAA,GACrB;AAAA,EACA;AAAA,IACI,OAAO,YAAA,CAAa,oBAAA;AAAA,IACpB,OAAA,EAAS,0DAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAoC;AAAA,MAC5C,MAAA,EAAQ,KAAA,CAAM,CAAC,CAAA,IAAK,EAAA;AAAA,MACpB,SAAA,EAAW,KAAA,CAAM,CAAC,CAAA,IAAK,EAAA;AAAA,MACvB,QAAA,EAAU,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KAC1B;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,YAAA,CAAa,wBAAA;AAAA,IACpB,OAAA,EAAS,oDAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAwC;AAAA,MAChD,UAAA,EAAY,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC;AAAA,KAC/B;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,YAAA,CAAa,eAAA;AAAA,IACpB,OAAA,EAAS,yBAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA8B;AAAA,MACtC,GAAA,EAAK,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACrB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,YAAA,CAAa,WAAA;AAAA,IACpB,OAAA,EAAS,oDAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA2B;AAAA,MACnC,QAAA,EAAA,CAAW,KAAA,CAAM,CAAC,CAAA,IAAK,IAAI,IAAA;AAAK,KACpC;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,YAAA,CAAa,mBAAA;AAAA,IACpB,OAAA,EAAS,sBAAA;AAAA,IACT,WAAW,MAAM;AAAA,GACrB;AAAA,EACA;AAAA,IACI,OAAO,YAAA,CAAa,mBAAA;AAAA,IACpB,OAAA,EAAS,6BAAA;AAAA,IACT,WAAW,MAAM;AAAA,GACrB;AAAA,EACA;AAAA,IACI,OAAO,YAAA,CAAa,YAAA;AAAA,IACpB,OAAA,EAAS,yBAAA;AAAA,IACT,WAAW,MAAM;AAAA,GACrB;AAAA,EACA;AAAA,IACI,OAAO,YAAA,CAAa,qBAAA;AAAA,IACpB,OAAA,EAAS,2CAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAoC;AAAA,MAC5C,OAAA,EAAS,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACzB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,YAAA,CAAa,oBAAA;AAAA,IACpB,OAAA,EAAS,4CAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAoC;AAAA,MAC5C,MAAA,EAAQ,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACxB;AAAA;AAER;AAGA,IAAM,uCAA4C,IAAI,GAAA,CAAI,CAAC,YAAA,CAAa,qBAAqB,CAAC;;;AC3F9F,IAAM,qBAAN,MAAyB;AAAA,EAAzB,WAAA,GAAA;AACI,IAAA,aAAA,CAAA,IAAA,EAAQ,aAAA,CAAA;AACR,IAAA,aAAA,CAAA,IAAA,EAAQ,SAAA,EAAU,CAAA,CAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWlB,iBAAiB,IAAA,EAAkG;AAC/G,IAAA,IAAA,CAAK,OAAA,EAAA;AACL,IAAA,MAAM,aAAA,GAAgB,CAAA,MAAA,EAAS,MAAA,CAAO,IAAA,CAAK,OAAO,CAAC,CAAA,CAAA;AACnD,IAAA,IAAA,CAAK,WAAA,GAAc;AAAA,MACf,aAAA;AAAA,MACA,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,MACpB,OAAO;AAAC,KACZ;AACA,IAAA,OAAO,aAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,UAAU,QAAA,EAA+B;AACrC,IAAA,IAAI,IAAA,CAAK,gBAAgB,MAAA,EAAW;AAChC,MAAA,OAAO;AAAA,QACH,QAAA;AAAA,QACA,aAAA,EAAe,EAAA;AAAA,QACf,SAAA,EAAW,EAAA;AAAA,QACX,QAAA,EAAU,EAAA;AAAA,QACV,MAAA,EAAQ;AAAA,OACZ;AAAA,IACJ;AACA,IAAA,IAAA,CAAK,WAAA,CAAY,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA;AACpC,IAAA,OAAO;AAAA,MACH,QAAA;AAAA,MACA,aAAA,EAAe,KAAK,WAAA,CAAY,aAAA;AAAA,MAChC,SAAA,EAAW,KAAK,WAAA,CAAY,SAAA;AAAA,MAC5B,QAAA,EAAU,KAAK,WAAA,CAAY,QAAA;AAAA,MAC3B,MAAA,EAAQ,KAAK,WAAA,CAAY;AAAA,KAC7B;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,MAAA,EAA6D;AACxE,IAAA,IAAI,IAAA,CAAK,WAAA,KAAgB,MAAA,EAAW,OAAO,MAAA;AAE3C,IAAA,MAAM,OAAA,GAA8B;AAAA,MAChC,aAAA,EAAe,KAAK,WAAA,CAAY,aAAA;AAAA,MAChC,SAAA,EAAW,KAAK,WAAA,CAAY,SAAA;AAAA,MAC5B,QAAA,EAAU,KAAK,WAAA,CAAY,QAAA;AAAA,MAC3B,MAAA,EAAQ,KAAK,WAAA,CAAY,MAAA;AAAA,MACzB,KAAA,EAAO,CAAC,GAAG,IAAA,CAAK,YAAY,KAAK,CAAA;AAAA,MACjC,UAAA,EAAY,IAAA,CAAK,GAAA,EAAI,GAAI,KAAK,WAAA,CAAY,SAAA;AAAA,MAC1C,SAAA,EAAW;AAAA,KACf;AAEA,IAAA,IAAA,CAAK,WAAA,GAAc,MAAA;AACnB,IAAA,OAAO,OAAA;AAAA,EACX;AAAA;AAAA,EAGA,IAAI,OAAA,GAA0C;AAC1C,IAAA,OAAO,IAAA,CAAK,WAAA;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,QAAA,GAAoB;AACpB,IAAA,OAAO,KAAK,WAAA,KAAgB,MAAA;AAAA,EAChC;AAAA;AAAA,EAGA,KAAA,GAAc;AACV,IAAA,IAAA,CAAK,WAAA,GAAc,MAAA;AAAA,EACvB;AACJ;;;AC5GA,IAAM,gBAAA,GAAmB;AAAA,EACrB,IAAA,EAAM,MAAA;AAAA,EACN,WAAA,EAAa;AACjB;AAKA,IAAM,YAAA,GAAe;AAAA,EACjB,OAAA,EAAS,SAAA;AAAA,EACT,MAAA,EAAQ,QAAA;AAAA,EACR,YAAA,EAAc,cAAA;AAAA,EACd,WAAA,EAAa;AACjB;AAKA,IAAM,WAAA,GAAc;AAAA,EAChB,MAAA,EAAQ,QAAA;AAAA,EACR,cAAA,EAAgB,gBAAA;AAAA,EAChB,MAAA,EAAQ;AACZ;AAsCA,IAAM,oBAAA,GAAuB,EACxB,MAAA,CAAO;AAAA,EACJ,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA;AAAA,EACvC,SAAS,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,EAAE,CAAA,CAAE,OAAO,cAAA,EAAgB,EAAE,SAAS,sCAAA,EAAwC,EAAE,QAAA,EAAS;AAAA,EACxH,eAAA,EAAiB,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,MAAA,CAAO,UAAA,EAAY,EAAE,OAAA,EAAS,4CAAA,EAA8C,EAAE,QAAA,EAAS;AAAA,EAC1H,UAAA,EAAY,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,MAAA,CAAO,UAAA,EAAY,EAAE,OAAA,EAAS,uCAAA,EAAyC,EAAE,QAAA,EAAS;AAAA,EAChH,eAAe,CAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EAC1C,YAAA,EAAc,EAAE,IAAA,CAAK,CAAC,QAAQ,aAAa,CAAC,EAAE,QAAA,EAAS;AAAA,EACvD,YAAA,EAAc,CAAA,CAAE,IAAA,CAAK,CAAC,SAAA,EAAW,UAAU,cAAA,EAAgB,aAAa,CAAC,CAAA,CAAE,QAAA,EAAS;AAAA,EACpF,mBAAmB,CAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EAC9C,WAAA,EAAa,EAAE,IAAA,CAAK,CAAC,UAAU,gBAAA,EAAkB,QAAQ,CAAC,CAAA,CAAE,QAAA,EAAS;AAAA,EACrE,WAAA,EAAa,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EAClD,YAAA,EAAc,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACnD,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI,CAAE,GAAA,CAAI,IAAI,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA,CAAE,QAAA,EAAS;AAAA,EACxD,cAAA,EAAgB,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACrD,cAAA,EAAgB,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACrD,MAAA,EAAQ,CAAA,CAAE,UAAA,CAAW,WAAW,EAAE,QAAA;AACtC,CAAC,EACA,MAAA,EAAO;AAOZ,SAAS,UAAU,OAAA,EAAmC;AAClD,EAAA,MAAM,IAAA,GAAiB,CAAC,WAAW,CAAA;AAEnC,EAAA,IAAI,OAAA,CAAQ,YAAY,MAAA,EAAW;AAC/B,IAAA,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,OAAA,CAAQ,OAAO,CAAA;AAAA,EAC1C;AACA,EAAA,IAAI,OAAA,CAAQ,oBAAoB,MAAA,EAAW;AACvC,IAAA,IAAA,CAAK,IAAA,CAAK,oBAAA,EAAsB,OAAA,CAAQ,eAAe,CAAA;AAAA,EAC3D;AACA,EAAA,IAAI,OAAA,CAAQ,UAAA,KAAe,MAAA,IAAa,OAAA,CAAQ,kBAAkB,MAAA,EAAW;AACzE,IAAA,IAAA,CAAK,IAAA,CAAK,eAAA,EAAiB,OAAA,CAAQ,UAAA,EAAY,QAAQ,aAAa,CAAA;AAAA,EACxE;AAEA,EAAA,eAAA,CAAgB,MAAM,OAAO,CAAA;AAC7B,EAAA,cAAA,CAAe,MAAM,OAAO,CAAA;AAC5B,EAAA,cAAA,CAAe,MAAM,OAAO,CAAA;AAE5B,EAAA,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAC,CAAA;AAC9B,EAAA,OAAO,IAAA;AACX;AAGA,SAAS,eAAA,CAAgB,MAAgB,OAAA,EAA+B;AACpE,EAAA,IAAI,OAAA,CAAQ,iBAAiB,aAAA,EAAe;AACxC,IAAA,IAAA,CAAK,KAAK,wBAAwB,CAAA;AAAA,EACtC;AACA,EAAA,IAAI,OAAA,CAAQ,iBAAiB,QAAA,EAAU;AACnC,IAAA,IAAA,CAAK,KAAK,oBAAoB,CAAA;AAAA,EAClC,CAAA,MAAA,IAAW,OAAA,CAAQ,YAAA,KAAiB,cAAA,EAAgB;AAChD,IAAA,IAAA,CAAK,KAAK,0BAA0B,CAAA;AAAA,EACxC,CAAA,MAAA,IAAW,OAAA,CAAQ,YAAA,KAAiB,aAAA,EAAe;AAC/C,IAAA,IAAA,CAAK,KAAK,yBAAyB,CAAA;AAAA,EACvC;AACA,EAAA,IAAI,OAAA,CAAQ,sBAAsB,MAAA,EAAW;AACzC,IAAA,IAAA,CAAK,IAAA,CAAK,sBAAA,EAAwB,OAAA,CAAQ,iBAAiB,CAAA;AAAA,EAC/D;AACJ;AAGA,SAAS,cAAA,CAAe,MAAgB,OAAA,EAA+B;AACnE,EAAA,IAAI,OAAA,CAAQ,gBAAgB,gBAAA,EAAkB;AAC1C,IAAA,IAAA,CAAK,KAAK,kBAAkB,CAAA;AAAA,EAChC,CAAA,MAAA,IAAW,OAAA,CAAQ,WAAA,KAAgB,QAAA,EAAU;AACzC,IAAA,IAAA,CAAK,KAAK,UAAU,CAAA;AAAA,EACxB;AACJ;AAGA,SAAS,cAAA,CAAe,MAAgB,OAAA,EAA+B;AACnE,EAAA,IAAI,OAAA,CAAQ,gBAAgB,MAAA,EAAW;AACnC,IAAA,IAAA,CAAK,IAAA,CAAK,gBAAA,EAAkB,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAC,CAAA;AAAA,EAC3D;AACA,EAAA,IAAI,OAAA,CAAQ,iBAAiB,MAAA,EAAW;AACpC,IAAA,IAAA,CAAK,IAAA,CAAK,iBAAA,EAAmB,MAAA,CAAO,OAAA,CAAQ,YAAY,CAAC,CAAA;AAAA,EAC7D;AACA,EAAA,IAAI,OAAA,CAAQ,WAAW,MAAA,EAAW;AAC9B,IAAA,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,EACjD;AACJ;AAyBA,IAAM,OAAA,GAAN,MAAM,QAAA,SAAgB,YAAA,CAAa;AAAA,EAMvB,WAAA,CAAY,MAAA,EAA4BC,OAAAA,EAAoB,MAAA,EAAsB;AACtF,IAAA,KAAA,CAAM,MAAM,CAAA;AANhB,IAAA,aAAA,CAAA,IAAA,EAAiB,QAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAiB,SAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAQ,aAAA,CAAA;AACR,IAAA,aAAA,CAAA,IAAA,EAAQ,cAAA,CAAA;AAIJ,IAAA,IAAA,CAAK,MAAA,GAASA,OAAAA;AACd,IAAA,IAAA,CAAK,OAAA,GAAU,IAAI,kBAAA,EAAmB;AACtC,IAAA,IAAA,CAAK,UAAA,EAAW;AAChB,IAAA,IAAA,CAAK,WAAA,EAAY;AACjB,IAAA,IAAI,WAAW,MAAA,EAAW;AACtB,MAAA,IAAA,CAAK,gBAAgB,MAAM,CAAA;AAAA,IAC/B;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,CAAC,MAAA,CAAO,OAAO,CAAA,GAAU;AACrB,IAAA,IAAI,IAAA,CAAK,WAAA,KAAgB,MAAA,IAAa,IAAA,CAAK,iBAAiB,MAAA,EAAW;AACnE,MAAA,IAAA,CAAK,WAAA,CAAY,mBAAA,CAAoB,OAAA,EAAS,IAAA,CAAK,YAAY,CAAA;AAAA,IACnE;AACA,IAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA,EAAE;AAC5B,IAAA,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,EAAE;AAAA,EAC1B;AAAA,EAEA,OAAA,CAAyC,OAAU,QAAA,EAAuD;AACtG,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,KAAA,EAAiB,QAAiB,CAAA;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,sBAAsB,QAAA,EAA4E;AAC9F,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,sBAAA,EAAwB,QAAQ,CAAA;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,QAAA,EAAmE;AAC5E,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,aAAA,EAAe,QAAQ,CAAA;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,QAAA,EAAqE;AAChF,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,eAAA,EAAiB,QAAQ,CAAA;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,sBAAsB,QAAA,EAA4E;AAC9F,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,sBAAA,EAAwB,QAAQ,CAAA;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OAAO,OAAA,EAA0C;AACpD,IAAA,MAAM,UAAA,GAAa,oBAAA,CAAqB,SAAA,CAAU,OAAO,CAAA;AACzD,IAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACrB,MAAA,OAAO,GAAA,CAAI,qBAAA,CAAsB,SAAA,EAAW,UAAA,CAAW,KAAK,CAAC,CAAA;AAAA,IACjE;AAEA,IAAA,MAAM,YAAA,GAAe,cAAc,SAAS,CAAA;AAC5C,IAAA,IAAI,CAAC,aAAa,EAAA,EAAI;AAClB,MAAA,OAAO,GAAA,CAAI,aAAa,KAAK,CAAA;AAAA,IACjC;AAEA,IAAA,MAAM,IAAA,GAAO,UAAU,OAAO,CAAA;AAC9B,IAAA,MAAMA,OAAAA,GAAS,IAAI,UAAA,EAAW;AAC9B,IAAA,KAAA,MAAW,WAAW,gBAAA,EAAkB;AACpC,MAAA,MAAM,SAAA,GAAYA,OAAAA,CAAO,UAAA,CAAW,OAAO,CAAA;AAC3C,MAAA,IAAI,CAAC,UAAU,EAAA,EAAI;AACf,QAAA,OAAO,GAAA,CAAI,UAAU,KAAK,CAAA;AAAA,MAC9B;AAAA,IACJ;AAEA,IAAA,MAAM,MAAA,GAA6B;AAAA,MAC/B,QAAQ,YAAA,CAAa,KAAA;AAAA,MACrB,IAAA;AAAA,MACA,gBAAgB,OAAA,CAAQ,cAAA;AAAA,MACxB,gBAAgB,OAAA,CAAQ,cAAA;AAAA,MACxB,kBAAA,EAAoB,CAAA,IAAA,KAAQ,YAAA,CAAa,IAAA,CAAK,IAAI;AAAA,KACtD;AAEA,IAAA,OAAO,GAAG,IAAI,QAAA,CAAQ,QAAQA,OAAAA,EAAQ,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,EACzD;AAAA;AAAA,EAGQ,UAAA,GAAmB;AACvB,IAAA,IAAA,CAAK,EAAA,CAAG,MAAA,EAAQ,CAAC,EAAE,MAAK,KAAM;AAC1B,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,IAAI,CAAA;AAAA,IACzB,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,OAAO,EAAA,CAAG,OAAA,EAAS,CAAC,EAAE,KAAA,EAAO,MAAK,KAAM;AACzC,MAAA,IAAI,oBAAA,CAAqB,GAAA,CAAI,KAAK,CAAA,EAAG;AACjC,QAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,EAAE,KAAA,EAAO,IAAI,KAAA,CAAM,CAAA,OAAA,EAAU,KAAK,CAAA,CAAE,CAAA,EAAG,KAAA,EAAO,IAAA,EAAM,CAAA;AACvE,QAAA,KAAK,KAAK,IAAA,EAAK;AAAA,MACnB;AACA,MAAA,IAAA,CAAK,IAAA,CAAK,OAAO,IAAI,CAAA;AAAA,IACzB,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,WAAA,GAAoB;AACxB,IAAA,IAAA,CAAK,OAAA,CAAQ,wBAAwB,CAAA,IAAA,KAAQ;AACzC,MAAA,IAAA,CAAK,OAAA,CAAQ,iBAAiB,IAAI,CAAA;AAAA,IACtC,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,OAAA,CAAQ,eAAe,CAAA,IAAA,KAAQ;AAChC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,SAAA,CAAU,KAAK,QAAQ,CAAA;AACpD,MAAA,IAAA,CAAK,IAAA,CAAK,YAAA,CAAa,aAAA,EAAyB,OAAO,CAAA;AAAA,IAC3D,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,OAAA,CAAQ,uBAAuB,MAAM;AACtC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,cAAA,CAAe,SAAS,CAAA;AACrD,MAAA,IAAI,YAAY,MAAA,EAAW;AACvB,QAAA,IAAA,CAAK,IAAA,CAAK,YAAA,CAAa,oBAAA,EAAgC,OAAO,CAAA;AAAA,MAClE;AAAA,IACJ,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,OAAA,CAAQ,uBAAuB,MAAM;AACtC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,cAAA,CAAe,OAAO,CAAA;AACnD,MAAA,IAAI,YAAY,MAAA,EAAW;AACvB,QAAA,IAAA,CAAK,IAAA,CAAK,YAAA,CAAa,oBAAA,EAAgC,OAAO,CAAA;AAAA,MAClE;AAAA,IACJ,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,gBAAgB,MAAA,EAA2B;AAC/C,IAAA,IAAI,OAAO,OAAA,EAAS;AAChB,MAAA,KAAK,KAAK,IAAA,EAAK;AACf,MAAA;AAAA,IACJ;AACA,IAAA,IAAA,CAAK,WAAA,GAAc,MAAA;AACnB,IAAA,IAAA,CAAK,eAAe,MAAY;AAC5B,MAAA,KAAK,KAAK,IAAA,EAAK;AAAA,IACnB,CAAA;AACA,IAAA,MAAA,CAAO,iBAAiB,OAAA,EAAS,IAAA,CAAK,cAAc,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EACtE;AACJ;;;ACtXA,IAAM,aAAA,GAAgB;AAAA,EAClB,GAAG,YAAA;AAAA,EACH,YAAA,EAAc,cAAA;AAAA,EACd,oBAAA,EAAsB;AAC1B;AA2BA,IAAM,6BAAA,GAA8C;AAAA,EAChD,OAAO,aAAA,CAAc,oBAAA;AAAA,EACrB,OAAA,EAAS,uBAAA;AAAA,EACT,SAAA,EAAW,OAAgC,EAAE,MAAA,EAAQ,IAAI,SAAA,EAAW,EAAA,EAAI,UAAU,EAAA,EAAG;AACzF,CAAA;AAEA,IAAM,4BAAA,GAAwD;AAAA,EAC1D;AAAA,IACI,OAAO,aAAA,CAAc,YAAA;AAAA,IACrB,OAAA,EAAS,yCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA4B;AAAA,MACpC,QAAA,EAAA,CAAW,KAAA,CAAM,CAAC,CAAA,IAAK,IAAI,IAAA;AAAK,KACpC;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,oBAAA;AAAA,IACrB,OAAA,EAAS,iDAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAoC;AAAA,MAC5C,SAAA,EAAA,CAAY,KAAA,CAAM,CAAC,CAAA,IAAK,IAAI,IAAA;AAAK,KACrC;AAAA;AAER,CAAA;AAGA,IAAM,iBAAA,GAA6C;AAAA,EAC/C,GAAG,gBAAA,CAAiB,MAAA,CAAO,OAAK,CAAA,CAAE,KAAA,KAAU,aAAa,oBAAoB,CAAA;AAAA,EAC7E,6BAAA;AAAA,EACA,GAAG;AACP;AAGA,IAAM,wCAA6C,IAAI,GAAA,CAAI,CAAC,GAAG,oBAAoB,CAAC;;;ACnBpF,IAAM,uBAAA,GAA0B;AAAA,EAC5B,aAAA,EAAe,eAAA;AAAA,EACf,UAAA,EAAY,YAAA;AAAA,EACZ,QAAA,EAAU,UAAA;AAAA,EACV,UAAA,EAAY;AAChB;AAmEA,IAAM,cAAA,GAAiB;AAAA;AAAA,EAEnB,aAAA,EAAe;AAAA,IACX,eAAA,EAAiB;AAAA,GACrB;AAAA;AAAA,EAEA,OAAA,EAAS;AAAA,IACL,eAAA,EAAiB,IAAA;AAAA,IACjB,aAAA,EAAe;AAAA,GACnB;AAAA;AAAA,EAEA,UAAA,EAAY;AAAA,IACR,eAAA,EAAiB,IAAA;AAAA,IACjB,WAAA,EAAa,EAAA;AAAA,IACb,YAAA,EAAc;AAAA;AAEtB;AAKA,IAAM,qBAAA,GAAwBC,EACzB,MAAA,CAAO;AAAA,EACJ,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA;AAAA,EACvC,SAASA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,EAAE,CAAA,CAAE,OAAO,cAAA,EAAgB,EAAE,SAAS,sCAAA,EAAwC,EAAE,QAAA,EAAS;AAAA,EACxH,eAAA,EAAiBA,CAAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,MAAA,CAAO,UAAA,EAAY,EAAE,OAAA,EAAS,4CAAA,EAA8C,EAAE,QAAA,EAAS;AAAA,EAC1H,UAAA,EAAYA,CAAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,MAAA,CAAO,UAAA,EAAY,EAAE,OAAA,EAAS,uCAAA,EAAyC,EAAE,QAAA,EAAS;AAAA,EAChH,eAAeA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EAC1C,uBAAA,EAAyBA,CAAAA,CAAE,IAAA,CAAK,CAAC,eAAA,EAAiB,cAAc,UAAA,EAAY,YAAY,CAAC,CAAA,CAAE,QAAA,EAAS;AAAA,EACpG,WAAA,EAAaA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EAClC,cAAA,EAAgBA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACrC,iBAAA,EAAmBA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACxC,eAAA,EAAiBA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACtC,aAAA,EAAeA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACpC,iBAAiBA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EAC5C,kBAAkBA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EAC7C,iBAAA,EAAmBA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACxD,kBAAA,EAAoBA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACzC,aAAA,EAAeA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACpD,WAAA,EAAaA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EAClD,YAAA,EAAcA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACnD,MAAA,EAAQA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI,CAAE,GAAA,CAAI,IAAI,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA,CAAE,QAAA,EAAS;AAAA,EACxD,mBAAmBA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EAC9C,cAAA,EAAgBA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACrD,cAAA,EAAgBA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACrD,MAAA,EAAQA,CAAAA,CAAE,UAAA,CAAW,WAAW,EAAE,QAAA;AACtC,CAAC,EACA,MAAA,EAAO;AAOZ,SAASC,WAAU,OAAA,EAAoC;AACnD,EAAA,MAAM,IAAA,GAAiB,CAAC,WAAW,CAAA;AAEnC,EAAA,IAAI,OAAA,CAAQ,YAAY,MAAA,EAAW;AAC/B,IAAA,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,OAAA,CAAQ,OAAO,CAAA;AAAA,EAC1C;AACA,EAAA,IAAI,OAAA,CAAQ,UAAA,KAAe,MAAA,IAAa,OAAA,CAAQ,kBAAkB,MAAA,EAAW;AACzE,IAAA,IAAA,CAAK,IAAA,CAAK,eAAA,EAAiB,OAAA,CAAQ,UAAA,EAAY,QAAQ,aAAa,CAAA;AAAA,EACxE;AAEA,EAAA,uBAAA,CAAwB,MAAM,OAAO,CAAA;AACrC,EAAA,aAAA,CAAc,MAAM,OAAO,CAAA;AAC3B,EAAA,eAAA,CAAgB,MAAM,OAAO,CAAA;AAC7B,EAAA,gBAAA,CAAiB,MAAM,OAAO,CAAA;AAC9B,EAAA,aAAA,CAAc,MAAM,OAAO,CAAA;AAE3B,EAAA,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAC,CAAA;AAC9B,EAAA,OAAO,IAAA;AACX;AAGA,SAAS,uBAAA,CAAwB,MAAgB,OAAA,EAAgC;AAC7E,EAAA,IAAI,OAAA,CAAQ,4BAA4B,eAAA,EAAiB;AACrD,IAAA,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,EACnB,CAAA,MAAA,IAAW,OAAA,CAAQ,uBAAA,KAA4B,YAAA,EAAc;AACzD,IAAA,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,EACnB,CAAA,MAAA,IAAW,OAAA,CAAQ,uBAAA,KAA4B,UAAA,EAAY;AACvD,IAAA,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,EACnB,CAAA,MAAA,IAAW,OAAA,CAAQ,uBAAA,KAA4B,YAAA,EAAc;AACzD,IAAA,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,EACnB;AACJ;AAGA,SAAS,aAAA,CAAc,MAAgB,OAAA,EAAgC;AACnE,EAAA,IAAI,OAAA,CAAQ,gBAAgB,IAAA,EAAM;AAC9B,IAAA,IAAA,CAAK,KAAK,qBAAqB,CAAA;AAAA,EACnC;AACA,EAAA,IAAI,OAAA,CAAQ,mBAAmB,IAAA,EAAM;AACjC,IAAA,IAAA,CAAK,KAAK,qBAAqB,CAAA;AAAA,EACnC;AACA,EAAA,IAAI,OAAA,CAAQ,sBAAsB,IAAA,EAAM;AACpC,IAAA,IAAA,CAAK,KAAK,wBAAwB,CAAA;AAAA,EACtC;AACJ;AAGA,SAAS,eAAA,CAAgB,MAAgB,OAAA,EAAgC;AACrE,EAAA,IAAI,OAAA,CAAQ,oBAAoB,MAAA,EAAW;AACvC,IAAA,IAAA,CAAK,IAAA,CAAK,oBAAA,EAAsB,OAAA,CAAQ,eAAe,CAAA;AAAA,EAC3D;AACA,EAAA,IAAI,OAAA,CAAQ,oBAAoB,IAAA,EAAM;AAClC,IAAA,IAAA,CAAK,KAAK,oBAAoB,CAAA;AAAA,EAClC;AACA,EAAA,IAAI,OAAA,CAAQ,kBAAkB,IAAA,EAAM;AAChC,IAAA,IAAA,CAAK,KAAK,kBAAkB,CAAA;AAAA,EAChC;AACA,EAAA,IAAI,OAAA,CAAQ,sBAAsB,MAAA,EAAW;AACzC,IAAA,IAAA,CAAK,IAAA,CAAK,sBAAA,EAAwB,OAAA,CAAQ,iBAAiB,CAAA;AAAA,EAC/D;AACJ;AAGA,SAAS,gBAAA,CAAiB,MAAgB,OAAA,EAAgC;AACtE,EAAA,IAAI,OAAA,CAAQ,kBAAkB,MAAA,EAAW;AACrC,IAAA,IAAA,CAAK,IAAA,CAAK,kBAAA,EAAoB,MAAA,CAAO,OAAA,CAAQ,aAAa,CAAC,CAAA;AAAA,EAC/D;AACA,EAAA,IAAI,OAAA,CAAQ,gBAAgB,MAAA,EAAW;AACnC,IAAA,IAAA,CAAK,IAAA,CAAK,gBAAA,EAAkB,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAC,CAAA;AAAA,EAC3D;AACA,EAAA,IAAI,OAAA,CAAQ,iBAAiB,MAAA,EAAW;AACpC,IAAA,IAAA,CAAK,IAAA,CAAK,iBAAA,EAAmB,MAAA,CAAO,OAAA,CAAQ,YAAY,CAAC,CAAA;AAAA,EAC7D;AACA,EAAA,IAAI,OAAA,CAAQ,WAAW,MAAA,EAAW;AAC9B,IAAA,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,EACjD;AACJ;AAGA,SAAS,aAAA,CAAc,MAAgB,OAAA,EAAgC;AACnE,EAAA,IAAI,OAAA,CAAQ,oBAAoB,MAAA,EAAW;AACvC,IAAA,IAAA,CAAK,IAAA,CAAK,qBAAA,EAAuB,OAAA,CAAQ,eAAe,CAAA;AAAA,EAC5D;AACA,EAAA,IAAI,OAAA,CAAQ,qBAAqB,MAAA,EAAW;AACxC,IAAA,IAAA,CAAK,IAAA,CAAK,mBAAA,EAAqB,OAAA,CAAQ,gBAAgB,CAAA;AAAA,EAC3D;AACA,EAAA,IAAI,OAAA,CAAQ,sBAAsB,MAAA,EAAW;AACzC,IAAA,IAAA,CAAK,IAAA,CAAK,mBAAA,EAAqB,MAAA,CAAO,OAAA,CAAQ,iBAAiB,CAAC,CAAA;AAAA,EACpE;AACA,EAAA,IAAI,OAAA,CAAQ,uBAAuB,IAAA,EAAM;AACrC,IAAA,IAAA,CAAK,KAAK,qBAAqB,CAAA;AAAA,EACnC;AACJ;AA6BA,IAAM,QAAA,GAAN,MAAM,SAAA,SAAiB,YAAA,CAAa;AAAA,EAMxB,WAAA,CAAY,MAAA,EAA4BF,OAAAA,EAAoB,MAAA,EAAsB;AACtF,IAAA,KAAA,CAAM,MAAM,CAAA;AANhB,IAAA,aAAA,CAAA,IAAA,EAAiB,QAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAiB,SAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAQ,aAAA,CAAA;AACR,IAAA,aAAA,CAAA,IAAA,EAAQ,cAAA,CAAA;AAIJ,IAAA,IAAA,CAAK,MAAA,GAASA,OAAAA;AACd,IAAA,IAAA,CAAK,OAAA,GAAU,IAAI,kBAAA,EAAmB;AACtC,IAAA,IAAA,CAAK,UAAA,EAAW;AAChB,IAAA,IAAA,CAAK,WAAA,EAAY;AACjB,IAAA,IAAI,WAAW,MAAA,EAAW;AACtB,MAAA,IAAA,CAAK,gBAAgB,MAAM,CAAA;AAAA,IAC/B;AAAA,EACJ;AAAA;AAAA,EAGA,CAAC,MAAA,CAAO,OAAO,CAAA,GAAU;AACrB,IAAA,IAAI,IAAA,CAAK,WAAA,KAAgB,MAAA,IAAa,IAAA,CAAK,iBAAiB,MAAA,EAAW;AACnE,MAAA,IAAA,CAAK,WAAA,CAAY,mBAAA,CAAoB,OAAA,EAAS,IAAA,CAAK,YAAY,CAAA;AAAA,IACnE;AACA,IAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA,EAAE;AAC5B,IAAA,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,EAAE;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAA,CAA0C,OAAU,QAAA,EAAwD;AACxG,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,KAAA,EAAiB,QAAiB,CAAA;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,sBAAsB,QAAA,EAA6E;AAC/F,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,sBAAA,EAAwB,QAAQ,CAAA;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAc,QAAA,EAAqE;AAC/E,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,cAAA,EAAgB,QAAQ,CAAA;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,QAAA,EAAsE;AACjF,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,eAAA,EAAiB,QAAQ,CAAA;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,sBAAsB,QAAA,EAA6E;AAC/F,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,sBAAA,EAAwB,QAAQ,CAAA;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OAAO,OAAA,EAA4C;AACtD,IAAA,MAAM,UAAA,GAAa,qBAAA,CAAsB,SAAA,CAAU,OAAO,CAAA;AAC1D,IAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACrB,MAAA,OAAO,GAAA,CAAI,qBAAA,CAAsB,UAAA,EAAY,UAAA,CAAW,KAAK,CAAC,CAAA;AAAA,IAClE;AAEA,IAAA,MAAM,YAAA,GAAe,cAAc,UAAU,CAAA;AAC7C,IAAA,IAAI,CAAC,aAAa,EAAA,EAAI;AAClB,MAAA,OAAO,GAAA,CAAI,aAAa,KAAK,CAAA;AAAA,IACjC;AAEA,IAAA,MAAM,IAAA,GAAOE,WAAU,OAAO,CAAA;AAC9B,IAAA,MAAMF,OAAAA,GAAS,IAAI,UAAA,EAAW;AAC9B,IAAA,KAAA,MAAW,WAAW,iBAAA,EAAmB;AACrC,MAAA,MAAM,SAAA,GAAYA,OAAAA,CAAO,UAAA,CAAW,OAAO,CAAA;AAC3C,MAAA,IAAI,CAAC,UAAU,EAAA,EAAI;AACf,QAAA,OAAO,GAAA,CAAI,UAAU,KAAK,CAAA;AAAA,MAC9B;AAAA,IACJ;AAEA,IAAA,MAAM,MAAA,GAA6B;AAAA,MAC/B,QAAQ,YAAA,CAAa,KAAA;AAAA,MACrB,IAAA;AAAA,MACA,gBAAgB,OAAA,CAAQ,cAAA;AAAA,MACxB,gBAAgB,OAAA,CAAQ;AAAA;AAAA,KAE5B;AAEA,IAAA,OAAO,GAAG,IAAI,SAAA,CAAS,QAAQA,OAAAA,EAAQ,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,EAC1D;AAAA;AAAA,EAGQ,UAAA,GAAmB;AACvB,IAAA,IAAA,CAAK,EAAA,CAAG,MAAA,EAAQ,CAAC,EAAE,MAAK,KAAM;AAC1B,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,IAAI,CAAA;AAAA,IACzB,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,OAAO,EAAA,CAAG,OAAA,EAAS,CAAC,EAAE,KAAA,EAAO,MAAK,KAAM;AACzC,MAAA,IAAI,qBAAA,CAAsB,GAAA,CAAI,KAAK,CAAA,EAAG;AAClC,QAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,EAAE,KAAA,EAAO,IAAI,KAAA,CAAM,CAAA,OAAA,EAAU,KAAK,CAAA,CAAE,CAAA,EAAG,KAAA,EAAO,IAAA,EAAM,CAAA;AACvE,QAAA,KAAK,KAAK,IAAA,EAAK;AAAA,MACnB;AACA,MAAA,IAAA,CAAK,IAAA,CAAK,OAAO,IAAI,CAAA;AAAA,IACzB,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,WAAA,GAAoB;AACxB,IAAA,IAAA,CAAK,OAAA,CAAQ,wBAAwB,CAAA,IAAA,KAAQ;AACzC,MAAA,IAAA,CAAK,OAAA,CAAQ,iBAAiB,IAAI,CAAA;AAAA,IACtC,CAAC,CAAA;AAKD,IAAA,IAAA,CAAK,OAAA,CAAQ,gBAAgB,CAAA,IAAA,KAAQ;AACjC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,SAAA,CAAU,KAAK,QAAQ,CAAA;AACpD,MAAA,IAAA,CAAK,IAAA,CAAK,YAAA,CAAa,aAAA,EAAyB,OAAO,CAAA;AAAA,IAC3D,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,OAAA,CAAQ,eAAe,CAAA,IAAA,KAAQ;AAChC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,SAAA,CAAU,KAAK,QAAQ,CAAA;AACpD,MAAA,IAAA,CAAK,IAAA,CAAK,YAAA,CAAa,aAAA,EAAyB,OAAO,CAAA;AAAA,IAC3D,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,OAAA,CAAQ,uBAAuB,MAAM;AACtC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,cAAA,CAAe,SAAS,CAAA;AACrD,MAAA,IAAI,YAAY,MAAA,EAAW;AACvB,QAAA,IAAA,CAAK,IAAA,CAAK,YAAA,CAAa,oBAAA,EAAgC,OAAO,CAAA;AAAA,MAClE;AAAA,IACJ,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,OAAA,CAAQ,uBAAuB,MAAM;AACtC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,cAAA,CAAe,OAAO,CAAA;AACnD,MAAA,IAAI,YAAY,MAAA,EAAW;AACvB,QAAA,IAAA,CAAK,IAAA,CAAK,YAAA,CAAa,oBAAA,EAAgC,OAAO,CAAA;AAAA,MAClE;AAAA,IACJ,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,gBAAgB,MAAA,EAA2B;AAC/C,IAAA,IAAI,OAAO,OAAA,EAAS;AAChB,MAAA,KAAK,KAAK,IAAA,EAAK;AACf,MAAA;AAAA,IACJ;AACA,IAAA,IAAA,CAAK,WAAA,GAAc,MAAA;AACnB,IAAA,IAAA,CAAK,eAAe,MAAY;AAC5B,MAAA,KAAK,KAAK,IAAA,EAAK;AAAA,IACnB,CAAA;AACA,IAAA,MAAA,CAAO,iBAAiB,OAAA,EAAS,IAAA,CAAK,cAAc,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EACtE;AACJ;ACndA,eAAe,gBAAgB,OAAA,EAAwC;AACnE,EAAA,IAAI;AACA,IAAA,MAAM,KAAA,CAAM,OAAA,EAAS,EAAE,SAAA,EAAW,MAAM,CAAA;AACxC,IAAA,OAAO,GAAG,KAAA,CAAS,CAAA;AAAA,EACvB,SAAS,CAAA,EAAY;AACjB,IAAA,MAAM,MAAM,CAAA,YAAa,KAAA,GAAQ,CAAA,CAAE,OAAA,GAAU,OAAO,CAAC,CAAA;AACrD,IAAA,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,OAAO,CAAA,EAAA,EAAK,GAAG,EAAE,CAAC,CAAA;AAAA,EACzE;AACJ;AASA,eAAe,QAAA,CAAS,KAAa,IAAA,EAAqC;AACtE,EAAA,IAAI;AACA,IAAA,MAAM,MAAA,CAAO,KAAK,IAAI,CAAA;AACtB,IAAA,OAAO,GAAG,KAAA,CAAS,CAAA;AAAA,EACvB,CAAA,CAAA,MAAQ;AACJ,IAAA,IAAI;AACA,MAAA,MAAM,QAAA,CAAS,KAAK,IAAI,CAAA;AACxB,MAAA,MAAM,OAAO,GAAG,CAAA;AAChB,MAAA,OAAO,GAAG,KAAA,CAAS,CAAA;AAAA,IACvB,SAAS,CAAA,EAAY;AACjB,MAAA,MAAM,MAAM,CAAA,YAAa,KAAA,GAAQ,CAAA,CAAE,OAAA,GAAU,OAAO,CAAC,CAAA;AACrD,MAAA,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,oBAAA,EAAuB,GAAG,WAAM,IAAI,CAAA,EAAA,EAAK,GAAG,CAAA,CAAE,CAAC,CAAA;AAAA,IACxE;AAAA,EACJ;AACJ;AAQA,eAAe,aAAa,QAAA,EAAmC;AAC3D,EAAA,IAAI;AACA,IAAA,MAAM,CAAA,GAAI,MAAM,IAAA,CAAK,QAAQ,CAAA;AAC7B,IAAA,OAAO,CAAA,CAAE,IAAA;AAAA,EACb,CAAA,CAAA,MAAQ;AAEJ,IAAA,OAAO,CAAA;AAAA,EACX;AACJ;AAOA,eAAe,cAAc,OAAA,EAAgC;AACzD,EAAA,IAAI;AACA,IAAA,MAAM,GAAG,OAAA,EAAS,EAAE,WAAW,IAAA,EAAM,KAAA,EAAO,MAAM,CAAA;AAAA,EACtD,CAAA,CAAA,MAAQ;AAAA,EAER;AACJ;AC0CA,SAAS,eAAe,KAAA,EAAiC;AACrD,EAAA,IAAI,CAAC,iBAAA,CAAkB,IAAA,CAAK,KAAK,CAAA,EAAG;AAChC,IAAA,OAAO,IAAI,IAAI,KAAA,CAAM,CAAA,oBAAA,EAAuB,KAAK,uDAAuD,CAAC,CAAA;AAAA,EAC7G;AACA,EAAA,OAAO,GAAG,KAAiB,CAAA;AAC/B;AA0CA,SAAS,kBAAkB,KAAA,EAAoC;AAC3D,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,IAAK,KAAA,CAAM,SAAS,cAAA,EAAgB;AACrD,IAAA,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,KAAK,CAAA,aAAA,EAAgB,cAAc,aAAa,CAAC,CAAA;AAAA,EACrG;AACA,EAAA,IAAI,CAAC,WAAA,CAAY,IAAA,CAAK,KAAK,CAAA,EAAG;AAC1B,IAAA,OAAO,IAAI,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,KAAK,iCAAiC,CAAC,CAAA;AAAA,EAC3F;AACA,EAAA,OAAO,GAAG,KAAoB,CAAA;AAClC;AAyBA,SAAS,oBAAoB,KAAA,EAAsC;AAC/D,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACpB,IAAA,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,uCAAuC,CAAC,CAAA;AAAA,EACjE;AACA,EAAA,IAAI,sBAAA,CAAuB,IAAA,CAAK,KAAK,CAAA,EAAG;AACpC,IAAA,OAAO,IAAI,IAAI,KAAA,CAAM,CAAA,qDAAA,EAAwD,KAAK,GAAG,CAAC,CAAA;AAAA,EAC1F;AAGA,EAAA,MAAM,UAAA,GAAa,UAAU,KAAK,CAAA;AAClC,EAAA,OAAO,GAAG,UAA2B,CAAA;AACzC;;;AC9KA,IAAM,eAAA,GAAkB,yDAAA;AAOxB,SAAS,eAAe,KAAA,EAAoC;AACxD,EAAA,MAAM,KAAA,GAAQ,MAAM,CAAC,CAAA;AACrB,EAAA,MAAM,OAAA,GAAU,MAAM,CAAC,CAAA;AACvB,EAAA,MAAM,QAAA,GAAW,MAAM,CAAC,CAAA;AAGxB,EAAA,IAAI,KAAA,KAAU,MAAA,IAAa,OAAA,KAAY,MAAA,EAAW;AAC9C,IAAA,MAAM,IAAI,MAAM,mCAAmC,CAAA;AAAA,EACvD;AAEA,EAAA,MAAM,YAAY,cAAA,CAAe,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA,CAAG,CAAA;AAExD,EAAA,IAAI,CAAC,SAAA,CAAU,EAAA,EAAI,MAAM,IAAI,MAAM,CAAA,sBAAA,EAAyB,KAAK,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA,CAAG,CAAA;AAE/E,EAAA,IAAI,QAAA,KAAa,KAAK,OAAO,EAAE,KAAK,SAAA,CAAU,KAAA,EAAO,YAAY,IAAA,EAAK;AACtE,EAAA,IAAI,QAAA,KAAa,MAAA,EAAW,OAAO,EAAE,GAAA,EAAK,UAAU,KAAA,EAAO,KAAA,EAAO,MAAA,CAAO,QAAQ,CAAA,EAAE;AACnF,EAAA,OAAO,EAAE,GAAA,EAAK,SAAA,CAAU,KAAA,EAAM;AAClC;AAGA,SAAS,gBAAA,CAAiB,WAAmB,WAAA,EAA6B;AACtE,EAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,KAAA,CAAM,WAAW,CAAA;AACzC,EAAA,IAAI,CAAC,KAAA,CAAM,UAAA,CAAW,GAAG,GAAG,OAAO,KAAA;AACnC,EAAA,IAAI,MAAM,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,MAAM,0CAA0C,CAAA;AAClF,EAAA,OAAO,KAAA,CAAM,MAAM,CAAC,CAAA;AACxB;AAwBA,SAAS,kBAAkBD,KAAAA,EAA+C;AACtE,EAAA,MAAM,WAAyB,EAAC;AAChC,EAAA,IAAI,SAAA,GAAoBA,KAAAA;AAExB,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,uBAAuB,SAAA,CAAU,MAAA,GAAS,GAAG,CAAA,EAAA,EAAK;AAClE,IAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,IAAA,CAAK,SAAS,CAAA;AAC5C,IAAA,IAAI,UAAU,IAAA,EAAM;AAChB,MAAA,MAAM,IAAI,MAAM,CAAA,qCAAA,EAAwCA,KAAAA,CAAK,SAAS,SAAA,CAAU,MAAM,CAAA,GAAA,EAAM,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,IAC5G;AACA,IAAA,QAAA,CAAS,IAAA,CAAK,cAAA,CAAe,KAAK,CAAC,CAAA;AACnC,IAAA,SAAA,GAAY,gBAAA,CAAiB,SAAA,EAAW,KAAA,CAAM,CAAC,EAAE,MAAM,CAAA;AAAA,EAC3D;AAEA,EAAA,IAAI,SAAA,CAAU,SAAS,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,kCAAA,EAAqC,mBAAmB,CAAA,CAAE,CAAA;AACpG,EAAA,IAAI,SAAS,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,MAAM,mBAAmB,CAAA;AAC9D,EAAA,OAAO,QAAA;AACX;;;AChGA,IAAM,iBAAA,GAAoB,EAAA;AA0C1B,SAAS,QAAA,CAAS,MAAsB,OAAA,EAAwD;AAC5F,EAAA,MAAM,GAAA,GAAmB;AAAA,IACrB,QAAA,EAAU,SAAS,QAAA,IAAY,iBAAA;AAAA,IAC/B,KAAA,EAAO,SAAS,QAAA,KAAa,MAAA,GAAY,IAAI,GAAA,CAAI,OAAA,CAAQ,QAAQ,CAAA,GAAI,MAAA;AAAA,IACrE,SAAS;AAAC,GACd;AACA,EAAA,SAAA,CAAU,IAAA,EAAM,CAAA,EAAG,EAAA,EAAI,GAAG,CAAA;AAC1B,EAAA,OAAO,GAAA,CAAI,OAAA;AACf;AAGA,SAAS,SAAA,CAAU,IAAA,EAAsB,KAAA,EAAe,UAAA,EAAoB,GAAA,EAAwB;AAChG,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA;AAC7B,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,QAAQ,CAAA,EAAA,EAAK;AAClC,IAAA,MAAM,GAAA,GAAM,KAAK,CAAC,CAAA;AAElB,IAAA,IAAI,QAAQ,MAAA,EAAW;AACvB,IAAA,MAAM,OAAA,GAAU,KAAK,GAAG,CAAA;AAExB,IAAA,IAAI,YAAY,MAAA,EAAW;AAC3B,IAAA,MAAM,KAAK,OAAA,CAAQ,EAAA;AACnB,IAAA,MAAMA,KAAAA,GAAO,WAAW,MAAA,GAAS,CAAA,GAAI,GAAG,UAAU,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,GAAK,GAAA;AAE9D,IAAA,IAAI,IAAI,KAAA,KAAU,MAAA,IAAa,IAAI,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA,EAAG;AAC9C,MAAA,GAAA,CAAI,OAAA,CAAQ,KAAK,EAAE,GAAA,EAAK,SAAS,EAAA,EAAI,KAAA,EAAO,IAAA,EAAAA,KAAAA,EAAM,CAAA;AAAA,IACtD;AAEA,IAAA,IAAI,OAAO,IAAA,IAAQ,OAAA,CAAQ,UAAU,MAAA,IAAa,KAAA,GAAQ,IAAI,QAAA,EAAU;AACpE,MAAA,iBAAA,CAAkB,OAAA,CAAQ,KAAA,EAAO,KAAA,EAAOA,KAAAA,EAAM,GAAG,CAAA;AAAA,IACrD;AAAA,EACJ;AACJ;AAGA,SAAS,iBAAA,CAAkB,KAAA,EAA+B,KAAA,EAAe,UAAA,EAAoB,GAAA,EAAwB;AACjH,EAAA,KAAA,IAAS,GAAA,GAAM,CAAA,EAAG,GAAA,GAAM,KAAA,CAAM,QAAQ,GAAA,EAAA,EAAO;AACzC,IAAA,MAAM,IAAA,GAAO,MAAM,GAAG,CAAA;AACtB,IAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,IAAA,EAAM;AAC/C,IAAA,MAAM,QAAA,GAAW,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,CAAA;AACrC,IAAA,SAAA,CAAU,IAAA,EAAwB,KAAA,GAAQ,CAAA,EAAG,QAAA,EAAU,GAAG,CAAA;AAAA,EAC9D;AACJ;;;ACrEA,IAAM,WAAA,GAAc,kBAAA;AAMpB,SAAS,mBAAmB,KAAA,EAA2C;AACnE,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA,IAAQ,QAAQ,KAAA,IAAS,OAAQ,KAAA,CAAkC,IAAI,CAAA,KAAM,QAAA;AAC/H;AAMA,SAAS,sBAAsB,GAAA,EAAuC;AAClE,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA;AAC5B,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,QAAQ,CAAA,EAAA,EAAK;AAClC,IAAA,MAAM,GAAA,GAAM,KAAK,CAAC,CAAA;AAElB,IAAA,IAAI,QAAQ,MAAA,EAAW;AACvB,IAAA,IAAI,CAAC,WAAA,CAAY,IAAA,CAAK,GAAG,GAAG,OAAO,KAAA;AACnC,IAAA,IAAI,CAAC,kBAAA,CAAmB,GAAA,CAAI,GAAG,CAAC,GAAG,OAAO,KAAA;AAAA,EAC9C;AACA,EAAA,OAAO,IAAA;AACX;AAMA,IAAM,eAAA,GAAkB,yCAAA;AACxB,IAAM,YAAA,GAAe,kBAAA;AAMrB,SAAS,aAAa,GAAA,EAAwC;AAC1D,EAAA,MAAM,UAAA,GAAa,eAAA,CAAgB,IAAA,CAAK,GAAG,CAAA;AAC3C,EAAA,IAAI,eAAe,IAAA,EAAM;AACrB,IAAA,MAAM,KAAA,GAAQ,WAAW,CAAC,CAAA;AAC1B,IAAA,MAAM,OAAA,GAAU,WAAW,CAAC,CAAA;AAE5B,IAAA,IAAI,KAAA,KAAU,MAAA,IAAa,OAAA,KAAY,MAAA,EAAW,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,cAAA,EAAiB,GAAG,CAAA,CAAA,CAAG,CAAC,CAAA;AAC/F,IAAA,OAAO,GAAG,CAAA,EAAG,KAAK,GAAG,OAAO,CAAA,CAAA,CAAG,aAAa,CAAA;AAAA,EAChD;AACA,EAAA,IAAI,YAAA,CAAa,IAAA,CAAK,GAAG,CAAA,EAAG;AACxB,IAAA,OAAO,EAAA,CAAG,GAAA,CAAI,WAAA,EAAa,CAAA;AAAA,EAC/B;AACA,EAAA,OAAO,IAAI,IAAI,KAAA,CAAM,CAAA,qBAAA,EAAwB,GAAG,qCAAqC,CAAC,CAAA;AAC1F;AAOA,SAAS,cAAA,CAAe,MAAsB,MAAA,EAA8C;AACxF,EAAA,OAAO,KAAK,MAAM,CAAA;AACtB;AAQA,SAAS,oBAAoB,KAAA,EAAwB;AACjD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,MAAM,OAAO,EAAA;AACxD,EAAA,MAAM,EAAA,GAAK,KAAA;AACX,EAAA,MAAM,UAAA,GAAa,GAAG,YAAY,CAAA;AAClC,EAAA,OAAO,OAAO,UAAA,KAAe,QAAA,GAAW,UAAA,GAAa,EAAA;AACzD;AAGA,SAAS,kBAAkB,KAAA,EAAwB;AAC/C,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,EAAA,IAAI,OAAO,UAAU,QAAA,IAAY,OAAO,UAAU,SAAA,EAAW,OAAO,OAAO,KAAK,CAAA;AAChF,EAAA,OAAO,EAAA;AACX;AAGA,SAAS,cAAc,OAAA,EAAmC;AACtD,EAAA,MAAM,SAAS,OAAA,CAAQ,KAAA;AACvB,EAAA,IAAI,MAAA,KAAW,MAAA,IAAa,MAAA,CAAO,MAAA,KAAW,GAAG,OAAO,EAAA;AAExD,EAAA,MAAM,KAAA,GAAQ,OAAO,CAAC,CAAA;AACtB,EAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM,OAAO,EAAA;AAElD,EAAA,IAAI,OAAA,CAAQ,EAAA,KAAO,IAAA,EAAM,OAAO,oBAAoB,KAAK,CAAA;AACzD,EAAA,OAAO,kBAAkB,KAAK,CAAA;AAClC;AAGA,SAAS,cAAc,OAAA,EAA2C;AAC9D,EAAA,MAAM,SAAS,OAAA,CAAQ,KAAA;AACvB,EAAA,IAAI,MAAA,KAAW,MAAA,IAAa,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG;AAC7C,IAAA,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,4BAA4B,CAAC,CAAA;AAAA,EACtD;AACA,EAAA,MAAM,KAAA,GAAQ,OAAO,CAAC,CAAA;AACtB,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,GAAG,KAAK,CAAA;AAC9C,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,IAAA,MAAM,MAAA,GAAS,OAAO,KAAK,CAAA;AAC3B,IAAA,IAAI,MAAA,CAAO,KAAA,CAAM,MAAM,CAAA,EAAG;AACtB,MAAA,OAAO,IAAI,IAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,KAAK,aAAa,CAAC,CAAA;AAAA,IAC/D;AACA,IAAA,OAAO,GAAG,MAAM,CAAA;AAAA,EACpB;AACA,EAAA,OAAO,IAAI,IAAI,KAAA,CAAM,yBAAyB,OAAO,KAAK,EAAE,CAAC,CAAA;AACjE;AAGA,SAAS,eAAe,OAAA,EAAkD;AACtE,EAAA,MAAM,SAAS,OAAA,CAAQ,KAAA;AACvB,EAAA,IAAI,MAAA,KAAW,MAAA,EAAW,OAAO,EAAC;AAClC,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACpB,IAAA,IAAI,OAAO,MAAM,QAAA,EAAU;AACvB,MAAA,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,IACjB,WAAW,OAAO,CAAA,KAAM,QAAA,IAAY,OAAO,MAAM,SAAA,EAAW;AACxD,MAAA,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,IACzB,CAAA,MAAO;AACH,MAAA,MAAA,CAAO,KAAK,EAAE,CAAA;AAAA,IAClB;AAAA,EACJ;AACA,EAAA,OAAO,MAAA;AACX;AAOA,SAAS,iBAAiB,OAAA,EAA+D;AACrF,EAAA,IAAI,QAAQ,EAAA,KAAO,IAAA,IAAQ,OAAA,CAAQ,KAAA,KAAU,QAAW,OAAO,MAAA;AAC/D,EAAA,OAAO,OAAA,CAAQ,KAAA;AACnB;AAGA,SAAS,iBAAiB,KAAA,EAAyC;AAC/D,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC9E;AAGA,SAAS,mBAAA,CAAoB,SAA2B,GAAA,EAAyC;AAC7F,EAAA,MAAM,KAAA,GAAQ,iBAAiB,OAAO,CAAA;AACtC,EAAA,IAAI,UAAU,MAAA,EAAW;AACrB,IAAA,OAAO,IAAI,IAAI,KAAA,CAAM,OAAO,GAAA,CAAI,GAAG,oBAAoB,CAAC,CAAA;AAAA,EAC5D;AACA,EAAA,MAAM,GAAA,GAAM,IAAI,KAAA,IAAS,CAAA;AACzB,EAAA,MAAM,IAAA,GAAO,MAAM,GAAG,CAAA;AACtB,EAAA,IAAI,CAAC,gBAAA,CAAiB,IAAI,CAAA,EAAG;AACzB,IAAA,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,SAAA,EAAY,IAAI,GAAG,CAAA,4BAAA,EAA+B,GAAG,CAAA,CAAE,CAAC,CAAA;AAAA,EACjF;AACA,EAAA,OAAO,GAAG,IAAI,CAAA;AAClB;AAGA,SAAS,YAAA,CAAa,MAAsB,QAAA,EAA+D;AACvG,EAAA,IAAI,OAAA,GAA0B,IAAA;AAE9B,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,QAAQ,CAAA,EAAA,EAAK;AACtC,IAAA,MAAM,GAAA,GAAM,SAAS,CAAC,CAAA;AAEtB,IAAA,IAAI,QAAQ,MAAA,EAAW,OAAO,IAAI,IAAI,KAAA,CAAM,8BAA8B,CAAC,CAAA;AAE3E,IAAA,MAAM,SAAA,GAAY,YAAA,CAAa,GAAA,CAAI,GAAG,CAAA;AACtC,IAAA,IAAI,CAAC,SAAA,CAAU,EAAA,EAAI,OAAO,GAAA,CAAI,UAAU,KAAK,CAAA;AAE7C,IAAA,MAAM,OAAA,GAAU,cAAA,CAAe,OAAA,EAAS,SAAA,CAAU,KAAK,CAAA;AACvD,IAAA,IAAI,OAAA,KAAY,MAAA,EAAW,OAAO,GAAA,CAAI,IAAI,MAAM,CAAA,IAAA,EAAO,GAAA,CAAI,GAAG,CAAA,UAAA,CAAY,CAAC,CAAA;AAE3E,IAAA,IAAI,MAAM,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG,OAAO,GAAG,OAAO,CAAA;AAEhD,IAAA,MAAM,OAAA,GAAU,mBAAA,CAAoB,OAAA,EAAS,GAAG,CAAA;AAChD,IAAA,IAAI,CAAC,OAAA,CAAQ,EAAA,EAAI,OAAO,GAAA,CAAI,QAAQ,KAAK,CAAA;AACzC,IAAA,OAAA,GAAU,OAAA,CAAQ,KAAA;AAAA,EACtB;AAGA,EAAA,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,qBAAqB,CAAC,CAAA;AAC/C;AAiBA,SAAS,eAAA,CAAgB,MAAsB,QAAA,EAAqD;AAChG,EAAA,MAAM,UAAqB,EAAC;AAC5B,EAAA,MAAM,QAAsB,CAAC,EAAE,IAAA,EAAM,YAAA,EAAc,GAAG,CAAA;AACtD,EAAA,MAAM,gBAAgB,mBAAA,GAAsB,GAAA;AAE5C,EAAA,IAAI,SAAA,GAAY,CAAA;AAChB,EAAA,OAAO,SAAA,GAAY,aAAA,IAAiB,KAAA,CAAM,MAAA,GAAS,GAAG,SAAA,EAAA,EAAa;AAC/D,IAAA,MAAM,KAAA,GAAQ,MAAM,KAAA,EAAM;AAE1B,IAAA,IAAI,UAAU,MAAA,EAAW;AACzB,IAAA,iBAAA,CAAkB,KAAA,EAAO,QAAA,EAAU,OAAA,EAAS,KAAK,CAAA;AAAA,EACrD;AAEA,EAAA,OAAO,EAAE,QAAQ,OAAA,EAAS,SAAA,EAAW,aAAa,aAAA,IAAiB,KAAA,CAAM,SAAS,CAAA,EAAE;AACxF;AAGA,SAAS,iBAAA,CAAkB,KAAA,EAAmB,QAAA,EAAqC,OAAA,EAAoB,KAAA,EAA2B;AAC9H,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,KAAA,CAAM,YAAY,CAAA;AAEvC,EAAA,IAAI,QAAQ,MAAA,EAAW;AAEvB,EAAA,MAAM,SAAA,GAAY,YAAA,CAAa,GAAA,CAAI,GAAG,CAAA;AACtC,EAAA,IAAI,CAAC,UAAU,EAAA,EAAI;AAEnB,EAAA,MAAM,OAAA,GAAU,cAAA,CAAe,KAAA,CAAM,IAAA,EAAM,UAAU,KAAK,CAAA;AAC1D,EAAA,IAAI,YAAY,MAAA,EAAW;AAE3B,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,YAAA,KAAiB,QAAA,CAAS,MAAA,GAAS,CAAA;AAExD,EAAA,IAAI,MAAA,EAAQ;AACR,IAAA,iBAAA,CAAkB,SAAS,OAAO,CAAA;AAClC,IAAA;AAAA,EACJ;AAEA,EAAA,oBAAA,CAAqB,OAAA,EAAS,GAAA,EAAK,KAAA,CAAM,YAAA,EAAc,KAAK,CAAA;AAChE;AAGA,SAAS,iBAAA,CAAkB,SAA2B,OAAA,EAA0B;AAC5E,EAAA,IAAI,OAAA,CAAQ,UAAU,MAAA,EAAW;AAC7B,IAAA,KAAA,MAAW,CAAA,IAAK,QAAQ,KAAA,EAAO;AAC3B,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,IAClB;AAAA,EACJ;AACJ;AAGA,SAAS,oBAAA,CAAqB,OAAA,EAA2B,GAAA,EAAiB,YAAA,EAAsB,KAAA,EAA2B;AACvH,EAAA,MAAM,KAAA,GAAQ,iBAAiB,OAAO,CAAA;AACtC,EAAA,IAAI,UAAU,MAAA,EAAW;AAEzB,EAAA,IAAI,GAAA,CAAI,eAAe,IAAA,EAAM;AACzB,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACtB,MAAA,IAAI,gBAAA,CAAiB,IAAI,CAAA,EAAG;AACxB,QAAA,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,MAAM,YAAA,EAAc,YAAA,GAAe,GAAG,CAAA;AAAA,MAC7D;AAAA,IACJ;AAAA,EACJ,CAAA,MAAO;AACH,IAAA,MAAM,GAAA,GAAM,IAAI,KAAA,IAAS,CAAA;AACzB,IAAA,MAAM,IAAA,GAAO,MAAM,GAAG,CAAA;AACtB,IAAA,IAAI,gBAAA,CAAiB,IAAI,CAAA,EAAG;AACxB,MAAA,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,MAAM,YAAA,EAAc,YAAA,GAAe,GAAG,CAAA;AAAA,IAC7D;AAAA,EACJ;AACJ;AAMA,IAAM,IAAA,GAAO;AAAA,EACT,eAAA,EAAiB,UAAA;AAAA,EACjB,WAAA,EAAa,UAAA;AAAA,EACb,SAAA,EAAW,UAAA;AAAA,EACX,SAAA,EAAW,UAAA;AAAA,EACX,QAAA,EAAU,UAAA;AAAA,EACV,WAAA,EAAa,UAAA;AAAA,EACb,gBAAA,EAAkB,UAAA;AAAA,EAClB,iBAAA,EAAmB,UAAA;AAAA,EACnB,cAAA,EAAgB,UAAA;AAAA,EAChB,iBAAA,EAAmB;AACvB,CAAA;AAsBA,IAAM,YAAA,GAAN,MAAM,aAAA,CAAa;AAAA,EAGP,YAAY,IAAA,EAAsB;AAF1C,IAAA,aAAA,CAAA,IAAA,EAAiB,MAAA,CAAA;AAGb,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,OAAO,SAAS,IAAA,EAAqC;AACjD,IAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,IAAA,KAAS,MAAA,IAAa,OAAO,SAAS,QAAA,IAAY,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,EAAG;AACxF,MAAA,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,2DAA2D,CAAC,CAAA;AAAA,IACrF;AACA,IAAA,MAAM,GAAA,GAAM,IAAA;AACZ,IAAA,IAAI,CAAC,qBAAA,CAAsB,GAAG,CAAA,EAAG;AAC7B,MAAA,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,0GAA0G,CAAC,CAAA;AAAA,IACpI;AACA,IAAA,OAAO,EAAA,CAAG,IAAI,aAAA,CAAa,IAAsB,CAAC,CAAA;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,GAAA,EAAkD;AACzD,IAAA,MAAM,IAAA,GAAO,aAAa,GAAG,CAAA;AAC7B,IAAA,IAAI,CAAC,IAAA,CAAK,EAAA,EAAI,OAAO,GAAA,CAAI,KAAK,KAAK,CAAA;AACnC,IAAA,MAAM,OAAA,GAAU,cAAA,CAAe,IAAA,CAAK,IAAA,EAAM,KAAK,KAAK,CAAA;AACpD,IAAA,IAAI,OAAA,KAAY,QAAW,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,IAAA,EAAO,GAAG,CAAA,UAAA,CAAY,CAAC,CAAA;AACvE,IAAA,OAAO,GAAG,OAAO,CAAA;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,GAAA,EAAwD;AAC7D,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA;AACtC,IAAA,IAAI,CAAC,UAAA,CAAW,EAAA,EAAI,OAAO,GAAA,CAAI,WAAW,KAAK,CAAA;AAC/C,IAAA,MAAM,MAAA,GAAS,WAAW,KAAA,CAAM,KAAA;AAChC,IAAA,IAAI,MAAA,KAAW,QAAW,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,IAAA,EAAO,GAAG,CAAA,aAAA,CAAe,CAAC,CAAA;AACzE,IAAA,OAAO,GAAG,MAAM,CAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAc,GAAA,EAAyC;AACnD,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA;AACnC,IAAA,IAAI,CAAC,SAAA,CAAU,EAAA,EAAI,OAAO,GAAA,CAAI,UAAU,KAAK,CAAA;AAC7C,IAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,KAAA,CAAM,CAAC,CAAA;AAC/B,IAAA,IAAI,KAAA,KAAU,QAAW,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,IAAA,EAAO,GAAG,CAAA,qBAAA,CAAuB,CAAC,CAAA;AAChF,IAAA,OAAO,GAAG,KAAK,CAAA;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,SAAA,CAAU,GAAA,EAAwB,QAAA,GAAW,EAAA,EAAY;AACrD,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA;AACtC,IAAA,IAAI,CAAC,UAAA,CAAW,EAAA,EAAI,OAAO,QAAA;AAC3B,IAAA,MAAM,GAAA,GAAM,aAAA,CAAc,UAAA,CAAW,KAAK,CAAA;AAC1C,IAAA,OAAO,GAAA,CAAI,MAAA,GAAS,CAAA,GAAI,GAAA,GAAM,QAAA;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,GAAA,EAAwC;AAC9C,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA;AACtC,IAAA,IAAI,CAAC,UAAA,CAAW,EAAA,EAAI,OAAO,GAAA,CAAI,WAAW,KAAK,CAAA;AAC/C,IAAA,OAAO,aAAA,CAAc,WAAW,KAAK,CAAA;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,WAAW,GAAA,EAAuD;AAC9D,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA;AACtC,IAAA,IAAI,CAAC,UAAA,CAAW,EAAA,EAAI,OAAO,GAAA,CAAI,WAAW,KAAK,CAAA;AAC/C,IAAA,OAAO,EAAA,CAAG,cAAA,CAAe,UAAA,CAAW,KAAK,CAAC,CAAA;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,GAAA,EAAiC;AACpC,IAAA,MAAM,IAAA,GAAO,aAAa,GAAG,CAAA;AAC7B,IAAA,IAAI,CAAC,IAAA,CAAK,EAAA,EAAI,OAAO,KAAA;AACrB,IAAA,OAAO,cAAA,CAAe,IAAA,CAAK,IAAA,EAAM,IAAA,CAAK,KAAK,CAAA,KAAM,MAAA;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,iBAAiBA,KAAAA,EAA8C;AAC3D,IAAA,IAAI,QAAA;AACJ,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,kBAAkBA,KAAI,CAAA;AAAA,IACrC,SAAS,CAAA,EAAY;AACjB,MAAA,OAAO,GAAA,CAAIJ,MAAAA,CAAO,CAAC,CAAC,CAAA;AAAA,IACxB;AACA,IAAA,OAAO,YAAA,CAAa,IAAA,CAAK,IAAA,EAAM,QAAQ,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,WAAWI,KAAAA,EAA4C;AACnD,IAAA,IAAI,QAAA;AACJ,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,kBAAkBA,KAAI,CAAA;AAAA,IACrC,CAAA,CAAA,MAAQ;AACJ,MAAA,OAAO,EAAC;AAAA,IACZ;AACA,IAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,IAAA,CAAK,IAAA,EAAM,QAAQ,CAAA;AAClD,IAAA,OAAO,MAAA,CAAO,MAAA;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,OAAA,EAAwD;AAC7D,IAAA,OAAO,QAAA,CAAW,IAAA,CAAK,IAAA,EAAM,OAAO,CAAA;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,SAAA,GAAoB;AACpB,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,eAAe,CAAA;AAAA,EAC9C;AAAA;AAAA,EAGA,IAAI,WAAA,GAAsB;AACtB,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,WAAW,CAAA;AAAA,EAC1C;AAAA;AAAA,EAGA,IAAI,SAAA,GAAoB;AACpB,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,SAAS,CAAA;AAAA,EACxC;AAAA;AAAA,EAGA,IAAI,SAAA,GAAoB;AACpB,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,SAAS,CAAA;AAAA,EACxC;AAAA;AAAA,EAGA,IAAI,QAAA,GAAmB;AACnB,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,QAAQ,CAAA;AAAA,EACvC;AAAA;AAAA,EAGA,IAAI,WAAA,GAAuC;AACvC,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,WAAW,CAAA;AAC3C,IAAA,IAAI,GAAA,CAAI,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAC7B,IAAA,MAAM,MAAA,GAAS,kBAAkB,GAAG,CAAA;AACpC,IAAA,OAAO,MAAA,CAAO,EAAA,GAAK,MAAA,CAAO,KAAA,GAAQ,MAAA;AAAA,EACtC;AAAA;AAAA,EAGA,IAAI,gBAAA,GAA2B;AAC3B,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,gBAAgB,CAAA;AAAA,EAC/C;AAAA;AAAA,EAGA,IAAI,iBAAA,GAA4B;AAC5B,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,iBAAiB,CAAA;AAAA,EAChD;AAAA;AAAA,EAGA,IAAI,cAAA,GAAyB;AACzB,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,cAAc,CAAA;AAAA,EAC7C;AAAA;AAAA,EAGA,IAAI,iBAAA,GAA4B;AAC5B,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,iBAAiB,CAAA;AAAA,EAChD;AACJ,CAAA;;;ACvhBA,IAAM,sBAAA,GAAyB,mBAAA;AAW/B,SAAS,cAAc,IAAA,EAAuB;AAC1C,EAAA,IAAI,IAAA,IAAQ,GAAM,OAAO,IAAA;AACzB,EAAA,IAAI,IAAA,KAAS,EAAA,IAAQ,IAAA,KAAS,EAAA,EAAM,OAAO,IAAA;AAC3C,EAAA,IAAI,IAAA,IAAQ,EAAA,IAAQ,IAAA,IAAQ,EAAA,EAAM,OAAO,IAAA;AACzC,EAAA,OAAO,IAAA,KAAS,GAAA;AACpB;AAGA,SAAS,cAAc,KAAA,EAAuB;AAC1C,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACnC,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,UAAA,CAAW,CAAC,CAAA;AAC/B,IAAA,IAAI,CAAC,aAAA,CAAc,IAAI,CAAA,EAAG;AACtB,MAAA,MAAA,IAAU,MAAM,CAAC,CAAA;AAAA,IACrB;AAAA,EACJ;AACA,EAAA,OAAO,MAAA;AACX;AAGA,SAAS,wBAAA,CACL,IAAA,EACA,KAAA,EACA,QAAA,EAC2B;AAC3B,EAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAoB,IAAI,CAAA;AAC3C,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,KAAA,EAAO;AAC9B,IAAA,MAAA,CAAO,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,EACzB;AACA,EAAA,KAAA,MAAW,OAAO,QAAA,EAAU;AACxB,IAAA,MAAA,CAAO,OAAO,GAAG,CAAA;AAAA,EACrB;AACA,EAAA,OAAO,MAAA;AACX;AAGA,SAAS,iBAAA,CAAkB,SAAoB,OAAA,EAAsD;AACjG,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AAChC,EAAA,IAAI,EAAA,GAAK,OAAA;AACT,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,QAAQ,CAAA,EAAA,EAAK;AAClC,IAAA,MAAM,GAAA,GAAM,KAAK,CAAC,CAAA;AAElB,IAAA,IAAI,QAAQ,MAAA,EAAW;AACvB,IAAA,MAAM,KAAA,GAAQ,QAAQ,GAAG,CAAA;AAEzB,IAAA,IAAI,UAAU,MAAA,EAAW;AACzB,IAAA,EAAA,GAAK,EAAA,CAAG,MAAA,CAAO,GAAA,EAAK,KAAK,CAAA;AAAA,EAC7B;AACA,EAAA,OAAO,EAAA;AACX;AAqBA,IAAM,SAAA,GAAN,MAAM,UAAA,CAAU;AAAA,EAIJ,WAAA,CAAY,MAAmC,QAAA,EAA+B;AAHtF,IAAA,aAAA,CAAA,IAAA,EAAiB,MAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAiB,QAAA,CAAA;AAGb,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,QAAA;AAAA,EAClB;AAAA;AAAA,EAGA,OAAO,KAAA,GAAmB;AACtB,IAAA,OAAO,IAAI,UAAA,iBAAU,IAAI,KAAI,kBAAG,IAAI,KAAK,CAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAA,CAAOA,OAAc,KAAA,EAA0B;AAC3C,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,IAAA,CAAK,IAAA,GAAO,KAAK,MAAA,CAAO,IAAA;AAC9C,IAAA,IAAI,YAAY,wBAAA,EAA0B;AACtC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,wBAAwB,CAAA,UAAA,CAAY,CAAA;AAAA,IACtF;AACA,IAAA,iBAAA,CAAkBA,KAAoB,CAAA;AACtC,IAAA,MAAM,SAAA,GAAY,cAAc,KAAK,CAAA;AACrC,IAAA,MAAM,OAAA,GAAU,IAAI,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA;AACjC,IAAA,OAAA,CAAQ,GAAA,CAAIA,OAAM,SAAS,CAAA;AAC3B,IAAA,MAAM,WAAA,GAAc,IAAI,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AACvC,IAAA,WAAA,CAAY,OAAOA,KAAI,CAAA;AACvB,IAAA,OAAO,IAAI,UAAA,CAAU,OAAA,EAAS,WAAW,CAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,SAASA,KAAAA,EAAyB;AAC9B,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,IAAA,CAAK,IAAA,GAAO,KAAK,MAAA,CAAO,IAAA;AAC9C,IAAA,IAAI,YAAY,wBAAA,EAA0B;AACtC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,wBAAwB,CAAA,UAAA,CAAY,CAAA;AAAA,IACtF;AACA,IAAA,iBAAA,CAAkBA,KAAoB,CAAA;AACtC,IAAA,MAAM,OAAA,GAAU,IAAI,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA;AACjC,IAAA,OAAA,CAAQ,OAAOA,KAAI,CAAA;AACnB,IAAA,MAAM,WAAA,GAAc,IAAI,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AACvC,IAAA,WAAA,CAAY,IAAIA,KAAI,CAAA;AACpB,IAAA,OAAO,IAAI,UAAA,CAAU,OAAA,EAAS,WAAW,CAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAA,GAA8B;AAC1B,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,IAAA,CAAK,IAAA,GAAO,KAAK,MAAA,CAAO,IAAA;AAC9C,IAAA,IAAI,YAAY,wBAAA,EAA0B;AACtC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,wBAAwB,CAAA,UAAA,CAAY,CAAA;AAAA,IACtF;AACA,IAAA,MAAM,WAAA,GAAc,IAAI,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AACvC,IAAA,WAAA,CAAY,IAAI,sBAAsB,CAAA;AACtC,IAAA,OAAO,IAAI,UAAA,CAAU,IAAI,IAAI,IAAA,CAAK,IAAI,GAAG,WAAW,CAAA;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAe,KAAA,EAA0B;AACrC,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,aAAa,KAAA,EAA0B;AACnC,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,aAAa,KAAA,EAA0B;AACnC,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,YAAY,KAAA,EAA0B;AAClC,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,mBAAmB,KAAA,EAA0B;AACzC,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,oBAAoB,KAAA,EAA0B;AAC1C,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,qBAAqB,KAAA,EAA0B;AAC3C,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,mBAAmB,KAAA,EAA0B;AACzC,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,OAAA,EAAsD;AAC3D,IAAA,OAAO,iBAAA,CAAkB,MAAM,OAAO,CAAA;AAAA,EAC1C;AAAA;AAAA,EAGA,IAAI,aAAA,GAA6C;AAC7C,IAAA,OAAO,IAAA,CAAK,IAAA;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,QAAA,GAAgC;AAChC,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,cAAA,GAAyB;AACzB,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,MAAA,CAAO,IAAA;AAAA,EACxC;AAAA;AAAA,EAGA,IAAI,OAAA,GAAmB;AACnB,IAAA,OAAO,KAAK,IAAA,CAAK,IAAA,KAAS,CAAA,IAAK,IAAA,CAAK,OAAO,IAAA,KAAS,CAAA;AAAA,EACxD;AAAA;AAAA,EAGA,IAAI,YAAA,GAAwB;AACxB,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,sBAAsB,CAAA;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,KAAA,EAA6B;AAC/B,IAAA,MAAM,cAAA,mBAAiB,IAAI,GAAA,CAAI,CAAC,GAAG,KAAK,MAAA,EAAQ,GAAG,KAAA,CAAM,MAAM,CAAC,CAAA;AAChE,IAAA,MAAM,aAAa,wBAAA,CAAyB,IAAA,CAAK,IAAA,EAAM,KAAA,CAAM,MAAM,cAAc,CAAA;AACjF,IAAA,OAAO,IAAI,UAAA,CAAU,UAAA,EAAY,cAAc,CAAA;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAA,GAAkD;AAC9C,IAAA,MAAM,SAA4B,EAAC;AACnC,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,KAAK,IAAA,EAAM;AAClC,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,GAAA,EAAK,KAAA,EAAO,CAAA;AAAA,IAC9B;AACA,IAAA,OAAO,MAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,aAAA,GAAuC;AACnC,IAAA,MAAM,SAAmB,EAAC;AAC1B,IAAA,KAAA,MAAWA,KAAAA,IAAQ,KAAK,MAAA,EAAQ;AAC5B,MAAA,IAAIA,UAAS,sBAAA,EAAwB;AACjC,QAAA,MAAA,CAAO,KAAKA,KAAI,CAAA;AAAA,MACpB;AAAA,IACJ;AACA,IAAA,OAAO,MAAA;AAAA,EACX;AACJ,CAAA;ACtRA,SAAS,SAAS,GAAA,EAAmB;AACjC,EAAA,IAAI;AACA,IAAAI,KAAK,GAAG,CAAA;AAAA,EAEZ,CAAA,CAAA,MAAQ;AAAA,EAER;AACJ;AAuBA,eAAe,WAAA,CAAY,MAAA,EAAgB,IAAA,EAAyB,OAAA,EAA4D;AAC5H,EAAA,MAAM,SAAA,GAAY,SAAS,SAAA,IAAa,kBAAA;AAExC,EAAA,OAAO,IAAI,QAAQ,CAAA,OAAA,KAAW;AAC1B,IAAA,MAAM,QAAQC,KAAAA,CAAM,MAAA,EAAQ,CAAC,GAAG,IAAI,CAAA,EAAG;AAAA,MACnC,KAAK,OAAA,EAAS,GAAA;AAAA,MACd,WAAA,EAAa,IAAA;AAAA,MACb,QAAQ,OAAA,EAAS;AAAA,KACpB,CAAA;AACD,IAAA,kBAAA,CAAmB,MAAA,EAAQ,KAAA,EAAO,SAAA,EAAW,OAAO,CAAA;AAAA,EACxD,CAAC,CAAA;AACL;AAKA,SAAS,kBAAA,CAAmB,MAAA,EAAgB,KAAA,EAAqB,SAAA,EAAmB,OAAA,EAA6D;AAC7I,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,IAAIT,OAAAA,GAAS,EAAA;AACb,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,MAAM,OAAO,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA,CAAE,KAAI,IAAK,MAAA;AAExC,EAAA,MAAM,MAAA,GAAS,CAAC,MAAA,KAA6C;AACzD,IAAA,IAAI,OAAA,EAAS;AACb,IAAA,OAAA,GAAU,IAAA;AACV,IAAA,YAAA,CAAa,KAAK,CAAA;AAClB,IAAA,OAAA,CAAQ,MAAM,CAAA;AAAA,EAClB,CAAA;AAEA,EAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC3B,IAAA,IAAI,KAAA,CAAM,QAAQ,MAAA,IAAa,KAAA,CAAM,QAAQ,IAAA,EAAM,QAAA,CAAS,MAAM,GAAG,CAAA;AACrE,IAAA,MAAA,CAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA,iBAAA,EAAoB,SAAS,CAAA,SAAA,EAAY,MAAA,CAAO,MAAM,GAAA,IAAO,SAAS,CAAC,CAAA,CAAA,CAAG,CAAC,CAAC,CAAA;AAAA,EAC5G,GAAG,SAAS,CAAA;AAEZ,EAAA,KAAA,CAAM,MAAA,EAAQ,EAAA,CAAG,MAAA,EAAQ,CAAC,KAAA,KAA2B;AACjD,IAAA,MAAA,IAAU,OAAO,KAAK,CAAA;AACtB,IAAA,IAAI,MAAA,CAAO,MAAA,GAASA,OAAAA,CAAO,MAAA,GAAS,gBAAA,EAAkB;AAClD,MAAA,IAAI,KAAA,CAAM,QAAQ,MAAA,IAAa,KAAA,CAAM,QAAQ,IAAA,EAAM,QAAA,CAAS,MAAM,GAAG,CAAA;AACrE,MAAA,MAAA,CAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA,iBAAA,EAAoB,gBAAgB,CAAA,MAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,IAC9E;AAAA,EACJ,CAAC,CAAA;AAED,EAAA,KAAA,CAAM,MAAA,EAAQ,EAAA,CAAG,MAAA,EAAQ,CAAC,KAAA,KAA2B;AACjD,IAAAA,OAAAA,IAAU,OAAO,KAAK,CAAA;AACtB,IAAA,IAAI,MAAA,CAAO,MAAA,GAASA,OAAAA,CAAO,MAAA,GAAS,gBAAA,EAAkB;AAClD,MAAA,IAAI,KAAA,CAAM,QAAQ,MAAA,IAAa,KAAA,CAAM,QAAQ,IAAA,EAAM,QAAA,CAAS,MAAM,GAAG,CAAA;AACrE,MAAA,MAAA,CAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA,iBAAA,EAAoB,gBAAgB,CAAA,MAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,IAC9E;AAAA,EACJ,CAAC,CAAA;AAED,EAAA,KAAA,CAAM,EAAA,CAAG,OAAA,EAAS,CAAC,KAAA,KAAiB;AAChC,IAAA,IAAI,KAAA,CAAM,QAAQ,MAAA,IAAa,KAAA,CAAM,QAAQ,IAAA,EAAM,QAAA,CAAS,MAAM,GAAG,CAAA;AACrE,IAAA,MAAA,CAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,EAAG,IAAI,WAAW,KAAA,CAAM,OAAO,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,EAC5D,CAAC,CAAA;AAED,EAAA,KAAA,CAAM,EAAA,CAAG,OAAA,EAAS,CAAC,IAAA,KAAwB;AACvC,IAAA,MAAA,CAAO,EAAA,CAAG,EAAE,MAAA,EAAQ,MAAA,EAAAA,SAAQ,QAAA,EAAU,IAAA,IAAQ,CAAA,EAAG,CAAC,CAAA;AAAA,EACtD,CAAC,CAAA;AACL;AAoBA,eAAe,YAAA,CAAa,MAAA,EAAgB,IAAA,EAAyB,OAAA,EAA6D;AAC9H,EAAA,MAAM,SAAA,GAAY,SAAS,SAAA,IAAa,kBAAA;AAExC,EAAA,OAAO,IAAI,QAAQ,CAAA,OAAA,KAAW;AAC1B,IAAA,MAAM,QAAQS,KAAAA,CAAM,MAAA,EAAQ,CAAC,GAAG,IAAI,CAAA,EAAG;AAAA,MACnC,KAAK,OAAA,EAAS,GAAA;AAAA,MACd,GAAA,EAAK,OAAA,EAAS,GAAA,GAAM,EAAE,GAAG,QAAQ,GAAA,EAAK,GAAG,OAAA,CAAQ,GAAA,EAAI,GAAI,MAAA;AAAA,MACzD,WAAA,EAAa,IAAA;AAAA,MACb,QAAQ,OAAA,EAAS;AAAA,KACpB,CAAA;AACD,IAAA,kBAAA,CAAmB,MAAA,EAAQ,KAAA,EAAO,SAAA,EAAW,OAAO,CAAA;AAAA,EACxD,CAAC,CAAA;AACL;ACpEA,IAAM,OAAA,GAAgC,CAAC,YAAA,EAAc,aAAA,EAAe,UAAU,CAAA;AAE9E,IAAM,eAAA,uBAAsB,GAAA,CAAI,CAAC,kBAAkB,OAAA,EAAS,YAAA,EAAc,MAAM,CAAC,CAAA;AAOjF,IAAM,cAAA,uBAAqB,GAAA,CAAI;AAAA,EAC3B,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA;AACJ,CAAC,CAAA;AAKD,SAAS,cAAc,IAAA,EAAsC;AACzD,EAAA,MAAM,QAAQ,CAAC,IAAA,CAAK,UAAA,IAAc,EAAA,EAAI,KAAK,SAAA,IAAa,EAAA,EAAI,IAAA,CAAK,UAAA,IAAc,IAAI,IAAA,CAAK,UAAA,IAAc,EAAA,EAAI,IAAA,CAAK,cAAc,EAAE,CAAA;AAC/H,EAAA,IAAI,IAAA,GAAO,MAAM,MAAA,GAAS,CAAA;AAC1B,EAAA,OAAO,IAAA,IAAQ,GAAG,IAAA,EAAA,EAAQ;AACtB,IAAA,IAAI,KAAA,CAAM,IAAI,CAAA,KAAM,EAAA,EAAI;AAAA,EAC5B;AACA,EAAA,OAAO,MAAM,KAAA,CAAM,CAAA,EAAG,OAAO,CAAC,CAAA,CAAE,KAAK,GAAG,CAAA;AAC5C;AAGA,SAAS,QAAQ,GAAA,EAAkC;AAC/C,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG,OAAO,GAAA;AAC/B,EAAA,IAAI,GAAA,KAAQ,MAAA,IAAa,GAAA,KAAQ,IAAA,SAAa,EAAC;AAC/C,EAAA,OAAO,CAAC,GAAG,CAAA;AACf;AAKA,SAAS,kBAAkB,MAAA,EAAyC;AAChE,EAAA,MAAM,SAAiC,EAAC;AAExC,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,MAAA,KAAW,MAAM,OAAO,MAAA;AAC1D,EAAA,MAAM,EAAA,GAAK,MAAA;AAEX,EAAA,KAAA,MAAW,OAAO,OAAA,EAAS;AACvB,IAAA,MAAM,OAAA,GAAU,GAAG,GAAG,CAAA;AACtB,IAAA,IAAI,YAAY,MAAA,IAAa,OAAO,OAAA,KAAY,QAAA,IAAY,YAAY,IAAA,EAAM;AAC1E,MAAA,MAAM,GAAA,GAAM,cAAc,OAAiC,CAAA;AAC3D,MAAA,IAAI,GAAA,CAAI,SAAS,CAAA,EAAG;AAChB,QAAA,MAAA,CAAO,GAAG,CAAA,GAAI,GAAA;AAAA,MAClB;AAAA,IACJ;AAAA,EACJ;AACA,EAAA,OAAO,MAAA;AACX;AAGA,SAAS,WAAW,GAAA,EAAsB;AACtC,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,GAAA;AACpC,EAAA,IAAI,OAAO,QAAQ,QAAA,IAAY,OAAO,QAAQ,SAAA,EAAW,OAAO,OAAO,GAAG,CAAA;AAE1E,EAAA,OAAO,EAAA;AACX;AAGA,SAAS,mBAAA,CAAoB,MAAyB,OAAA,EAA+B;AACjF,EAAA,OAAA,CAAQ,YAAA,GAAe,UAAA,CAAW,IAAA,CAAK,YAAY,CAAA;AACvD;AAGA,SAAS,kBAAA,CAAmB,MAAyB,OAAA,EAA+B;AAChF,EAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,IAAA,CAAK,WAAW,CAAA;AAC1C,EAAA,MAAM,SAAA,GAAY,UAAU,CAAC,CAAA;AAC7B,EAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,SAAA,KAAc,IAAA,IAAQ,WAAW,SAAA,EAAW;AAC7E,IAAA,OAAA,CAAQ,WAAA,GAAc,UAAA,CAAY,SAAA,CAAsC,OAAO,CAAC,CAAA;AAAA,EACpF,CAAA,MAAO;AACH,IAAA,OAAA,CAAQ,WAAA,GAAc,WAAW,SAAS,CAAA;AAAA,EAC9C;AACJ;AAGA,SAAS,cAAA,CAAe,MAAyB,OAAA,EAA+B;AAC5E,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,IAAA,CAAK,UAAU,CAAA;AACvC,EAAA,MAAM,SAAmC,EAAC;AAC1C,EAAA,KAAA,MAAW,MAAM,OAAA,EAAS;AACtB,IAAA,MAAA,CAAO,IAAA,CAAK,iBAAA,CAAkB,EAAE,CAAC,CAAA;AAAA,EACrC;AACA,EAAA,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,OAAA,CAAQ,KAAA,GAAQ,MAAA;AAC3C;AAGA,SAAS,eAAA,CAAgB,MAAyB,OAAA,EAA+B;AAC7E,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAA;AAC/B,EAAA,MAAM,SAA2B,EAAC;AAClC,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AAEtB,IAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,IAAA,EAAM;AAC/C,IAAA,MAAA,CAAO,IAAA,CAAK,iBAAA,CAAkB,IAA+B,CAAC,CAAA;AAAA,EAClE;AACA,EAAA,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,OAAA,CAAQ,KAAA,GAAQ,MAAA;AAC3C;AAGA,IAAM,gBAAA,mBAAmB,IAAI,GAAA,CAAI,CAAC,MAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,IAAI,CAAC,CAAA;AAG7F,SAAS,YAAY,CAAA,EAAqB;AACtC,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,CAAA,KAAM,MAAM,OAAO,CAAA;AAChD,EAAA,MAAM,GAAA,GAAM,CAAA;AACZ,EAAA,IAAI,OAAA,IAAW,GAAA,EAAK,OAAO,GAAA,CAAI,OAAO,CAAA;AACtC,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA;AAC5B,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,IAAK,IAAA,CAAK,CAAC,CAAA,KAAM,MAAA,IAAa,IAAA,CAAK,CAAC,CAAA,CAAE,UAAA,CAAW,IAAI,CAAA,EAAG;AACxE,IAAA,OAAO,GAAA,CAAI,IAAA,CAAK,CAAC,CAAC,CAAA;AAAA,EACtB;AACA,EAAA,OAAO,CAAA;AACX;AAGA,SAAS,cAAc,KAAA,EAAyB;AAC5C,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,EAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,KAAA;AACjC,EAAA,MAAM,GAAA,GAAM,OAAO,OAAO,CAAA;AAC1B,EAAA,OAAO,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA,GAAI,KAAA,GAAQ,GAAA;AACvC;AAGA,SAAS,mBAAA,CAAoB,IAAA,EAAyB,OAAA,EAAyB,EAAA,EAAkB;AAC7F,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA;AACnC,EAAA,MAAM,SAAoB,EAAC;AAC3B,EAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,GAAA,CAAI,EAAE,CAAA;AACzC,EAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACtB,IAAA,MAAM,SAAA,GAAY,YAAY,CAAC,CAAA;AAC/B,IAAA,MAAA,CAAO,IAAA,CAAK,SAAA,GAAY,aAAA,CAAc,SAAS,IAAI,SAAS,CAAA;AAAA,EAChE;AACA,EAAA,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,OAAA,CAAQ,KAAA,GAAQ,MAAA;AAC3C;AAKA,SAAS,eAAe,IAAA,EAA2C;AAC/D,EAAA,MAAM,KAAA,GAAQ,KAAK,MAAM,CAAA;AACzB,EAAA,MAAM,EAAA,GAAK,cAAA,CAAe,GAAA,CAAI,KAAK,IAAI,KAAA,GAAQ,IAAA;AAC/C,EAAA,MAAM,OAAA,GAA0B,EAAE,EAAA,EAAG;AAErC,EAAA,IAAI,IAAA,CAAK,iBAAiB,MAAA,EAAW;AACjC,IAAA,mBAAA,CAAoB,MAAM,OAAO,CAAA;AAAA,EACrC,CAAA,MAAA,IAAW,IAAA,CAAK,WAAA,KAAgB,MAAA,EAAW;AACvC,IAAA,kBAAA,CAAmB,MAAM,OAAO,CAAA;AAAA,EACpC,WAAW,OAAA,CAAQ,EAAA,KAAO,IAAA,IAAQ,IAAA,CAAK,eAAe,MAAA,EAAW;AAC7D,IAAA,cAAA,CAAe,MAAM,OAAO,CAAA;AAAA,EAChC,WAAW,OAAA,CAAQ,EAAA,KAAO,IAAA,IAAQ,IAAA,CAAK,SAAS,MAAA,EAAW;AACvD,IAAA,eAAA,CAAgB,MAAM,OAAO,CAAA;AAAA,EACjC,CAAA,MAAA,IAAW,IAAA,CAAK,KAAA,KAAU,MAAA,EAAW;AACjC,IAAA,mBAAA,CAAoB,IAAA,EAAM,SAAS,EAAE,CAAA;AAAA,EACzC;AAEA,EAAA,OAAO,MAAA,CAAO,OAAO,OAAO,CAAA;AAChC;AAKA,SAAS,kBAAkB,GAAA,EAA8C;AACrE,EAAA,MAAM,SAA2C,EAAC;AAClD,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,gBAAgB,CAAC,CAAA;AAE3C,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACtB,IAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,IAAA,EAAM;AAC/C,IAAA,MAAM,OAAA,GAAU,IAAA;AAChB,IAAA,MAAM,GAAA,GAAM,QAAQ,OAAO,CAAA;AAC3B,IAAA,IAAI,QAAQ,MAAA,EAAW;AACvB,IAAA,MAAA,CAAO,GAAG,CAAA,GAAI,cAAA,CAAe,OAAO,CAAA;AAAA,EACxC;AAEA,EAAA,OAAO,MAAA;AACX;AAGA,IAAM,MAAA,GAAS,IAAI,SAAA,CAAU;AAAA,EACzB,gBAAA,EAAkB,KAAA;AAAA,EAClB,mBAAA,EAAqB,IAAA;AAAA,EACrB,aAAA,EAAe,KAAA;AAAA,EACf,OAAA,EAAS,CAAC,IAAA,KAA0B,eAAA,CAAgB,IAAI,IAAI,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAK5D,eAAA,EAAiB;AACrB,CAAC,CAAA;AAQD,SAAS,UAAU,GAAA,EAAqC;AACpD,EAAA,IAAI;AACA,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AAC/B,IAAA,MAAM,IAAA,GAAO,OAAO,kBAAkB,CAAA;AACtC,IAAA,IAAI,SAAS,KAAA,CAAA,EAAW;AACpB,MAAA,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,+DAA+D,CAAC,CAAA;AAAA,IACzF;AAEA,IAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,IAAA,EAAM;AAC3C,MAAA,OAAO,EAAA,CAAG,EAAE,CAAA;AAAA,IAChB;AACA,IAAA,OAAO,EAAA,CAAG,iBAAA,CAAkB,IAA+B,CAAC,CAAA;AAAA,EAChE,SAAS,KAAA,EAAgB;AACrB,IAAA,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,6BAAA,EAAgCT,OAAO,KAAK,CAAA,CAAE,OAAO,CAAA,CAAE,CAAC,CAAA;AAAA,EACjF;AACJ;;;AC5SA,IAAM,mBAAA,GAAsB,mCAAA;AAM5B,IAAM,WAAA,GAAc,0CAAA;AAQpB,SAAS,kBAAkB,KAAA,EAAuB;AAC9C,EAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,EAAA,IAAI,WAAA,CAAY,IAAA,CAAK,OAAO,CAAA,EAAG;AAC3B,IAAA,OAAO,IAAI,OAAO,CAAA,CAAA,CAAA;AAAA,EACtB;AACA,EAAA,OAAO,OAAA;AACX;AAQA,SAAS,YAAY,KAAA,EAAuB;AACxC,EAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,KAAA;AAGjC,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,IAAI,OAAA,GAAU,EAAA;AACd,EAAA,IAAI,QAAA,GAAW,KAAA;AAEf,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,CAAQ,QAAQ,CAAA,EAAA,EAAK;AACrC,IAAA,MAAM,EAAA,GAAK,QAAQ,CAAC,CAAA;AACpB,IAAA,IAAI,EAAA,KAAO,QAAQ,CAAA,KAAM,CAAA,IAAK,QAAQ,CAAA,GAAI,CAAC,MAAM,IAAA,CAAA,EAAO;AACpD,MAAA,QAAA,GAAW,CAAC,QAAA;AACZ,MAAA,OAAA,IAAW,EAAA;AAAA,IACf,CAAA,MAAA,IAAW,EAAA,KAAO,GAAA,IAAO,CAAC,QAAA,EAAU;AAChC,MAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,MAAA,OAAA,GAAU,EAAA;AAAA,IACd,CAAA,MAAO;AACH,MAAA,OAAA,IAAW,EAAA;AAAA,IACf;AAAA,EACJ;AACA,EAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AAEnB,EAAA,OAAO,MAAA,CAAO,GAAA,CAAI,iBAAiB,CAAA,CAAE,KAAK,IAAI,CAAA;AAClD;AAQA,SAAS,WAAW,GAAA,EAAqB;AACrC,EAAA,OAAO,IAAI,OAAA,CAAQ,mBAAA,EAAqB,CAAC,MAAA,EAAQ,MAAA,EAAgB,OAAe,MAAA,KAAmB;AAC/F,IAAA,OAAO,GAAG,MAAM,CAAA,EAAG,YAAY,KAAK,CAAC,GAAG,MAAM,CAAA,CAAA;AAAA,EAClD,CAAC,CAAA;AACL;;;AClCA,IAAM,qBAAA,GAAwBM,EACzB,MAAA,CAAO;AAAA,EACJ,SAAA,EAAWA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EAChD,MAAA,EAAQA,CAAAA,CAAE,UAAA,CAAW,WAAW,EAAE,QAAA,EAAS;AAAA,EAC3C,UAAA,EAAYA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACjC,eAAeA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EAC1C,iBAAiBA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EAC5C,SAAA,EAAWA,EAAE,IAAA,CAAK,CAAC,WAAW,OAAO,CAAC,EAAE,QAAA;AAC5C,CAAC,CAAA,CACA,MAAA,EAAO,CACP,QAAA,EAAS;AAMd,IAAM,eAAA,GAAuD,EAAE,OAAA,EAAS,IAAA,EAAM,OAAO,IAAA,EAAK;AAK1F,SAAS,mBAAmB,SAAA,EAA2C;AACnE,EAAA,IAAI,cAAc,MAAA,EAAW;AACzB,IAAA,OAAO,CAAC,eAAA,CAAgB,SAAS,CAAC,CAAA;AAAA,EACtC;AACA,EAAA,OAAO,EAAC;AACZ;AAGA,SAAS,aAAa,OAAA,EAAwC;AAC1D,EAAA,MAAM,SAAiC,EAAC;AACxC,EAAA,IAAI,SAAS,SAAA,KAAc,MAAA,EAAW,MAAA,CAAO,WAAW,IAAI,OAAA,CAAQ,SAAA;AACpE,EAAA,IAAI,SAAS,aAAA,KAAkB,MAAA,EAAW,MAAA,CAAO,eAAe,IAAI,OAAA,CAAQ,aAAA;AAC5E,EAAA,IAAI,SAAS,eAAA,KAAoB,MAAA,EAAW,MAAA,CAAO,iBAAiB,IAAI,OAAA,CAAQ,eAAA;AAChF,EAAA,OAAO,MAAA;AACX;AAGA,SAAS,eAAe,YAAA,EAA+B;AACnD,EAAA,OAAO,aAAa,QAAA,CAAS,4BAA4B,CAAA,IAAK,YAAA,CAAa,SAAS,uBAAuB,CAAA;AAC/G;AAGA,eAAe,cAAA,CAAe,MAAA,EAAgB,IAAA,EAAgB,QAAA,EAAwF;AAClJ,EAAA,MAAM,SAAA,GAAY,MAAM,WAAA,CAAY,MAAA,EAAQ,MAAM,QAAQ,CAAA;AAC1D,EAAA,IAAI,CAAC,SAAA,CAAU,EAAA,EAAI,OAAO,GAAA,CAAI,UAAU,KAAK,CAAA;AAC7C,EAAA,IAAI,SAAA,CAAU,KAAA,CAAM,QAAA,KAAa,CAAA,EAAG;AAChC,IAAA,OAAO,GAAA,CAAI,eAAA,CAAgB,SAAA,EAAW,IAAA,EAAM,SAAA,CAAU,MAAM,QAAA,EAAU,SAAA,CAAU,KAAA,CAAM,MAAM,CAAC,CAAA;AAAA,EACjG;AACA,EAAA,MAAM,UAAA,GAAa,SAAA,CAAU,SAAA,CAAU,KAAA,CAAM,MAAM,CAAA;AACnD,EAAA,IAAI,CAAC,UAAA,CAAW,EAAA,EAAI,OAAO,GAAA,CAAI,WAAW,KAAK,CAAA;AAC/C,EAAA,OAAO,GAAG,EAAE,IAAA,EAAM,WAAW,KAAA,EAAO,MAAA,EAAQ,OAAgB,CAAA;AAChE;AAMA,eAAe,UAAA,CAAW,SAAA,EAAmB,SAAA,EAAmB,MAAA,EAAsB,IAAA,EAAqD;AACvI,EAAA,MAAM,SAAA,GAAY,cAAc,SAAS,CAAA;AACzC,EAAA,IAAI,CAAC,SAAA,CAAU,EAAA,EAAI,OAAO,GAAA,CAAI,UAAU,KAAK,CAAA;AAE7C,EAAA,MAAM,WAAA,GAAc,MAAM,aAAA,KAAkB,MAAA,GAAY,CAAC,KAAA,EAAO,IAAA,CAAK,aAAa,CAAA,GAAI,EAAC;AACvF,EAAA,MAAM,OAAA,GAAU,CAAC,GAAG,kBAAA,CAAmB,IAAA,EAAM,SAAS,CAAA,EAAG,GAAG,WAAA,EAAa,MAAA,EAAQ,SAAS,CAAA;AAC1F,EAAA,MAAM,QAAA,GAAW,WAAW,MAAA,GAAY,EAAE,WAAW,MAAA,EAAO,GAAI,EAAE,SAAA,EAAU;AAE5E,EAAA,MAAM,SAAS,MAAM,cAAA,CAAe,SAAA,CAAU,KAAA,EAAO,SAAS,QAAQ,CAAA;AAGtE,EAAA,IAAI,CAAC,MAAA,CAAO,EAAA,IAAM,IAAA,EAAM,eAAA,KAAoB,UAAa,cAAA,CAAe,MAAA,CAAO,KAAA,CAAM,OAAO,CAAA,EAAG;AAC3F,IAAA,MAAM,YAAA,GAAe,CAAC,GAAG,kBAAA,CAAmB,IAAA,CAAK,SAAS,CAAA,EAAG,KAAA,EAAO,IAAA,CAAK,eAAA,EAAiB,MAAA,EAAQ,SAAS,CAAA;AAC3G,IAAA,OAAO,cAAA,CAAe,SAAA,CAAU,KAAA,EAAO,YAAA,EAAc,QAAQ,CAAA;AAAA,EACjE;AAEA,EAAA,OAAO,MAAA;AACX;AAQA,eAAe,aAAA,CAAc,SAAA,EAAmB,SAAA,EAAmB,MAAA,EAAsB,SAAA,EAAkE;AACvJ,EAAA,MAAM,UAAA,GAAa,cAAc,UAAU,CAAA;AAC3C,EAAA,IAAI,CAAC,WAAW,EAAA,EAAI;AAChB,IAAA,OAAO,GAAA,CAAI,WAAW,KAAK,CAAA;AAAA,EAC/B;AAEA,EAAA,MAAM,OAAA,GAAU,MAAM,iBAAA,EAAkB;AACxC,EAAA,MAAM,UAAA,GAAa,CAAC,GAAG,kBAAA,CAAmB,SAAS,CAAA,EAAG,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,SAAS,CAAA;AAErF,EAAA,IAAI;AACA,IAAA,MAAM,QAAA,GAAW,WAAW,KAAA,CAAA,GAAY,EAAE,WAAW,MAAA,EAAO,GAAI,EAAE,SAAA,EAAU;AAC5E,IAAA,OAAO,MAAM,YAAA,CAAa,UAAA,CAAW,KAAA,EAAO,UAAA,EAAY,WAAW,QAAQ,CAAA;AAAA,EAC/E,CAAA,SAAE;AACE,IAAAI,EAAAA,CAAG,OAAA,EAAS,EAAE,SAAA,EAAW,IAAA,EAAM,OAAO,IAAA,EAAM,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,IAAC,CAAC,CAAA;AAAA,EAChE;AACJ;AAGA,eAAe,iBAAA,GAAqC;AAChD,EAAA,OAAO,OAAA,CAAQP,IAAAA,CAAK,MAAA,EAAO,EAAG,gBAAgB,CAAC,CAAA;AACnD;AAGA,eAAe,YAAA,CACX,MAAA,EACA,IAAA,EACA,SAAA,EACA,QAAA,EAC+B;AAC/B,EAAA,MAAM,MAAA,GAAS,MAAM,WAAA,CAAY,MAAA,EAAQ,MAAM,QAAQ,CAAA;AACvD,EAAA,IAAI,CAAC,OAAO,EAAA,EAAI;AACZ,IAAA,OAAO,GAAA,CAAI,OAAO,KAAK,CAAA;AAAA,EAC3B;AAEA,EAAA,IAAI,MAAA,CAAO,KAAA,CAAM,QAAA,KAAa,CAAA,EAAG;AAC7B,IAAA,OAAO,GAAA,CAAI,eAAA,CAAgB,UAAA,EAAY,IAAA,EAAM,MAAA,CAAO,MAAM,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAM,CAAC,CAAA;AAAA,EAC5F;AAEA,EAAA,IAAI;AACA,IAAA,MAAM,QAAA,GAAW,UAAA,CAAW,MAAA,CAAO,KAAA,CAAM,MAAM,CAAA;AAC/C,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,QAAQ,CAAA;AAChC,IAAA,OAAO,EAAA,CAAG,EAAE,IAAA,EAAM,MAAA,EAAQ,UAAmB,CAAA;AAAA,EACjD,SAAS,UAAA,EAAqB;AAC1B,IAAA,OAAO,GAAA,CAAI,eAAA,CAAgB,UAAA,EAAY,CAAC,SAAS,CAAA,EAAG,CAAA,EAAG,CAAA,aAAA,EAAgBH,MAAAA,CAAO,UAAU,CAAA,CAAE,OAAO,EAAE,CAAC,CAAA;AAAA,EACxG;AACJ;AAsBA,eAAe,QAAA,CAAS,WAAmB,OAAA,EAA4D;AACnG,EAAA,MAAM,UAAA,GAAa,qBAAA,CAAsB,SAAA,CAAU,OAAO,CAAA;AAC1D,EAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACrB,IAAA,OAAO,GAAA,CAAI,qBAAA,CAAsB,UAAA,EAAY,UAAA,CAAW,KAAK,CAAC,CAAA;AAAA,EAClE;AAEA,EAAA,MAAM,SAAA,GAAY,SAAS,SAAA,IAAa,kBAAA;AACxC,EAAA,MAAM,SAAS,OAAA,EAAS,MAAA;AACxB,EAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAC3B,EAAA,MAAM,SAAA,GAAY,MAAc,IAAA,CAAK,GAAA,CAAI,KAAM,SAAA,IAAa,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA,CAAU,CAAA;AAEnF,EAAA,MAAM,YAAY,OAAA,EAAS,SAAA;AAG3B,EAAA,IAAI,OAAA,EAAS,eAAe,IAAA,EAAM;AAC9B,IAAA,OAAO,aAAA,CAAc,SAAA,EAAW,SAAA,EAAU,EAAG,QAAQ,SAAS,CAAA;AAAA,EAClE;AAGA,EAAA,MAAM,SAAA,GAAY,MAAM,UAAA,CAAW,SAAA,EAAW,WAAU,EAAG,MAAA,EAAQ,YAAA,CAAa,OAAO,CAAC,CAAA;AACxF,EAAA,IAAI,UAAU,EAAA,EAAI;AACd,IAAA,OAAO,SAAA;AAAA,EACX;AAGA,EAAA,OAAO,aAAA,CAAc,SAAA,EAAW,SAAA,EAAU,EAAG,QAAQ,SAAS,CAAA;AAClE;AC9KA,IAAM,mBAAA,GAAsB,4FAAA;AAE5B,IAAM,qBAAA,GAAwBM,EAAE,MAAA,CAAO;AAAA,EACnC,GAAA,EAAKA,CAAAA,CAAE,MAAA,EAAO,CAAE,MAAM,mBAAmB,CAAA;AAAA,EACzC,KAAA,EAAOA,EAAE,MAAA;AACb,CAAC,CAAA;AAGD,IAAMK,gBAAAA,GAAuD,EAAE,OAAA,EAAS,IAAA,EAAM,OAAO,IAAA,EAAK;AAE1F,IAAM,qBAAA,GAAwBL,EACzB,MAAA,CAAO;AAAA,EACJ,SAAA,EAAWA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EAChD,MAAA,EAAQA,CAAAA,CAAE,UAAA,CAAW,WAAW,EAAE,QAAA,EAAS;AAAA,EAC3C,aAAA,EAAeA,EAAE,KAAA,CAAM,qBAAqB,EAAE,QAAA,EAAS,CAAE,OAAA,CAAQ,EAAE,CAAA;AAAA,EACnE,UAAUA,CAAAA,CAAE,KAAA,CAAMA,EAAE,MAAA,EAAQ,EAAE,QAAA,EAAS;AAAA,EACvC,gBAAA,EAAkBA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACvC,QAAA,EAAUA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EAC/B,eAAA,EAAiBA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACtC,iBAAA,EAAmBA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACxC,SAAA,EAAWA,EAAE,IAAA,CAAK,CAAC,WAAW,OAAO,CAAC,EAAE,QAAA;AAC5C,CAAC,EACA,MAAA,EAAO,CACP,OAAO,CAAA,IAAA,KAAQ,IAAA,CAAK,cAAc,MAAA,GAAS,CAAA,IAAM,IAAA,CAAK,QAAA,KAAa,UAAa,IAAA,CAAK,QAAA,CAAS,SAAS,CAAA,IAAM,IAAA,CAAK,qBAAqB,IAAA,EAAM;AAAA,EAC1I,OAAA,EAAS;AACb,CAAC,CAAA;AAKL,SAASC,UAAAA,CAAU,WAAmB,OAAA,EAAoC;AACtE,EAAA,MAAM,OAAiB,EAAC;AAExB,EAAA,IAAI,OAAA,CAAQ,cAAc,MAAA,EAAW;AACjC,IAAA,IAAA,CAAK,IAAA,CAAKI,gBAAAA,CAAgB,OAAA,CAAQ,SAAS,CAAC,CAAA;AAAA,EAChD;AAEA,EAAA,IAAI,OAAA,CAAQ,aAAa,KAAA,EAAO;AAC5B,IAAA,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,EACnB;AAEA,EAAA,IAAI,OAAA,CAAQ,sBAAsB,IAAA,EAAM;AACpC,IAAA,IAAA,CAAK,KAAK,MAAM,CAAA;AAAA,EACpB;AAEA,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,eAAA,KAAoB,IAAA,GAAO,IAAA,GAAO,IAAA;AACvD,EAAA,MAAM,aAAA,GAAgB,OAAA,CAAQ,aAAA,IAAiB,EAAC;AAEhD,EAAA,KAAA,MAAW,OAAO,aAAA,EAAe;AAC7B,IAAA,IAAA,CAAK,IAAA,CAAK,MAAM,CAAA,EAAG,GAAA,CAAI,GAAG,CAAA,CAAA,EAAI,GAAA,CAAI,KAAK,CAAA,CAAE,CAAA;AAAA,EAC7C;AAEA,EAAA,IAAI,OAAA,CAAQ,aAAa,MAAA,EAAW;AAChC,IAAA,KAAA,MAAW,OAAA,IAAW,QAAQ,QAAA,EAAU;AACpC,MAAA,IAAA,CAAK,IAAA,CAAK,MAAM,OAAO,CAAA;AAAA,IAC3B;AAAA,EACJ;AAEA,EAAA,IAAI,OAAA,CAAQ,qBAAqB,IAAA,EAAM;AACnC,IAAA,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,EACnB;AAEA,EAAA,IAAA,CAAK,KAAK,SAAS,CAAA;AAEnB,EAAA,OAAO,IAAA;AACX;AAqBA,eAAe,QAAA,CAAS,WAAmB,OAAA,EAA2D;AAClG,EAAA,MAAM,UAAA,GAAa,qBAAA,CAAsB,SAAA,CAAU,OAAO,CAAA;AAC1D,EAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACrB,IAAA,OAAO,GAAA,CAAI,qBAAA,CAAsB,UAAA,EAAY,UAAA,CAAW,KAAK,CAAC,CAAA;AAAA,EAClE;AAEA,EAAA,MAAM,YAAA,GAAe,cAAc,UAAU,CAAA;AAC7C,EAAA,IAAI,CAAC,aAAa,EAAA,EAAI;AAClB,IAAA,OAAO,GAAA,CAAI,aAAa,KAAK,CAAA;AAAA,EACjC;AAEA,EAAA,MAAM,IAAA,GAAOJ,UAAAA,CAAU,SAAA,EAAW,OAAO,CAAA;AACzC,EAAA,MAAM,SAAA,GAAY,QAAQ,SAAA,IAAa,kBAAA;AAEvC,EAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa,YAAA,CAAa,OAAO,IAAA,EAAM;AAAA,IACxD,SAAA;AAAA,IACA,QAAQ,OAAA,CAAQ;AAAA,GACnB,CAAA;AAED,EAAA,IAAI,CAAC,OAAO,EAAA,EAAI;AACZ,IAAA,OAAO,GAAA,CAAI,OAAO,KAAK,CAAA;AAAA,EAC3B;AAEA,EAAA,IAAI,MAAA,CAAO,KAAA,CAAM,QAAA,KAAa,CAAA,EAAG;AAC7B,IAAA,OAAO,GAAA,CAAI,eAAA,CAAgB,UAAA,EAAY,IAAA,EAAM,MAAA,CAAO,MAAM,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAM,CAAC,CAAA;AAAA,EAC5F;AAEA,EAAA,OAAO,EAAA,CAAG,EAAE,QAAA,EAAU,SAAA,EAAW,CAAA;AACrC;ACpIA,eAAe,kBAAA,CAAmB,QAAA,EAAyB,SAAA,EAAsB,OAAA,EAA+C;AAC5H,EAAA,MAAM,aAAA,GAAgB,UAAU,eAAA,EAAgB;AAChD,EAAA,MAAM,QAAA,GAAW,UAAU,aAAA,EAAc;AAEzC,EAAA,MAAM,WAAA,GAAc,QAAA,CAAS,MAAA,GAAS,CAAA,IAAK,SAAA,CAAU,YAAA;AAErD,EAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,QAAA,EAAU;AAAA,IACpC,aAAA,EAAe,aAAA,CAAc,MAAA,GAAS,CAAA,GAAI,aAAA,GAAgB,MAAA;AAAA,IAC1D,QAAA,EAAU,QAAA,CAAS,MAAA,GAAS,CAAA,GAAI,QAAA,GAAW,MAAA;AAAA,IAC3C,gBAAA,EAAkB,UAAU,YAAA,IAAgB,MAAA;AAAA,IAC5C,eAAA,EAAiB,IAAA;AAAA,IACjB,mBAAmB,WAAA,IAAe,MAAA;AAAA,IAClC,SAAA,EAAW,QAAQ,SAAA,IAAa,kBAAA;AAAA,IAChC,QAAQ,OAAA,CAAQ;AAAA,GACnB,CAAA;AAED,EAAA,IAAI,CAAC,MAAA,CAAO,EAAA,EAAI,OAAO,GAAA,CAAI,OAAO,KAAK,CAAA;AACvC,EAAA,OAAO,GAAG,MAAS,CAAA;AACvB;AAGA,eAAe,YAAA,CAAa,QAAgB,IAAA,EAAqC;AAC7E,EAAA,OAAO,QAAA;AAAA,IACH,MAAMK,QAAAA,CAAS,MAAA,EAAQ,IAAI,CAAA;AAAA,IAC3B,OAAK,IAAI,KAAA,CAAM,CAAA,qBAAA,EAAwB,CAAA,CAAE,OAAO,CAAA,CAAE;AAAA,GACtD;AACJ;AAGA,eAAe,aAAaR,KAAAA,EAAuC;AAC/D,EAAA,OAAO,QAAA;AAAA,IACH,YAAA,CAAa,MAAMS,IAAAA,CAAKT,KAAI,CAAA,EAAG,IAAA;AAAA,IAC/B,OAAK,IAAI,KAAA,CAAM,CAAA,qBAAA,EAAwB,CAAA,CAAE,OAAO,CAAA,CAAE;AAAA,GACtD;AACJ;AAGA,eAAe,WAAWA,KAAAA,EAAqC;AAC3D,EAAA,OAAO,QAAA;AAAA,IACH,MAAMU,OAAOV,KAAI,CAAA;AAAA,IACjB,OAAK,IAAI,KAAA,CAAM,CAAA,uBAAA,EAA0B,CAAA,CAAE,OAAO,CAAA,CAAE;AAAA,GACxD;AACJ;;;ACjCA,IAAM,aAAA,GAAN,MAAM,cAAA,CAAc;AAAA,EAMR,WAAA,CAAY,OAAA,EAAuB,OAAA,EAAoB,QAAA,EAAqC,QAAA,EAAwC;AAL5I,IAAA,aAAA,CAAA,IAAA,EAAiB,cAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAiB,WAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAiB,UAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAiB,MAAA,CAAA;AAGb,IAAA,IAAA,CAAK,YAAA,GAAe,OAAA;AACpB,IAAA,IAAA,CAAK,SAAA,GAAY,OAAA;AACjB,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,IAAA,GAAO,QAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,aAAa,IAAA,CAAKA,KAAAA,EAAc,OAAA,EAA4D;AACxF,IAAA,MAAM,cAAA,GAAiB,oBAAoBA,KAAI,CAAA;AAC/C,IAAA,IAAI,CAAC,cAAA,CAAe,EAAA,EAAI,OAAO,GAAA,CAAI,eAAe,KAAK,CAAA;AAEvD,IAAA,MAAM,UAAA,GAAa,MAAM,QAAA,CAASA,KAAAA,EAAM;AAAA,MACpC,SAAA,EAAW,SAAS,SAAA,IAAa,kBAAA;AAAA,MACjC,QAAQ,OAAA,EAAS,MAAA;AAAA,MACjB,eAAe,OAAA,EAAS,aAAA;AAAA,MACxB,iBAAiB,OAAA,EAAS;AAAA,KAC7B,CAAA;AACD,IAAA,IAAI,CAAC,UAAA,CAAW,EAAA,EAAI,OAAO,GAAA,CAAI,WAAW,KAAK,CAAA;AAE/C,IAAA,MAAM,aAAA,GAAgB,YAAA,CAAa,QAAA,CAAS,UAAA,CAAW,MAAM,IAAI,CAAA;AACjE,IAAA,IAAI,CAAC,aAAA,CAAc,EAAA,EAAI,OAAO,GAAA,CAAI,cAAc,KAAK,CAAA;AAErD,IAAA,OAAO,EAAA,CAAG,IAAI,cAAA,CAAc,aAAA,CAAc,KAAA,EAAO,SAAA,CAAU,KAAA,EAAM,EAAG,cAAA,CAAe,KAAA,kBAAO,IAAI,GAAA,EAAK,CAAC,CAAA;AAAA,EACxG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,WAAA,CAAY,OAAA,EAAuB,QAAA,EAA0C;AAChF,IAAA,IAAI,EAAA;AACJ,IAAA,IAAI,aAAa,MAAA,EAAW;AACxB,MAAA,MAAM,QAAA,GAAW,oBAAoB,QAAQ,CAAA;AAC7C,MAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,OAAO,GAAA,CAAI,SAAS,KAAK,CAAA;AAC3C,MAAA,EAAA,GAAK,QAAA,CAAS,KAAA;AAAA,IAClB;AACA,IAAA,OAAO,EAAA,CAAG,IAAI,cAAA,CAAc,OAAA,EAAS,SAAA,CAAU,KAAA,EAAM,EAAG,EAAA,kBAAI,IAAI,GAAA,EAAK,CAAC,CAAA;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,OAAA,GAAwB;AACxB,IAAA,OAAO,IAAA,CAAK,YAAA;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,OAAA,GAAqB;AACrB,IAAA,OAAO,IAAA,CAAK,SAAA;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,iBAAA,GAA6B;AAC7B,IAAA,OAAO,CAAC,KAAK,SAAA,CAAU,OAAA;AAAA,EAC3B;AAAA;AAAA,EAGA,IAAI,QAAA,GAA+B;AAC/B,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,WAAA,GAAsB;AACtB,IAAA,OAAO,KAAK,YAAA,CAAa,WAAA;AAAA,EAC7B;AAAA;AAAA,EAGA,IAAI,SAAA,GAAoB;AACpB,IAAA,OAAO,KAAK,YAAA,CAAa,SAAA;AAAA,EAC7B;AAAA;AAAA,EAGA,IAAI,SAAA,GAAoB;AACpB,IAAA,OAAO,KAAK,YAAA,CAAa,SAAA;AAAA,EAC7B;AAAA;AAAA,EAGA,IAAI,QAAA,GAAmB;AACnB,IAAA,OAAO,KAAK,YAAA,CAAa,QAAA;AAAA,EAC7B;AAAA;AAAA,EAGA,IAAI,SAAA,GAAoB;AACpB,IAAA,OAAO,KAAK,YAAA,CAAa,SAAA;AAAA,EAC7B;AAAA;AAAA,EAGA,IAAI,WAAA,GAAuC;AACvC,IAAA,OAAO,KAAK,YAAA,CAAa,WAAA;AAAA,EAC7B;AAAA;AAAA,EAGA,IAAI,gBAAA,GAA2B;AAC3B,IAAA,OAAO,KAAK,YAAA,CAAa,gBAAA;AAAA,EAC7B;AAAA;AAAA,EAGA,IAAI,iBAAA,GAA4B;AAC5B,IAAA,OAAO,KAAK,YAAA,CAAa,iBAAA;AAAA,EAC7B;AAAA;AAAA,EAGA,IAAI,cAAA,GAAyB;AACzB,IAAA,OAAO,KAAK,YAAA,CAAa,cAAA;AAAA,EAC7B;AAAA;AAAA,EAGA,IAAI,iBAAA,GAA4B;AAC5B,IAAA,OAAO,KAAK,YAAA,CAAa,iBAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAA,CAAU,GAAA,EAAwB,QAAA,GAAW,EAAA,EAAY;AACrD,IAAA,OAAO,IAAA,CAAK,YAAA,CAAa,SAAA,CAAU,GAAA,EAAK,QAAQ,CAAA;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU,GAAA,EAAwC;AAC9C,IAAA,OAAO,IAAA,CAAK,YAAA,CAAa,SAAA,CAAU,GAAG,CAAA;AAAA,EAC1C;AAAA;AAAA,EAGA,OAAO,GAAA,EAAiC;AACpC,IAAA,OAAO,IAAA,CAAK,YAAA,CAAa,MAAA,CAAO,GAAG,CAAA;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAWA,KAAAA,EAA4C;AACnD,IAAA,OAAO,IAAA,CAAK,YAAA,CAAa,UAAA,CAAWA,KAAI,CAAA;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAA,CAAOA,OAAc,KAAA,EAA8B;AAC/C,IAAA,OAAO,IAAI,cAAA,CAAc,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,SAAA,CAAU,MAAA,CAAOA,KAAAA,EAAM,KAAK,CAAA,EAAG,IAAA,CAAK,QAAA,EAAU,KAAK,IAAI,CAAA;AAAA,EAC5G;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAASA,KAAAA,EAA6B;AAClC,IAAA,OAAO,IAAI,cAAA,CAAc,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,SAAA,CAAU,QAAA,CAASA,KAAI,CAAA,EAAG,IAAA,CAAK,QAAA,EAAU,IAAA,CAAK,IAAI,CAAA;AAAA,EACvG;AAAA;AAAA,EAGA,gBAAA,GAAkC;AAC9B,IAAA,OAAO,IAAI,cAAA,CAAc,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,SAAA,CAAU,gBAAA,EAAiB,EAAG,IAAA,CAAK,QAAA,EAAU,IAAA,CAAK,IAAI,CAAA;AAAA,EAC3G;AAAA;AAAA,EAGA,eAAe,KAAA,EAA8B;AACzC,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,aAAa,KAAA,EAA8B;AACvC,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,aAAa,KAAA,EAA8B;AACvC,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,YAAY,KAAA,EAA8B;AACtC,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,mBAAmB,KAAA,EAA8B;AAC7C,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,oBAAoB,KAAA,EAA8B;AAC9C,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,qBAAqB,KAAA,EAA8B;AAC/C,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA,EAGA,mBAAmB,KAAA,EAA8B;AAC7C,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,aAAA,EAAe,KAAK,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,YAAA,CAAaA,OAAc,EAAA,EAA4D;AACnF,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,YAAA,CAAa,SAAA,CAAUA,KAAI,CAAA;AAChD,IAAA,MAAM,WAAW,EAAA,CAAG,OAAA,CAAQ,MAAA,GAAS,CAAA,GAAI,UAAU,MAAS,CAAA;AAC5D,IAAA,OAAO,IAAA,CAAK,MAAA,CAAOA,KAAAA,EAAM,QAAQ,CAAA;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAS,OAAA,EAA0D;AAC/D,IAAA,OAAO,IAAI,cAAA,CAAc,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,SAAA,CAAU,QAAA,CAAS,OAAO,CAAA,EAAG,IAAA,CAAK,QAAA,EAAU,IAAA,CAAK,IAAI,CAAA;AAAA,EAC1G;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,OAAA,EAAmC;AAC3C,IAAA,OAAO,IAAI,cAAA,CAAc,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,SAAA,CAAU,KAAA,CAAM,OAAO,CAAA,EAAG,IAAA,CAAK,QAAA,EAAU,IAAA,CAAK,IAAI,CAAA;AAAA,EACvG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,aAAa,OAAA,EAAgC;AACzC,IAAA,MAAM,MAAA,GAAS,oBAAoB,OAAO,CAAA;AAC1C,IAAA,IAAI,CAAC,MAAA,CAAO,EAAA,EAAI,MAAM,MAAA,CAAO,KAAA;AAC7B,IAAA,OAAO,IAAI,eAAc,IAAA,CAAK,YAAA,EAAc,KAAK,SAAA,EAAW,MAAA,CAAO,KAAA,EAAO,IAAA,CAAK,IAAI,CAAA;AAAA,EACvF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,aAAa,OAAA,EAAgD;AAC/D,IAAA,IAAI,IAAA,CAAK,aAAa,MAAA,EAAW,OAAO,IAAI,IAAI,KAAA,CAAM,4CAA4C,CAAC,CAAA;AACnG,IAAA,IAAI,IAAA,CAAK,SAAA,CAAU,OAAA,EAAS,OAAO,GAAG,MAAS,CAAA;AAC/C,IAAA,OAAO,mBAAmB,IAAA,CAAK,QAAA,EAAU,KAAK,SAAA,EAAW,OAAA,IAAW,EAAE,CAAA;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,OAAA,CAAQ,UAAA,EAAoB,OAAA,EAAyD;AACvF,IAAA,IAAI,IAAA,CAAK,aAAa,MAAA,EAAW,OAAO,IAAI,IAAI,KAAA,CAAM,4CAA4C,CAAC,CAAA;AAEnG,IAAA,MAAM,aAAA,GAAgB,oBAAoB,UAAU,CAAA;AACpD,IAAA,IAAI,CAAC,aAAA,CAAc,EAAA,EAAI,OAAO,GAAA,CAAI,cAAc,KAAK,CAAA;AAErD,IAAA,MAAM,UAAA,GAAa,MAAM,YAAA,CAAa,IAAA,CAAK,UAAU,UAAU,CAAA;AAC/D,IAAA,IAAI,CAAC,UAAA,CAAW,EAAA,EAAI,OAAO,GAAA,CAAI,WAAW,KAAK,CAAA;AAE/C,IAAA,IAAI,CAAC,IAAA,CAAK,SAAA,CAAU,OAAA,EAAS;AACzB,MAAA,MAAM,WAAA,GAAc,MAAM,kBAAA,CAAmB,aAAA,CAAc,OAAO,IAAA,CAAK,SAAA,EAAW,OAAA,IAAW,EAAE,CAAA;AAC/F,MAAA,IAAI,CAAC,YAAY,EAAA,EAAI;AACjB,QAAA,MAAM,WAAW,UAAU,CAAA;AAC3B,QAAA,OAAO,GAAA,CAAI,YAAY,KAAK,CAAA;AAAA,MAChC;AAAA,IACJ;AAEA,IAAA,OAAO,EAAA,CAAG,IAAI,cAAA,CAAc,IAAA,CAAK,YAAA,EAAc,SAAA,CAAU,KAAA,EAAM,EAAG,aAAA,CAAc,KAAA,EAAO,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,EACrG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAA,GAAoC;AACtC,IAAA,IAAI,IAAA,CAAK,aAAa,MAAA,EAAW,OAAO,IAAI,IAAI,KAAA,CAAM,4CAA4C,CAAC,CAAA;AACnG,IAAA,OAAO,YAAA,CAAa,KAAK,QAAQ,CAAA;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,MAAA,GAAgC;AAClC,IAAA,IAAI,IAAA,CAAK,aAAa,MAAA,EAAW,OAAO,IAAI,IAAI,KAAA,CAAM,4CAA4C,CAAC,CAAA;AACnG,IAAA,OAAO,UAAA,CAAW,KAAK,QAAQ,CAAA;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,YAAA,CAAa,KAAa,KAAA,EAA+B;AACrD,IAAA,MAAM,OAAA,GAAU,IAAI,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA;AACjC,IAAA,OAAA,CAAQ,GAAA,CAAI,KAAK,KAAK,CAAA;AACtB,IAAA,OAAO,IAAI,eAAc,IAAA,CAAK,YAAA,EAAc,KAAK,SAAA,EAAW,IAAA,CAAK,UAAU,OAAO,CAAA;AAAA,EACtF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,GAAA,EAAsB;AAC9B,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AAAA,EAC5B;AACJ,CAAA;;;ACnYA,IAAM,qBAAA,GAAwB,CAAA;AAC9B,IAAM,qBAAA,GAAwB,EAAA;AAC9B,IAAM,6BAAA,GAAgC,GAAA;AACtC,IAAM,4BAAA,GAA+B,GAAA;AACrC,IAAM,sBAAA,GAAyB,GAAA;AAC/B,IAAM,gCAAA,GAAmC,GAAA;AAwLzC,IAAM,0BAAA,GAA6BE,EAC9B,MAAA,CAAO;AAAA,EACJ,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA;AAAA,EACvC,UAAA,EAAYA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,MAAA,CAAO,UAAA,EAAY,EAAE,OAAA,EAAS,uCAAA,EAAyC,CAAA;AAAA,EACrG,SAASA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,EAAE,CAAA,CAAE,OAAO,cAAA,EAAgB,EAAE,SAAS,sCAAA,EAAwC,EAAE,QAAA,EAAS;AAAA,EACxH,WAAA,EAAaA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,GAAG,CAAA,CAAE,QAAA,EAAS;AAAA,EACvD,WAAA,EAAaA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,GAAG,CAAA,CAAE,QAAA,EAAS;AAAA,EACvD,mBAAA,EAAqBA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EAC1D,UAAA,EAAYA,CAAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,MAAA,CAAO,UAAA,EAAY,EAAE,OAAA,EAAS,uCAAA,EAAyC,EAAE,QAAA,EAAS;AAAA,EAChH,eAAeA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EAC1C,WAAA,EAAaA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EAClD,YAAA,EAAcA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACnD,MAAA,EAAQA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI,CAAE,GAAA,CAAI,IAAI,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA,CAAE,QAAA,EAAS;AAAA,EACxD,YAAA,EAAcA,CAAAA,CAAE,IAAA,CAAK,CAAC,SAAA,EAAW,UAAU,cAAA,EAAgB,aAAa,CAAC,CAAA,CAAE,QAAA,EAAS;AAAA,EACpF,mBAAmBA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EAC9C,WAAA,EAAaA,EAAE,IAAA,CAAK,CAAC,UAAU,gBAAA,EAAkB,QAAQ,CAAC,CAAA,CAAE,QAAA,EAAS;AAAA,EACrE,mBAAA,EAAqBA,EAChB,MAAA,CAAO;AAAA,IACJ,SAAA,EAAWA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,IAChD,MAAA,EAAQA,CAAAA,CAAE,UAAA,CAAW,WAAW,EAAE,QAAA,EAAS;AAAA,IAC3C,eAAeA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,IAC1C,iBAAiBA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA;AAAS,GAC/C,CAAA,CACA,MAAA,EAAO,CACP,QAAA,EAAS;AAAA,EACd,cAAA,EAAgBA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACrC,MAAA,EAAQA,CAAAA,CAAE,UAAA,CAAW,WAAW,EAAE,QAAA;AACtC,CAAC,CAAA,CACA,MAAA,EAAO,CACP,MAAA,CAAO,CAAA,IAAA,KAAA,CAAS,KAAK,WAAA,IAAe,qBAAA,MAA2B,IAAA,CAAK,WAAA,IAAe,qBAAA,CAAA,EAAwB;AAAA,EACxG,OAAA,EAAS;AACb,CAAC,CAAA;AAkBL,IAAM,SAAN,MAAa;AAAA,EAgBT,WAAA,CAAY,OAAA,EAAkB,IAAA,EAAc,OAAA,EAAiB;AAf7D,IAAA,aAAA,CAAA,IAAA,EAAS,SAAA,CAAA;AACT,IAAA,aAAA,CAAA,IAAA,EAAS,MAAA,CAAA;AACT,IAAA,aAAA,CAAA,IAAA,EAAS,SAAA,CAAA;AACT,IAAA,aAAA,CAAA,IAAA,EAAQ,QAAA,EAAyC,MAAA,CAAA;AACjD,IAAA,aAAA,CAAA,IAAA,EAAQ,UAAA,CAAA;AACR,IAAA,aAAA,CAAA,IAAA,EAAiB,UAAA,sBAAe,GAAA,EAAmB,CAAA;AACnD,IAAA,aAAA,CAAA,IAAA,EAAiB,kBAAA,sBAAuB,GAAA,EAAmB,CAAA;AAC3D,IAAA,aAAA,CAAA,IAAA,EAAQ,oBAAA,EAAqB,CAAA,CAAA;AAC7B,IAAA,aAAA,CAAA,IAAA,EAAQ,iBAAA,EAAkB,CAAA,CAAA;AAC1B,IAAA,aAAA,CAAA,IAAA,EAAiB,UAAmB,EAAC,CAAA;AACrC,IAAA,aAAA,CAAA,IAAA,EAAiB,cAAuB,EAAC,CAAA;AACzC,IAAA,aAAA,CAAA,IAAA,EAAiB,gBAAyB,EAAC,CAAA;AAC3C,IAAA,aAAA,CAAA,IAAA,EAAQ,eAAA,CAAA;AACR,IAAA,aAAA,CAAA,IAAA,EAAQ,eAAA,CAAA;AAGJ,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACnB;AAAA;AAAA,EAGA,IAAI,KAAA,GAAwC;AACxC,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,OAAA,GAA0C;AAC1C,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,KAAA,GAA2B;AAC3B,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,SAAA,GAA+B;AAC/B,IAAA,OAAO,IAAA,CAAK,UAAA;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,WAAA,GAAiC;AACjC,IAAA,OAAO,IAAA,CAAK,YAAA;AAAA,EAChB;AAAA;AAAA,EAGA,iBAAiB,GAAA,EAA+B;AAC5C,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,QAAA,GAAW,GAAA;AAChB,IAAA,IAAA,CAAK,OAAO,MAAA,GAAS,CAAA;AACrB,IAAA,IAAA,CAAK,WAAW,MAAA,GAAS,CAAA;AACzB,IAAA,IAAA,CAAK,aAAa,MAAA,GAAS,CAAA;AAC3B,IAAA,IAAA,CAAK,SAAS,KAAA,EAAM;AACpB,IAAA,IAAA,CAAK,iBAAiB,KAAA,EAAM;AAC5B,IAAA,IAAA,CAAK,kBAAA,GAAqB,CAAA;AAC1B,IAAA,IAAA,CAAK,eAAA,GAAkB,CAAA;AAAA,EAC3B;AAAA;AAAA,EAGA,cAAA,GAAuB;AACnB,IAAA,IAAA,CAAK,MAAA,GAAS,YAAA;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAA,GAAuB;AACnB,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAEd,IAAA,IAAA,CAAK,OAAO,MAAA,GAAS,CAAA;AACrB,IAAA,IAAA,CAAK,WAAW,MAAA,GAAS,CAAA;AACzB,IAAA,IAAA,CAAK,aAAa,MAAA,GAAS,CAAA;AAC3B,IAAA,IAAA,CAAK,SAAS,KAAA,EAAM;AACpB,IAAA,IAAA,CAAK,iBAAiB,KAAA,EAAM;AAC5B,IAAA,IAAA,CAAK,kBAAA,GAAqB,CAAA;AAC1B,IAAA,IAAA,CAAK,eAAA,GAAkB,CAAA;AACvB,IAAA,IAAA,CAAK,aAAA,GAAgB,MAAA;AACrB,IAAA,IAAA,CAAK,aAAA,GAAgB,MAAA;AAAA,EACzB;AAAA;AAAA,EAGA,UAAU,OAAA,EAA8B;AACpC,IAAA,IAAA,CAAK,QAAA,CAAS,IAAI,OAAO,CAAA;AACzB,IAAA,KAAK,OAAA,CAAQ,QAAQ,MAAM;AACvB,MAAA,IAAA,CAAK,QAAA,CAAS,OAAO,OAAO,CAAA;AAAA,IAChC,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGA,cAAc,OAAA,EAA8B;AACxC,IAAA,IAAA,CAAK,gBAAA,CAAiB,IAAI,OAAO,CAAA;AACjC,IAAA,KAAK,OAAA,CAAQ,QAAQ,MAAM;AACvB,MAAA,IAAA,CAAK,gBAAA,CAAiB,OAAO,OAAO,CAAA;AAAA,IACxC,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGA,qBAAA,GAA8B;AAC1B,IAAA,IAAA,CAAK,kBAAA,EAAA;AAAA,EACT;AAAA;AAAA,EAGA,mBAAA,GAA4B;AACxB,IAAA,IAAA,CAAK,eAAA,EAAA;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,oBAAA,GAAsC;AACxC,IAAA,IAAI,IAAA,CAAK,gBAAA,CAAiB,IAAA,GAAO,CAAA,EAAG;AAChC,MAAA,MAAM,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,gBAAgB,CAAA;AAAA,IAC3C;AAAA,EACJ;AAAA;AAAA,EAGA,IAAI,iBAAA,GAA4B;AAC5B,IAAA,OAAO,IAAA,CAAK,kBAAA;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,cAAA,GAAyB;AACzB,IAAA,OAAO,IAAA,CAAK,eAAA;AAAA,EAChB;AAAA;AAAA,EAGA,UAAA,CAAW,UAAkB,IAAA,EAAoB;AAC7C,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,QAAQ,CAAA;AACzB,IAAA,IAAA,CAAK,UAAA,CAAW,KAAK,IAAI,CAAA;AAAA,EAC7B;AAAA;AAAA,EAGA,MAAM,iBAAA,GAAmC;AACrC,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,IAAA,GAAO,CAAA,EAAG;AACxB,MAAA,MAAM,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,QAAQ,CAAA;AAAA,IACnC;AAAA,EACJ;AAAA;AAAA,EAGA,cAAc,IAAA,EAAoB;AAC9B,IAAA,IAAI,IAAA,CAAK,YAAA,CAAa,MAAA,GAAS,gCAAA,EAAkC;AAC7D,MAAA,IAAA,CAAK,YAAA,CAAa,KAAK,IAAI,CAAA;AAAA,IAC/B;AAAA,EACJ;AAAA;AAAA,EAGA,UAAA,CAAW,QAAoB,MAAA,EAA0B;AACrD,IAAA,IAAA,CAAK,aAAA,GAAgB,MAAA;AACrB,IAAA,IAAA,CAAK,aAAA,GAAgB,MAAA;AAAA,EACzB;AAAA;AAAA,EAGA,cAAA,GAAuB;AACnB,IAAA,IAAI,KAAK,aAAA,KAAkB,MAAA,IAAa,CAAC,IAAA,CAAK,cAAc,SAAA,EAAW;AACnE,MAAA,IAAA,CAAK,cAAc,OAAA,EAAQ;AAAA,IAC/B;AACA,IAAA,IAAI,KAAK,aAAA,KAAkB,MAAA,IAAa,CAAC,IAAA,CAAK,cAAc,SAAA,EAAW;AACnE,MAAA,IAAA,CAAK,cAAc,OAAA,EAAQ;AAAA,IAC/B;AAAA,EACJ;AACJ,CAAA;AAOA,SAAS,YAAA,GAAwC;AAC7C,EAAA,OAAO,IAAI,QAAQ,CAAA,OAAA,KAAW;AAC1B,IAAA,MAAM,SAAa,GAAA,CAAA,YAAA,EAAa;AAChC,IAAA,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,WAAA,EAAa,MAAM;AAChC,MAAA,MAAM,IAAA,GAAO,OAAO,OAAA,EAAQ;AAC5B,MAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,EAAU;AAC3C,QAAA,MAAA,CAAO,KAAA,CAAM,MAAM,OAAA,CAAQ,GAAA,CAAI,IAAI,KAAA,CAAM,yBAAyB,CAAC,CAAC,CAAC,CAAA;AACrE,QAAA;AAAA,MACJ;AACA,MAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAClB,MAAA,MAAA,CAAO,MAAM,MAAM,OAAA,CAAQ,EAAA,CAAG,IAAI,CAAC,CAAC,CAAA;AAAA,IACxC,CAAC,CAAA;AACD,IAAA,MAAA,CAAO,EAAA,CAAG,SAAS,CAAA,CAAA,KAAK;AACpB,MAAA,OAAA,CAAQ,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,EAAE,OAAO,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,IAClE,CAAC,CAAA;AAAA,EACL,CAAC,CAAA;AACL;AAOA,SAAS,SAAS,GAAA,EAAgC;AAC9C,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,QAAQ,CAAA,EAAA,EAAK;AACjC,IAAA,KAAA,IAAS,GAAA,CAAI,CAAC,CAAA,IAAK,CAAA;AAAA,EACvB;AACA,EAAA,OAAO,KAAA;AACX;AA8BA,IAAM,aAAA,GAAN,MAAM,cAAA,SAAsBP,YAAAA,CAAoC;AAAA,EAcpD,YAAY,OAAA,EAA+B;AAC/C,IAAA,KAAA,EAAM;AAdV,IAAA,aAAA,CAAA,IAAA,EAAiB,SAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAiB,aAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAiB,aAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAiB,qBAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAiB,6BAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAiB,gBAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAiB,SAAA,sBAAmC,GAAA,EAAI,CAAA;AACxD,IAAA,aAAA,CAAA,IAAA,EAAQ,WAAA,CAAA;AACR,IAAA,aAAA,CAAA,IAAA,EAAQ,oBAAA,EAAqB,CAAA,CAAA;AAC7B,IAAA,aAAA,CAAA,IAAA,EAAQ,SAAA,EAAU,KAAA,CAAA;AAClB,IAAA,aAAA,CAAA,IAAA,EAAQ,UAAA,EAAW,KAAA,CAAA;AACnB,IAAA,aAAA,CAAA,IAAA,EAAQ,cAAA,CAAA;AAIJ,IAAA,IAAA,CAAK,gBAAgB,EAAE,CAAA;AACvB,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,WAAA,GAAc,QAAQ,WAAA,IAAe,qBAAA;AAC1C,IAAA,IAAA,CAAK,WAAA,GAAc,QAAQ,WAAA,IAAe,qBAAA;AAC1C,IAAA,IAAA,CAAK,mBAAA,GAAsB,QAAQ,mBAAA,IAAuB,6BAAA;AAC1D,IAAA,IAAA,CAAK,8BAA8B,EAAE,eAAA,EAAiB,QAAA,EAAU,GAAG,QAAQ,mBAAA,EAAoB;AAC/F,IAAA,IAAA,CAAK,cAAA,GAAiB,QAAQ,cAAA,IAAkB,IAAA;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAO,OAAO,OAAA,EAAsD;AAChE,IAAA,MAAM,UAAA,GAAa,0BAAA,CAA2B,SAAA,CAAU,OAAO,CAAA;AAC/D,IAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACrB,MAAA,OAAO,GAAA,CAAI,qBAAA,CAAsB,eAAA,EAAiB,UAAA,CAAW,KAAK,CAAC,CAAA;AAAA,IACvE;AACA,IAAA,OAAO,EAAA,CAAG,IAAI,cAAA,CAAc,OAAO,CAAC,CAAA;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KAAA,GAA+B;AACjC,IAAA,IAAI,KAAK,OAAA,EAAS;AACd,MAAA,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,gCAAgC,CAAC,CAAA;AAAA,IAC1D;AACA,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AAEf,IAAA,MAAM,gBAAA,GAAmB,MAAM,eAAA,CAAgB,IAAA,CAAK,QAAQ,UAAU,CAAA;AACtE,IAAA,IAAI,CAAC,gBAAA,CAAiB,EAAA,EAAI,OAAO,gBAAA;AAEjC,IAAA,MAAM,YAAA,GAAe,MAAM,IAAA,CAAK,YAAA,CAAa,KAAK,WAAW,CAAA;AAC7D,IAAA,IAAI,CAAC,YAAA,CAAa,EAAA,EAAI,OAAO,YAAA;AAE7B,IAAA,MAAM,YAAA,GAAe,MAAM,IAAA,CAAK,aAAA,EAAc;AAC9C,IAAA,IAAI,CAAC,YAAA,CAAa,EAAA,EAAI,OAAO,YAAA;AAE7B,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,MAAA,KAAW,MAAA,EAAW;AACnC,MAAA,IAAA,CAAK,eAAA,CAAgB,IAAA,CAAK,OAAA,CAAQ,MAAM,CAAA;AAAA,IAC5C;AAEA,IAAA,OAAO,GAAG,MAAS,CAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAA,GAAsB;AACxB,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,IAAW,IAAA,CAAK,QAAA,EAAU;AAChC,MAAA;AAAA,IACJ;AACA,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAEhB,IAAA,IAAI,KAAK,OAAA,CAAQ,MAAA,KAAW,MAAA,IAAa,IAAA,CAAK,iBAAiB,MAAA,EAAW;AACtE,MAAA,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,mBAAA,CAAoB,OAAA,EAAS,KAAK,YAAY,CAAA;AAAA,IACtE;AAEA,IAAA,MAAM,KAAK,aAAA,EAAc;AAGzB,IAAA,MAAM,KAAK,eAAA,EAAgB;AAE3B,IAAA,MAAM,eAAgC,EAAC;AACvC,IAAA,KAAA,MAAW,MAAA,IAAU,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO,EAAG;AACxC,MAAA,YAAA,CAAa,IAAA,CAAK,IAAA,CAAK,UAAA,CAAW,MAAM,CAAC,CAAA;AAAA,IAC7C;AACA,IAAA,MAAM,OAAA,CAAQ,IAAI,YAAY,CAAA;AAC9B,IAAA,IAAA,CAAK,QAAQ,KAAA,EAAM;AAEnB,IAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AACf,IAAA,IAAA,CAAK,QAAA,GAAW,KAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAA,CAA+C,OAAU,QAAA,EAA6D;AAClH,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,KAAA,EAAO,QAAiB,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,QAAA,EAA0D;AACrE,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,eAAA,EAAiB,QAAQ,CAAA;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,QAAA,EAAwD;AACjE,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,aAAA,EAAe,QAAQ,CAAA;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,mBAAmB,QAAA,EAAsD;AACrE,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,mBAAA,EAAqB,QAAQ,CAAA;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,QAAA,EAA2D;AACvE,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,gBAAA,EAAkB,QAAQ,CAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,sBAAsB,QAAA,EAAyD;AAC3E,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,sBAAA,EAAwB,QAAQ,CAAA;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,uBAAuB,QAAA,EAAkE;AACrF,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,uBAAA,EAAyB,QAAQ,CAAA;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,sBAAsB,QAAA,EAA6D;AAC/E,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,sBAAA,EAAwB,QAAQ,CAAA;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,QAAA,EAAuD;AACnE,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,iBAAA,EAAmB,QAAQ,CAAA;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAc,QAAA,EAAqD;AAC/D,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,cAAA,EAAgB,QAAQ,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,sBAAsB,QAAA,EAA6D;AAC/E,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,sBAAA,EAAwB,QAAQ,CAAA;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,aAAa,MAAA,EAA0B;AACnC,IAAA,IAAI,CAAC,KAAK,OAAA,EAAS;AACf,MAAA,MAAA,CAAO,OAAA,CAAQ,IAAI,KAAA,CAAM,4BAA4B,CAAC,CAAA;AACtD,MAAA;AAAA,IACJ;AACA,IAAA,KAAK,IAAA,CAAK,iBAAiB,MAAM,CAAA;AAAA,EACrC;AAAA;AAAA,EAGA,IAAI,UAAA,GAAyB;AACzB,IAAA,IAAI,IAAA,GAAO,CAAA;AACX,IAAA,IAAI,IAAA,GAAO,CAAA;AACX,IAAA,KAAA,MAAW,CAAA,IAAK,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO,EAAG;AACnC,MAAA,IAAI,CAAA,CAAE,UAAU,MAAA,EAAQ,IAAA,EAAA;AAAA,WACnB,IAAA,EAAA;AAAA,IACT;AACA,IAAA,OAAO,EAAE,IAAA,EAAM,IAAA,EAAM,KAAA,EAAO,IAAA,CAAK,QAAQ,IAAA,EAAK;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,aAAA,GAAuC;AAC3C,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,IAAA,KAAS,CAAA,EAAG;AACzB,MAAA,OAAO,OAAA,CAAQ,OAAA,CAAQ,EAAA,CAAG,MAAS,CAAC,CAAA;AAAA,IACxC;AACA,IAAA,OAAO,IAAI,QAAQ,CAAA,OAAA,KAAW;AAC1B,MAAA,IAAA,CAAK,SAAA,GAAgB,iBAAa,CAAA,MAAA,KAAU;AACxC,QAAA,KAAK,IAAA,CAAK,iBAAiB,MAAM,CAAA;AAAA,MACrC,CAAC,CAAA;AACD,MAAA,IAAA,CAAK,SAAA,CAAU,EAAA,CAAG,OAAA,EAAS,CAAA,CAAA,KAAK;AAC5B,QAAA,IAAI,CAAC,KAAK,OAAA,EAAS;AACf,UAAA,OAAA,CAAQ,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,EAAE,OAAO,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,QAC3E,CAAA,MAAO;AACH,UAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,EAAE,KAAA,EAAO,CAAA,YAAa,KAAA,GAAQ,CAAA,GAAI,IAAI,KAAA,CAAM,MAAA,CAAO,CAAC,CAAC,GAAG,CAAA;AAAA,QAC/E;AAAA,MACJ,CAAC,CAAA;AACD,MAAA,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,IAAA,CAAK,OAAA,CAAQ,MAAM,MAAM;AAC3C,QAAA,OAAA,CAAQ,EAAA,CAAG,MAAS,CAAC,CAAA;AAAA,MACzB,CAAC,CAAA;AAAA,IACL,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,aAAA,GAA+B;AACnC,IAAA,OAAO,IAAI,QAAQ,CAAA,OAAA,KAAW;AAC1B,MAAA,IAAI,IAAA,CAAK,cAAc,MAAA,EAAW;AAC9B,QAAA,OAAA,EAAQ;AACR,QAAA;AAAA,MACJ;AACA,MAAA,IAAA,CAAK,SAAA,CAAU,KAAA,CAAM,MAAM,OAAA,EAAS,CAAA;AAAA,IACxC,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGA,MAAc,eAAA,GAAiC;AAC3C,IAAA,MAAM,gBAAiC,EAAC;AACxC,IAAA,KAAA,MAAW,MAAA,IAAU,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO,EAAG;AACxC,MAAA,IAAI,MAAA,CAAO,UAAU,MAAA,EAAQ;AACzB,QAAA,aAAA,CAAc,IAAA,CAAK,MAAA,CAAO,iBAAA,EAAmB,CAAA;AAC7C,QAAA,aAAA,CAAc,IAAA,CAAK,MAAA,CAAO,oBAAA,EAAsB,CAAA;AAAA,MACpD;AAAA,IACJ;AACA,IAAA,IAAI,aAAA,CAAc,WAAW,CAAA,EAAG;AAChC,IAAA,MAAM,OAAA,CAAQ,IAAA,CAAK,CAAC,OAAA,CAAQ,GAAA,CAAI,aAAa,CAAA,EAAGgB,YAAA,CAAM,GAAI,CAAC,CAAC,CAAA;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,iBAAiB,YAAA,EAAyC;AACpE,IAAA,YAAA,CAAa,KAAA,EAAM;AAEnB,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,cAAA,EAAe;AACzC,IAAA,IAAI,WAAW,MAAA,EAAW;AACtB,MAAA,YAAA,CAAa,OAAA,CAAQ,IAAI,KAAA,CAAM,yCAAyC,CAAC,CAAA;AACzE,MAAA,IAAA,CAAK,IAAA,CAAK,SAAS,EAAE,KAAA,EAAO,IAAI,KAAA,CAAM,0DAAqD,GAAG,CAAA;AAC9F,MAAA;AAAA,IACJ;AAEA,IAAA,IAAA,CAAK,kBAAA,EAAA;AACL,IAAA,MAAM,aAAA,GAAgB,CAAA,MAAA,EAAS,MAAA,CAAO,IAAA,CAAK,kBAAkB,CAAC,CAAA,CAAA;AAC9D,IAAA,MAAM,cAAA,GAAsB,IAAA,CAAA,IAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,YAAY,aAAa,CAAA;AAEvE,IAAA,MAAM,WAAA,GAAc,MAAM,eAAA,CAAgB,cAAc,CAAA;AACxD,IAAA,IAAI,CAAC,YAAY,EAAA,EAAI;AACjB,MAAA,YAAA,CAAa,OAAA,EAAQ;AACrB,MAAA,IAAA,CAAK,KAAK,OAAA,EAAS,EAAE,KAAA,EAAO,WAAA,CAAY,OAAO,CAAA;AAC/C,MAAA;AAAA,IACJ;AAEA,IAAA,MAAM,GAAA,GAA0B;AAAA,MAC5B,aAAA;AAAA,MACA,cAAA;AAAA,MACA,OAAA,EAAS,KAAK,GAAA;AAAI,KACtB;AAEA,IAAA,MAAA,CAAO,iBAAiB,GAAG,CAAA;AAC3B,IAAA,IAAA,CAAK,cAAA,CAAe,QAAQ,YAAY,CAAA;AACxC,IAAA,KAAK,IAAA,CAAK,aAAA,EAAc,CAAE,KAAA,CAAM,CAAC,CAAA,KAAe;AAC5C,MAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,EAAE,KAAA,EAAO,CAAA,YAAa,KAAA,GAAQ,CAAA,GAAI,IAAI,KAAA,CAAM,MAAA,CAAO,CAAC,CAAC,GAAG,CAAA;AAAA,IAC/E,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGA,MAAc,cAAA,GAA8C;AACxD,IAAA,MAAM,IAAA,GAAO,KAAK,aAAA,EAAc;AAChC,IAAA,IAAI,IAAA,KAAS,QAAW,OAAO,IAAA;AAE/B,IAAA,MAAM,UAAA,GAAa,KAAK,GAAA,CAAI,IAAA,CAAK,KAAK,IAAA,CAAK,mBAAA,GAAsB,4BAA4B,CAAA,EAAG,sBAAsB,CAAA;AAEtH,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,UAAA,EAAY,CAAA,EAAA,EAAK;AACjC,MAAA,MAAMA,aAAM,4BAA4B,CAAA;AACxC,MAAA,MAAM,KAAA,GAAQ,KAAK,aAAA,EAAc;AACjC,MAAA,IAAI,KAAA,KAAU,QAAW,OAAO,KAAA;AAChC,MAAA,IAAI,IAAA,CAAK,UAAU,OAAO,MAAA;AAAA,IAC9B;AACA,IAAA,OAAO,MAAA;AAAA,EACX;AAAA;AAAA,EAGQ,aAAA,GAAoC;AACxC,IAAA,KAAA,MAAW,CAAA,IAAK,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO,EAAG;AACnC,MAAA,IAAI,CAAA,CAAE,KAAA,KAAU,MAAA,EAAQ,OAAO,CAAA;AAAA,IACnC;AACA,IAAA,OAAO,MAAA;AAAA,EACX;AAAA;AAAA,EAGQ,cAAA,CAAe,QAAgB,YAAA,EAAgC;AACnE,IAAA,MAAM,YAAA,GAAmB,qBAAiB,EAAE,IAAA,EAAM,OAAO,IAAA,EAAM,IAAA,EAAM,aAAa,CAAA;AAElF,IAAA,MAAA,CAAO,UAAA,CAAW,cAAc,YAAY,CAAA;AAE5C,IAAA,MAAM,UAAU,MAAY;AACxB,MAAA,YAAA,CAAa,OAAO,YAAY,CAAA;AAChC,MAAA,YAAA,CAAa,OAAO,YAAY,CAAA;AAChC,MAAA,IAAI,CAAC,YAAA,CAAa,SAAA,EAAW,YAAA,CAAa,OAAA,EAAQ;AAClD,MAAA,IAAI,CAAC,YAAA,CAAa,SAAA,EAAW,YAAA,CAAa,OAAA,EAAQ;AAAA,IACtD,CAAA;AAMA,IAAA,YAAA,CAAa,EAAA,CAAG,WAAW,MAAM;AAC7B,MAAA,YAAA,CAAa,KAAK,YAAY,CAAA;AAC9B,MAAA,YAAA,CAAa,KAAK,YAAY,CAAA;AAC9B,MAAA,YAAA,CAAa,MAAA,EAAO;AAAA,IACxB,CAAC,CAAA;AAED,IAAA,YAAA,CAAa,EAAA,CAAG,SAAS,OAAO,CAAA;AAChC,IAAA,YAAA,CAAa,EAAA,CAAG,SAAS,OAAO,CAAA;AAChC,IAAA,YAAA,CAAa,EAAA,CAAG,SAAS,OAAO,CAAA;AAChC,IAAA,YAAA,CAAa,EAAA,CAAG,SAAS,OAAO,CAAA;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,aAAa,KAAA,EAAsC;AAC7D,IAAA,MAAM,WAAsC,EAAC;AAC7C,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC5B,MAAA,QAAA,CAAS,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,CAAA;AAAA,IACpC;AACA,IAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AAC1C,IAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC1B,MAAA,IAAI,CAAC,MAAA,CAAO,EAAA,EAAI,OAAO,GAAA,CAAI,OAAO,KAAK,CAAA;AAAA,IAC3C;AACA,IAAA,OAAO,GAAG,MAAS,CAAA;AAAA,EACvB;AAAA;AAAA,EAGQ,aAAA,CAAc,MAAc,OAAA,EAAkC;AAClE,IAAA,OAAO,QAAQ,MAAA,CAAO;AAAA,MAClB,IAAA;AAAA,MACA,OAAA,EAAS,KAAK,OAAA,CAAQ,OAAA;AAAA,MACtB,eAAA,EAAiB,OAAA;AAAA,MACjB,UAAA,EAAY,KAAK,OAAA,CAAQ,UAAA;AAAA,MACzB,aAAA,EAAe,KAAK,OAAA,CAAQ,aAAA;AAAA,MAC5B,WAAA,EAAa,KAAK,OAAA,CAAQ,WAAA;AAAA,MAC1B,YAAA,EAAc,KAAK,OAAA,CAAQ,YAAA;AAAA,MAC3B,MAAA,EAAQ,KAAK,OAAA,CAAQ,MAAA;AAAA,MACrB,YAAA,EAAc,IAAA,CAAK,OAAA,CAAQ,YAAA,IAAgB,QAAA;AAAA,MAC3C,iBAAA,EAAmB,KAAK,OAAA,CAAQ,iBAAA;AAAA,MAChC,WAAA,EAAa,KAAK,OAAA,CAAQ;AAAA,KAC7B,CAAA;AAAA,EACL;AAAA;AAAA,EAGA,MAAc,WAAA,GAAuC;AACjD,IAAA,MAAM,UAAA,GAAa,MAAM,YAAA,EAAa;AACtC,IAAA,IAAI,CAAC,UAAA,CAAW,EAAA,EAAI,OAAO,UAAA;AAC3B,IAAA,MAAM,OAAO,UAAA,CAAW,KAAA;AAExB,IAAA,MAAM,OAAA,GAAe,IAAA,CAAA,IAAA,CAAQ,EAAA,CAAA,MAAA,EAAO,EAAG,gBAAgB,MAAA,CAAO,IAAI,CAAC,CAAA,CAAA,EAAI,MAAA,CAAO,IAAA,CAAK,GAAA,EAAK,CAAC,CAAA,CAAE,CAAA;AAC3F,IAAA,MAAM,WAAA,GAAc,MAAM,eAAA,CAAgB,OAAO,CAAA;AACjD,IAAA,IAAI,CAAC,WAAA,CAAY,EAAA,EAAI,OAAO,WAAA;AAE5B,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,aAAA,CAAc,IAAA,EAAM,OAAO,CAAA;AACrD,IAAA,IAAI,CAAC,YAAA,CAAa,EAAA,EAAI,OAAO,YAAA;AAE7B,IAAA,MAAM,UAAU,YAAA,CAAa,KAAA;AAC7B,IAAA,MAAM,MAAA,GAAS,IAAI,MAAA,CAAO,OAAA,EAAS,MAAM,OAAO,CAAA;AAEhD,IAAA,IAAA,CAAK,iBAAiB,MAAM,CAAA;AAC5B,IAAA,MAAM,WAAA,GAAc,MAAM,OAAA,CAAQ,KAAA,EAAM;AACxC,IAAA,IAAI,CAAC,YAAY,EAAA,EAAI;AACjB,MAAA,OAAO,GAAA,CAAI,IAAI,KAAA,CAAM,CAAA,2CAAA,EAA8C,MAAA,CAAO,IAAI,CAAC,CAAA,EAAA,EAAK,WAAA,CAAY,KAAA,CAAM,OAAO,CAAA,CAAE,CAAC,CAAA;AAAA,IACpH;AAEA,IAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,IAAA,EAAM,MAAM,CAAA;AAC7B,IAAA,OAAO,GAAG,MAAM,CAAA;AAAA,EACpB;AAAA;AAAA,EAGA,MAAc,WAAW,MAAA,EAA+B;AACpD,IAAA,MAAA,CAAO,cAAA,EAAe;AACtB,IAAA,MAAM,MAAA,CAAO,QAAQ,IAAA,EAAK;AAC1B,IAAA,MAAA,CAAO,OAAA,CAAQ,MAAA,CAAO,OAAO,CAAA,EAAE;AAC/B,IAAA,MAAM,aAAA,CAAc,OAAO,OAAO,CAAA;AAClC,IAAA,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,MAAA,CAAO,IAAI,CAAA;AAAA,EACnC;AAAA;AAAA,EAGA,MAAc,aAAA,GAA+B;AACzC,IAAA,MAAM,SAAS,IAAA,CAAK,UAAA;AACpB,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,WAAA,GAAc,MAAA,CAAO,IAAA;AACzC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,WAAA,GAAc,MAAA,CAAO,KAAA;AAC3C,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,QAAQ,CAAA;AAEzC,IAAA,IAAI,WAAW,CAAA,EAAG;AAElB,IAAA,MAAM,WAAsC,EAAC;AAC7C,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,EAAS,CAAA,EAAA,EAAK;AAC9B,MAAA,QAAA,CAAS,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,CAAA;AAAA,IACpC;AACA,IAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AAC1C,IAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC1B,MAAA,IAAI,CAAC,OAAO,EAAA,EAAI;AACZ,QAAA,IAAA,CAAK,KAAK,OAAA,EAAS,EAAE,KAAA,EAAO,MAAA,CAAO,OAAO,CAAA;AAAA,MAC9C;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA,EAGA,MAAc,SAAA,GAA2B;AACrC,IAAA,MAAM,cAAwB,EAAC;AAC/B,IAAA,KAAA,MAAW,CAAA,IAAK,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO,EAAG;AACnC,MAAA,IAAI,CAAA,CAAE,KAAA,KAAU,MAAA,EAAQ,WAAA,CAAY,KAAK,CAAC,CAAA;AAAA,IAC9C;AACA,IAAA,MAAM,MAAA,GAAS,WAAA,CAAY,MAAA,IAAU,IAAA,CAAK,WAAA,GAAc,CAAA,CAAA;AACxD,IAAA,IAAI,UAAU,CAAA,EAAG;AAEjB,IAAA,MAAM,MAAA,GAAS,WAAA,CAAY,KAAA,CAAM,CAAA,EAAG,MAAM,CAAA;AAC1C,IAAA,MAAM,WAA4B,EAAC;AACnC,IAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACpB,MAAA,QAAA,CAAS,IAAA,CAAK,IAAA,CAAK,UAAA,CAAW,CAAC,CAAC,CAAA;AAAA,IACpC;AACA,IAAA,MAAM,OAAA,CAAQ,IAAI,QAAQ,CAAA;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,iBAAiB,MAAA,EAAsB;AAC3C,IAAA,IAAA,CAAK,iBAAiB,MAAM,CAAA;AAC5B,IAAA,IAAA,CAAK,wBAAwB,MAAM,CAAA;AACnC,IAAA,IAAA,CAAK,wBAAwB,MAAM,CAAA;AACnC,IAAA,IAAA,CAAK,kBAAkB,MAAM,CAAA;AAC7B,IAAA,IAAA,CAAK,gBAAgB,MAAM,CAAA;AAC3B,IAAA,IAAA,CAAK,wBAAwB,MAAM,CAAA;AACnC,IAAA,IAAA,CAAK,kBAAkB,MAAM,CAAA;AAAA,EACjC;AAAA;AAAA,EAGQ,iBAAiB,MAAA,EAAsB;AAC3C,IAAA,MAAA,CAAO,OAAA,CAAQ,eAAe,CAAA,IAAA,KAAQ;AAClC,MAAA,MAAM,MAAM,MAAA,CAAO,OAAA;AACnB,MAAA,IAAI,QAAQ,MAAA,EAAW;AACnB,QAAA,IAAA,CAAK,KAAK,OAAA,EAAS;AAAA,UACf,OAAO,IAAI,KAAA,CAAM,CAAA,uEAAA,EAA0E,MAAA,CAAO,KAAK,CAAA,CAAA,CAAG,CAAA;AAAA,UAC1G,UAAU,IAAA,CAAK,QAAA;AAAA,UACf,WAAW,IAAA,CAAK,SAAA;AAAA,UAChB,UAAU,IAAA,CAAK,QAAA;AAAA,UACf,QAAQ,IAAA,CAAK;AAAA,SAChB,CAAA;AACD,QAAA;AAAA,MACJ;AAGA,MAAA,IAAA,CAAK,KAAK,eAAA,EAAiB;AAAA,QACvB,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,eAAe,GAAA,CAAI,aAAA;AAAA,QACnB,WAAW,IAAA,CAAK,SAAA;AAAA,QAChB,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,QAAQ,IAAA,CAAK;AAAA,OAChB,CAAA;AAED,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,kBAAA,CAAmB,MAAA,EAAQ,MAAM,GAAG,CAAA;AACzD,MAAA,MAAA,CAAO,UAAU,OAAO,CAAA;AAAA,IAC5B,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGA,MAAc,kBAAA,CACV,MAAA,EACA,IAAA,EACA,GAAA,EACa;AACb,IAAA,IAAI;AACA,MAAA,MAAM,IAAA,CAAK,eAAA,CAAgB,MAAA,EAAQ,IAAA,EAAM,GAAG,CAAA;AAAA,IAChD,SAAS,MAAA,EAAiB;AACtB,MAAA,MAAM,KAAA,GAAQ,kBAAkB,KAAA,GAAQ,MAAA,GAAS,IAAI,KAAA,CAAM,MAAA,CAAO,MAAM,CAAC,CAAA;AACzE,MAAA,IAAA,CAAK,KAAK,OAAA,EAAS;AAAA,QACf,KAAA;AAAA,QACA,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,eAAe,GAAA,CAAI,aAAA;AAAA,QACnB,gBAAgB,GAAA,CAAI,cAAA;AAAA,QACpB,WAAW,IAAA,CAAK,SAAA;AAAA,QAChB,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,QAAQ,IAAA,CAAK;AAAA,OAChB,CAAA;AAAA,IACL;AAAA,EACJ;AAAA;AAAA,EAGA,MAAc,eAAA,CACV,MAAA,EACA,IAAA,EACA,GAAA,EACa;AACb,IAAA,MAAM,UAAU,IAAA,CAAK,QAAA;AACrB,IAAA,MAAM,WAAgB,IAAA,CAAA,IAAA,CAAK,GAAA,CAAI,cAAA,EAAqB,IAAA,CAAA,QAAA,CAAS,OAAO,CAAC,CAAA;AAErE,IAAA,MAAM,UAAA,GAAa,MAAM,QAAA,CAAS,OAAA,EAAS,QAAQ,CAAA;AACnD,IAAA,MAAM,SAAA,GAAY,UAAA,CAAW,EAAA,GAAK,QAAA,GAAW,OAAA;AAC7C,IAAA,MAAM,QAAA,GAAW,MAAM,YAAA,CAAa,SAAS,CAAA;AAC7C,IAAA,MAAA,CAAO,UAAA,CAAW,WAAW,QAAQ,CAAA;AAGrC,IAAA,IAAA,CAAK,KAAK,aAAA,EAAe;AAAA,MACrB,QAAA,EAAU,SAAA;AAAA,MACV,QAAA;AAAA,MACA,eAAe,GAAA,CAAI,aAAA;AAAA,MACnB,gBAAgB,GAAA,CAAI,cAAA;AAAA,MACpB,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,QAAQ,IAAA,CAAK;AAAA,KAChB,CAAA;AAED,IAAA,IAAI,KAAK,cAAA,EAAgB;AACrB,MAAA,MAAM,WAAA,GAAc;AAAA,QAChB,QAAA,EAAU,SAAA;AAAA,QACV,QAAA;AAAA,QACA,eAAe,GAAA,CAAI,aAAA;AAAA,QACnB,gBAAgB,GAAA,CAAI,cAAA;AAAA,QACpB,WAAW,IAAA,CAAK,SAAA;AAAA,QAChB,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,QAAQ,IAAA,CAAK;AAAA,OACjB;AACA,MAAA,MAAA,CAAO,aAAA,CAAc,IAAA,CAAK,oBAAA,CAAqB,MAAA,EAAQ,WAAW,CAAC,CAAA;AAAA,IACvE;AAAA,EACJ;AAAA;AAAA,EAGA,MAAc,oBAAA,CAAqB,MAAA,EAAgB,GAAA,EAA4C;AAC3F,IAAA,IAAI;AACA,MAAA,MAAM,aAAa,MAAM,aAAA,CAAc,KAAK,GAAA,CAAI,QAAA,EAAU,KAAK,2BAA2B,CAAA;AAC1F,MAAA,IAAI,CAAC,WAAW,EAAA,EAAI;AAChB,QAAA,MAAA,CAAO,mBAAA,EAAoB;AAC3B,QAAA,IAAA,CAAK,IAAA,CAAK,gBAAA,EAAkB,EAAE,KAAA,EAAO,UAAA,CAAW,OAAO,MAAA,EAAQ,KAAA,EAAO,GAAG,GAAA,EAAK,CAAA;AAC9E,QAAA;AAAA,MACJ;AACA,MAAA,MAAA,CAAO,qBAAA,EAAsB;AAC7B,MAAA,IAAA,CAAK,IAAA,CAAK,qBAAqB,EAAE,GAAG,KAAK,QAAA,EAAU,UAAA,CAAW,OAAO,CAAA;AAAA,IACzE,SAAS,MAAA,EAAiB;AACtB,MAAA,MAAM,KAAA,GAAQ,kBAAkB,KAAA,GAAQ,MAAA,GAAS,IAAI,KAAA,CAAM,MAAA,CAAO,MAAM,CAAC,CAAA;AACzE,MAAA,MAAA,CAAO,mBAAA,EAAoB;AAC3B,MAAA,IAAA,CAAK,IAAA,CAAK,kBAAkB,EAAE,KAAA,EAAO,QAAQ,IAAA,EAAM,GAAG,KAAK,CAAA;AAAA,IAC/D;AAAA,EACJ;AAAA;AAAA,EAGQ,wBAAwB,MAAA,EAAsB;AAClD,IAAA,MAAA,CAAO,OAAA,CAAQ,qBAAA,CAAsB,CAAC,IAAA,KAAkC;AAGpE,MAAA,MAAA,CAAO,cAAA,EAAe;AAKtB,MAAA,YAAA,CAAa,MAAM;AACf,QAAA,KAAK,IAAA,CAAK,mBAAA,CAAoB,MAAA,EAAQ,IAAI,CAAA;AAAA,MAC9C,CAAC,CAAA;AAAA,IACL,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGA,MAAc,mBAAA,CAAoB,MAAA,EAAgB,IAAA,EAA8C;AAC5F,IAAA,MAAM,OAAO,iBAAA,EAAkB;AAC/B,IAAA,IAAA,CAAK,uBAAA,CAAwB,QAAQ,IAAI,CAAA;AAEzC,IAAA,MAAM,OAAO,oBAAA,EAAqB;AAClC,IAAA,IAAA,CAAK,wBAAA,CAAyB,QAAQ,IAAI,CAAA;AAE1C,IAAA,MAAA,CAAO,cAAA,EAAe;AACtB,IAAA,KAAK,KAAK,SAAA,EAAU;AAAA,EACxB;AAAA;AAAA,EAGQ,uBAAA,CAAwB,QAAgB,IAAA,EAAqC;AACjF,IAAA,MAAM,MAAM,MAAA,CAAO,OAAA;AACnB,IAAA,MAAM,OAAA,GAAU,GAAA,EAAK,aAAA,IAAiB,IAAA,CAAK,aAAA;AAC3C,IAAA,MAAM,QAAA,GAAW,KAAK,cAAA,IAAkB,EAAA;AACxC,IAAA,MAAM,OAAA,GAAU,GAAA,EAAK,OAAA,IAAW,IAAA,CAAK,GAAA,EAAI;AACzC,IAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,MAAA,CAAO,KAAK,CAAA;AAC9B,IAAA,MAAM,MAAA,GAAS,CAAC,GAAG,MAAA,CAAO,WAAW,CAAA;AAErC,IAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,EAAI;AACvB,IAAA,MAAM,UAAA,GAAa,QAAA,CAAS,MAAA,CAAO,SAAS,CAAA;AAC5C,IAAA,MAAM,YAAY,KAAA,GAAQ,OAAA;AAC1B,IAAA,MAAM,cAAA,GAAiB,YAAY,CAAA,GAAI,IAAA,CAAK,MAAO,UAAA,GAAa,SAAA,GAAa,GAAI,CAAA,GAAI,CAAA;AAErF,IAAA,IAAA,CAAK,KAAK,sBAAA,EAAwB;AAAA,MAC9B,aAAA,EAAe,OAAA;AAAA,MACf,cAAA,EAAgB,QAAA;AAAA,MAChB,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,KAAA;AAAA,MACA,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,UAAA;AAAA,MACA,cAAA;AAAA,MACA,OAAA;AAAA,MACA,KAAA;AAAA,MACA;AAAA,KACH,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,wBAAA,CAAyB,QAAgB,IAAA,EAAqC;AAClF,IAAA,MAAM,MAAM,MAAA,CAAO,OAAA;AACnB,IAAA,IAAA,CAAK,KAAK,uBAAA,EAAyB;AAAA,MAC/B,aAAA,EAAe,GAAA,EAAK,aAAA,IAAiB,IAAA,CAAK,aAAA;AAAA,MAC1C,cAAA,EAAgB,KAAK,cAAA,IAAkB,EAAA;AAAA,MACvC,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,KAAA,EAAO,CAAC,GAAG,MAAA,CAAO,KAAK,CAAA;AAAA,MACvB,mBAAmB,MAAA,CAAO,iBAAA;AAAA,MAC1B,gBAAgB,MAAA,CAAO;AAAA,KAC1B,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,wBAAwB,MAAA,EAAsB;AAClD,IAAA,MAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,sBAAA,EAAwB,CAAC,IAAA,KAAkE;AAC9G,MAAA,IAAA,CAAK,KAAK,sBAAA,EAAwB;AAAA,QAC9B,aAAA,EAAe,MAAA,CAAO,OAAA,EAAS,aAAA,IAAiB,EAAA;AAAA,QAChD,WAAW,IAAA,CAAK,SAAA;AAAA,QAChB,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,QAAQ,IAAA,CAAK;AAAA,OAChB,CAAA;AAAA,IACL,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,kBAAkB,MAAA,EAAsB;AAC5C,IAAA,MAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,iBAAA,EAAmB,CAAC,IAAA,KAA0B;AACjE,MAAA,IAAA,CAAK,KAAK,iBAAA,EAAmB;AAAA,QACzB,aAAA,EAAe,MAAA,CAAO,OAAA,EAAS,aAAA,IAAiB,EAAA;AAAA,QAChD,KAAK,IAAA,CAAK;AAAA,OACb,CAAA;AAAA,IACL,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,gBAAgB,MAAA,EAAsB;AAC1C,IAAA,MAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,cAAA,EAAgB,MAAM;AACzC,MAAA,IAAA,CAAK,KAAK,cAAA,EAAgB;AAAA,QACtB,aAAA,EAAe,MAAA,CAAO,OAAA,EAAS,aAAA,IAAiB;AAAA,OACnD,CAAA;AAAA,IACL,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,wBAAwB,MAAA,EAAsB;AAClD,IAAA,MAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,sBAAA,EAAwB,CAAC,IAAA,KAA6B;AACzE,MAAA,IAAA,CAAK,KAAK,sBAAA,EAAwB;AAAA,QAC9B,QAAQ,IAAA,CAAK;AAAA,OAChB,CAAA;AAAA,IACL,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,kBAAkB,MAAA,EAAsB;AAC5C,IAAA,MAAA,CAAO,QAAQ,EAAA,CAAG,MAAA,EAAQ,CAAC,EAAE,MAAK,KAAwB;AACtD,MAAA,IAAI,MAAA,CAAO,UAAU,MAAA,EAAQ;AACzB,QAAA,MAAA,CAAO,cAAc,IAAI,CAAA;AAAA,MAC7B;AAAA,IACJ,CAAC,CAAA;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,gBAAgB,MAAA,EAA2B;AAE/C,IAAA,IAAI,OAAO,OAAA,EAAS;AAChB,MAAA,KAAK,KAAK,IAAA,EAAK;AACf,MAAA;AAAA,IACJ;AACA,IAAA,IAAA,CAAK,eAAe,MAAY;AAC5B,MAAA,KAAK,KAAK,IAAA,EAAK;AAAA,IACnB,CAAA;AACA,IAAA,MAAA,CAAO,iBAAiB,OAAA,EAAS,IAAA,CAAK,cAAc,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EACtE;AACJ;;;AC/sCA,IAAM,aAAA,GAAgB;AAAA,EAClB,cAAA,EAAgB,gBAAA;AAAA,EAChB,oBAAA,EAAsB,sBAAA;AAAA,EACtB,wBAAA,EAA0B,0BAAA;AAAA,EAC1B,mBAAA,EAAqB,qBAAA;AAAA,EACrB,mBAAA,EAAqB,qBAAA;AAAA,EACrB,qBAAA,EAAuB,uBAAA;AAAA,EACvB,YAAA,EAAc;AAClB;AAsCA,IAAM,iBAAA,GAA6C;AAAA,EAC/C;AAAA,IACI,OAAO,aAAA,CAAc,cAAA;AAAA,IACrB,OAAA,EAAS,yCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA8B;AAAA,MACtC,SAAA,EAAW,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KAC3B;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,oBAAA;AAAA,IACrB,OAAA,EAAS,yCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAyC;AAAA,MACjD,QAAA,EAAA,CAAW,KAAA,CAAM,CAAC,CAAA,IAAK,IAAI,IAAA;AAAK,KACpC;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,wBAAA;AAAA,IACrB,OAAA,EAAS,oDAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA6C;AAAA,MACrD,UAAA,EAAY,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC;AAAA,KAC/B;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,mBAAA;AAAA,IACrB,OAAA,EAAS,sBAAA;AAAA,IACT,WAAW,MAAM;AAAA,GACrB;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,mBAAA;AAAA,IACrB,OAAA,EAAS,oBAAA;AAAA,IACT,WAAW,MAAM;AAAA,GACrB;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,qBAAA;AAAA,IACrB,OAAA,EAAS,0CAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAyC;AAAA,MACjD,OAAA,EAAS,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACzB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,YAAA;AAAA,IACrB,OAAA,EAAS,0DAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA4B;AAAA,MACpC,OAAA,EAAS,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACzB;AAAA;AAER;AAGA,IAAM,qBAAA,uBAAiD,GAAA,CAAI,CAAC,cAAc,qBAAA,EAAuB,aAAA,CAAc,YAAY,CAAC;;;AC5C5H,IAAM,qBAAA,GAAwBT,EACzB,MAAA,CAAO;AAAA,EACJ,UAAA,EAAYA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,MAAA,CAAO,UAAA,EAAY,EAAE,OAAA,EAAS,uCAAA,EAAyC,CAAA;AAAA,EACrG,SAASA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EACpC,IAAA,EAAMA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EAC3B,QAAA,EAAUA,CAAAA,CAAE,IAAA,CAAK,CAAC,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,OAAA,EAAS,OAAO,CAAC,CAAA,CAAE,QAAA,EAAS;AAAA,EAChF,SAAA,EAAWA,CAAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,MAAA,CAAO,UAAA,EAAY,EAAE,OAAA,EAAS,sCAAA,EAAwC,EAAE,QAAA,EAAS;AAAA,EAC9G,cAAA,EAAgBA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACrD,cAAA,EAAgBA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACrD,MAAA,EAAQA,CAAAA,CAAE,UAAA,CAAW,WAAW,EAAE,QAAA;AACtC,CAAC,EACA,MAAA,EAAO;AAOZ,SAASC,WAAU,OAAA,EAAoC;AACnD,EAAA,MAAM,IAAA,GAAiB,CAAC,WAAA,EAAa,UAAA,EAAY,QAAQ,UAAU,CAAA;AAEnE,EAAA,IAAI,OAAA,CAAQ,YAAY,MAAA,EAAW;AAC/B,IAAA,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,OAAA,CAAQ,OAAO,CAAA;AAAA,EAC1C;AACA,EAAA,IAAI,OAAA,CAAQ,SAAS,IAAA,EAAM;AACvB,IAAA,IAAA,CAAK,KAAK,QAAQ,CAAA;AAAA,EACtB;AACA,EAAA,IAAI,OAAA,CAAQ,aAAa,MAAA,EAAW;AAChC,IAAA,IAAA,CAAK,IAAA,CAAK,aAAA,EAAe,OAAA,CAAQ,QAAQ,CAAA;AAAA,EAC7C;AACA,EAAA,IAAI,OAAA,CAAQ,cAAc,MAAA,EAAW;AACjC,IAAA,IAAA,CAAK,IAAA,CAAK,cAAA,EAAgB,OAAA,CAAQ,SAAS,CAAA;AAAA,EAC/C;AAEA,EAAA,OAAO,IAAA;AACX;AAyBA,IAAM,QAAA,GAAN,MAAM,SAAA,SAAiB,YAAA,CAAa;AAAA,EAKxB,WAAA,CAAY,MAAA,EAA4BF,OAAAA,EAAoB,MAAA,EAAsB;AACtF,IAAA,KAAA,CAAM,MAAM,CAAA;AALhB,IAAA,aAAA,CAAA,IAAA,EAAiB,QAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAQ,aAAA,CAAA;AACR,IAAA,aAAA,CAAA,IAAA,EAAQ,cAAA,CAAA;AAIJ,IAAA,IAAA,CAAK,MAAA,GAASA,OAAAA;AACd,IAAA,IAAA,CAAK,UAAA,EAAW;AAChB,IAAA,IAAI,WAAW,MAAA,EAAW;AACtB,MAAA,IAAA,CAAK,gBAAgB,MAAM,CAAA;AAAA,IAC/B;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,CAAC,MAAA,CAAO,OAAO,CAAA,GAAU;AACrB,IAAA,IAAI,IAAA,CAAK,WAAA,KAAgB,MAAA,IAAa,IAAA,CAAK,iBAAiB,MAAA,EAAW;AACnE,MAAA,IAAA,CAAK,WAAA,CAAY,mBAAA,CAAoB,OAAA,EAAS,IAAA,CAAK,YAAY,CAAA;AAAA,IACnE;AACA,IAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA,EAAE;AAC5B,IAAA,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,EAAE;AAAA,EAC1B;AAAA,EAEA,OAAA,CAA0C,OAAU,QAAA,EAAwD;AACxG,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,KAAA,EAAiB,QAAiB,CAAA;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,QAAA,EAAuE;AACnF,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,gBAAA,EAAkB,QAAQ,CAAA;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,sBAAsB,QAAA,EAA6E;AAC/F,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,sBAAA,EAAwB,QAAQ,CAAA;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OAAO,OAAA,EAA4C;AACtD,IAAA,MAAM,UAAA,GAAa,qBAAA,CAAsB,SAAA,CAAU,OAAO,CAAA;AAC1D,IAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACrB,MAAA,OAAO,GAAA,CAAI,qBAAA,CAAsB,UAAA,EAAY,UAAA,CAAW,KAAK,CAAC,CAAA;AAAA,IAClE;AAEA,IAAA,MAAM,YAAA,GAAe,cAAc,UAAU,CAAA;AAC7C,IAAA,IAAI,CAAC,aAAa,EAAA,EAAI;AAClB,MAAA,OAAO,GAAA,CAAI,aAAa,KAAK,CAAA;AAAA,IACjC;AAEA,IAAA,MAAM,IAAA,GAAOE,WAAU,OAAO,CAAA;AAC9B,IAAA,MAAMF,OAAAA,GAAS,IAAI,UAAA,EAAW;AAC9B,IAAA,KAAA,MAAW,WAAW,iBAAA,EAAmB;AACrC,MAAA,MAAM,SAAA,GAAYA,OAAAA,CAAO,UAAA,CAAW,OAAO,CAAA;AAC3C,MAAA,IAAI,CAAC,UAAU,EAAA,EAAI;AACf,QAAA,OAAO,GAAA,CAAI,UAAU,KAAK,CAAA;AAAA,MAC9B;AAAA,IACJ;AAEA,IAAA,MAAM,MAAA,GAA6B;AAAA,MAC/B,QAAQ,YAAA,CAAa,KAAA;AAAA,MACrB,IAAA;AAAA,MACA,gBAAgB,OAAA,CAAQ,cAAA;AAAA,MACxB,gBAAgB,OAAA,CAAQ,cAAA;AAAA,MACxB,kBAAA,EAAoB,CAAA,IAAA,KAAQ,8BAAA,CAA+B,IAAA,CAAK,IAAI;AAAA,KACxE;AAEA,IAAA,OAAO,GAAG,IAAI,SAAA,CAAS,QAAQA,OAAAA,EAAQ,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,EAC1D;AAAA;AAAA,EAGQ,UAAA,GAAmB;AACvB,IAAA,IAAA,CAAK,EAAA,CAAG,MAAA,EAAQ,CAAC,EAAE,MAAK,KAAM;AAC1B,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,IAAI,CAAA;AAAA,IACzB,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,OAAO,EAAA,CAAG,OAAA,EAAS,CAAC,EAAE,KAAA,EAAO,MAAK,KAAM;AACzC,MAAA,IAAI,qBAAA,CAAsB,GAAA,CAAI,KAAK,CAAA,EAAG;AAClC,QAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,EAAE,KAAA,EAAO,IAAI,KAAA,CAAM,CAAA,OAAA,EAAU,KAAK,CAAA,CAAE,CAAA,EAAG,KAAA,EAAO,IAAA,EAAM,CAAA;AACvE,QAAA,KAAK,KAAK,IAAA,EAAK;AAAA,MACnB;AACA,MAAA,IAAA,CAAK,IAAA,CAAK,OAAO,IAAI,CAAA;AAAA,IACzB,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,gBAAgB,MAAA,EAA2B;AAC/C,IAAA,IAAI,OAAO,OAAA,EAAS;AAChB,MAAA,KAAK,KAAK,IAAA,EAAK;AACf,MAAA;AAAA,IACJ;AACA,IAAA,IAAA,CAAK,WAAA,GAAc,MAAA;AACnB,IAAA,IAAA,CAAK,eAAe,MAAY;AAC5B,MAAA,KAAK,KAAK,IAAA,EAAK;AAAA,IACnB,CAAA;AACA,IAAA,MAAA,CAAO,iBAAiB,OAAA,EAAS,IAAA,CAAK,cAAc,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EACtE;AACJ;;;ACpOA,IAAM,aAAA,GAAgB;AAAA,EAClB,SAAA,EAAW,WAAA;AAAA,EACX,cAAA,EAAgB,gBAAA;AAAA,EAChB,oBAAA,EAAsB,sBAAA;AAAA,EACtB,wBAAA,EAA0B,0BAAA;AAAA,EAC1B,YAAA,EAAc,cAAA;AAAA,EACd,eAAA,EAAiB,iBAAA;AAAA,EACjB,YAAA,EAAc,cAAA;AAAA,EACd,mBAAA,EAAqB,qBAAA;AAAA,EACrB,mBAAA,EAAqB,qBAAA;AAAA,EACrB,qBAAA,EAAuB,uBAAA;AAAA,EACvB,YAAA,EAAc,cAAA;AAAA,EACd,WAAA,EAAa;AACjB;AA2DA,IAAM,iBAAA,GAA6C;AAAA,EAC/C;AAAA,IACI,OAAO,aAAA,CAAc,SAAA;AAAA,IACrB,OAAA,EAAS,mDAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAkC;AAAA,MAC1C,UAAA,EAAY,KAAA,CAAM,CAAC,CAAA,IAAK,EAAA;AAAA,MACxB,IAAA,EAAM,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC;AAAA,KACzB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,cAAA;AAAA,IACrB,OAAA,EAAS,yCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAsC;AAAA,MAC9C,SAAA,EAAW,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KAC3B;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,oBAAA;AAAA,IACrB,OAAA,EAAS,oCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA4C;AAAA,MACpD,QAAA,EAAA,CAAW,KAAA,CAAM,CAAC,CAAA,IAAK,IAAI,IAAA;AAAK,KACpC;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,wBAAA;AAAA,IACrB,OAAA,EAAS,oDAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAgD;AAAA,MACxD,UAAA,EAAY,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC;AAAA,KAC/B;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,YAAA;AAAA,IACrB,OAAA,EAAS,uCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAoC;AAAA,MAC5C,SAAA,EAAW,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC;AAAA,KAC9B;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,eAAA;AAAA,IACrB,OAAA,EAAS,qBAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAsC;AAAA,MAC9C,GAAA,EAAK,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACrB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,YAAA;AAAA,IACrB,OAAA,EAAS,yCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA4B;AAAA,MACpC,QAAA,EAAA,CAAW,KAAA,CAAM,CAAC,CAAA,IAAK,IAAI,IAAA;AAAK,KACpC;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,mBAAA;AAAA,IACrB,OAAA,EAAS,sBAAA;AAAA,IACT,WAAW,MAAM;AAAA,GACrB;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,mBAAA;AAAA,IACrB,OAAA,EAAS,oBAAA;AAAA,IACT,WAAW,MAAM;AAAA,GACrB;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,qBAAA;AAAA,IACrB,OAAA,EAAS,wBAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA4C;AAAA,MACpD,OAAA,EAAS,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACzB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,YAAA;AAAA,IACrB,OAAA,EAAS,iHAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAoC;AAAA,MAC5C,OAAA,EAAS,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACzB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,WAAA;AAAA,IACrB,OAAA,EAAS,4BAAA;AAAA,IACT,WAAW,MAAM;AAAA;AAEzB;AAGA,IAAM,qBAAA,uBAAiD,GAAA,CAAI,CAAC,cAAc,qBAAA,EAAuB,aAAA,CAAc,YAAY,CAAC;;;AClG5H,IAAM,qBAAA,GAAwBC,EACzB,MAAA,CAAO;AAAA,EACJ,UAAA,EAAYA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,MAAA,CAAO,UAAA,EAAY,EAAE,OAAA,EAAS,uCAAA,EAAyC,CAAA;AAAA,EACrG,YAAYA,CAAAA,CAAE,MAAA,GAAS,GAAA,CAAI,CAAC,EAAE,QAAA,EAAS;AAAA,EACvC,QAAA,EAAUA,CAAAA,CAAE,IAAA,CAAK,CAAC,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,OAAA,EAAS,OAAO,CAAC,CAAA,CAAE,QAAA,EAAS;AAAA,EAChF,SAAA,EAAWA,CAAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,MAAA,CAAO,UAAA,EAAY,EAAE,OAAA,EAAS,sCAAA,EAAwC,EAAE,QAAA,EAAS;AAAA,EAC9G,cAAA,EAAgBA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACrD,cAAA,EAAgBA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACrD,MAAA,EAAQA,CAAAA,CAAE,UAAA,CAAW,WAAW,EAAE,QAAA;AACtC,CAAC,EACA,MAAA,EAAO;AAOZ,SAASC,WAAU,OAAA,EAAoC;AACnD,EAAA,MAAM,IAAA,GAAiB,CAAC,WAAW,CAAA;AAEnC,EAAA,IAAI,OAAA,CAAQ,aAAa,MAAA,EAAW;AAChC,IAAA,IAAA,CAAK,IAAA,CAAK,aAAA,EAAe,OAAA,CAAQ,QAAQ,CAAA;AAAA,EAC7C;AACA,EAAA,IAAI,OAAA,CAAQ,cAAc,MAAA,EAAW;AACjC,IAAA,IAAA,CAAK,IAAA,CAAK,cAAA,EAAgB,OAAA,CAAQ,SAAS,CAAA;AAAA,EAC/C;AAEA,EAAA,IAAA,CAAK,IAAA,CAAK,QAAQ,UAAU,CAAA;AAE5B,EAAA,IAAI,OAAA,CAAQ,eAAe,MAAA,EAAW;AAClC,IAAA,IAAA,CAAK,IAAA,CAAK,QAAQ,UAAU,CAAA;AAAA,EAChC;AAEA,EAAA,OAAO,IAAA;AACX;AAyBA,IAAM,QAAA,GAAN,MAAM,SAAA,SAAiB,YAAA,CAAa;AAAA,EAKxB,WAAA,CAAY,MAAA,EAA4BF,OAAAA,EAAoB,MAAA,EAAsB;AACtF,IAAA,KAAA,CAAM,MAAM,CAAA;AALhB,IAAA,aAAA,CAAA,IAAA,EAAiB,QAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAQ,aAAA,CAAA;AACR,IAAA,aAAA,CAAA,IAAA,EAAQ,cAAA,CAAA;AAIJ,IAAA,IAAA,CAAK,MAAA,GAASA,OAAAA;AACd,IAAA,IAAA,CAAK,UAAA,EAAW;AAChB,IAAA,IAAI,WAAW,MAAA,EAAW;AACtB,MAAA,IAAA,CAAK,gBAAgB,MAAM,CAAA;AAAA,IAC/B;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,CAAC,MAAA,CAAO,OAAO,CAAA,GAAU;AACrB,IAAA,IAAI,IAAA,CAAK,WAAA,KAAgB,MAAA,IAAa,IAAA,CAAK,iBAAiB,MAAA,EAAW;AACnE,MAAA,IAAA,CAAK,WAAA,CAAY,mBAAA,CAAoB,OAAA,EAAS,IAAA,CAAK,YAAY,CAAA;AAAA,IACnE;AACA,IAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA,EAAE;AAC5B,IAAA,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,EAAE;AAAA,EAC1B;AAAA,EAEA,OAAA,CAA0C,OAAU,QAAA,EAAwD;AACxG,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,KAAA,EAAiB,QAAiB,CAAA;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,QAAA,EAAkE;AAC1E,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,WAAA,EAAa,QAAQ,CAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,QAAA,EAAwE;AACpF,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,iBAAA,EAAmB,QAAQ,CAAA;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OAAO,OAAA,EAA4C;AACtD,IAAA,MAAM,UAAA,GAAa,qBAAA,CAAsB,SAAA,CAAU,OAAO,CAAA;AAC1D,IAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACrB,MAAA,OAAO,GAAA,CAAI,qBAAA,CAAsB,UAAA,EAAY,UAAA,CAAW,KAAK,CAAC,CAAA;AAAA,IAClE;AAEA,IAAA,MAAM,YAAA,GAAe,cAAc,UAAU,CAAA;AAC7C,IAAA,IAAI,CAAC,aAAa,EAAA,EAAI;AAClB,MAAA,OAAO,GAAA,CAAI,aAAa,KAAK,CAAA;AAAA,IACjC;AAEA,IAAA,MAAM,IAAA,GAAOE,WAAU,OAAO,CAAA;AAC9B,IAAA,MAAMF,OAAAA,GAAS,IAAI,UAAA,EAAW;AAC9B,IAAA,KAAA,MAAW,WAAW,iBAAA,EAAmB;AACrC,MAAA,MAAM,SAAA,GAAYA,OAAAA,CAAO,UAAA,CAAW,OAAO,CAAA;AAC3C,MAAA,IAAI,CAAC,UAAU,EAAA,EAAI;AACf,QAAA,OAAO,GAAA,CAAI,UAAU,KAAK,CAAA;AAAA,MAC9B;AAAA,IACJ;AAEA,IAAA,MAAM,MAAA,GAA6B;AAAA,MAC/B,QAAQ,YAAA,CAAa,KAAA;AAAA,MACrB,IAAA;AAAA,MACA,gBAAgB,OAAA,CAAQ,cAAA;AAAA,MACxB,gBAAgB,OAAA,CAAQ,cAAA;AAAA,MACxB,kBAAA,EAAoB,CAAA,IAAA,KAAQ,2BAAA,CAA4B,IAAA,CAAK,IAAI;AAAA,KACrE;AAEA,IAAA,OAAO,GAAG,IAAI,SAAA,CAAS,QAAQA,OAAAA,EAAQ,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,EAC1D;AAAA;AAAA,EAGQ,UAAA,GAAmB;AACvB,IAAA,IAAA,CAAK,EAAA,CAAG,MAAA,EAAQ,CAAC,EAAE,MAAK,KAAM;AAC1B,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,IAAI,CAAA;AAAA,IACzB,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,OAAO,EAAA,CAAG,OAAA,EAAS,CAAC,EAAE,KAAA,EAAO,MAAK,KAAM;AACzC,MAAA,IAAI,qBAAA,CAAsB,GAAA,CAAI,KAAK,CAAA,EAAG;AAClC,QAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,EAAE,KAAA,EAAO,IAAI,KAAA,CAAM,CAAA,OAAA,EAAU,KAAK,CAAA,CAAE,CAAA,EAAG,KAAA,EAAO,IAAA,EAAM,CAAA;AACvE,QAAA,KAAK,KAAK,IAAA,EAAK;AAAA,MACnB;AACA,MAAA,IAAA,CAAK,IAAA,CAAK,OAAO,IAAI,CAAA;AAAA,IACzB,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,gBAAgB,MAAA,EAA2B;AAC/C,IAAA,IAAI,OAAO,OAAA,EAAS;AAChB,MAAA,KAAK,KAAK,IAAA,EAAK;AACf,MAAA;AAAA,IACJ;AACA,IAAA,IAAA,CAAK,WAAA,GAAc,MAAA;AACnB,IAAA,IAAA,CAAK,eAAe,MAAY;AAC5B,MAAA,KAAK,KAAK,IAAA,EAAK;AAAA,IACnB,CAAA;AACA,IAAA,MAAA,CAAO,iBAAiB,OAAA,EAAS,IAAA,CAAK,cAAc,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EACtE;AACJ;;;AC3OA,IAAM,aAAA,GAAgB;AAAA,EAClB,SAAA,EAAW,WAAA;AAAA,EACX,oBAAA,EAAsB,sBAAA;AAAA,EACtB,wBAAA,EAA0B,0BAAA;AAAA,EAC1B,cAAA,EAAgB,gBAAA;AAAA,EAChB,cAAA,EAAgB,gBAAA;AAAA,EAChB,aAAA,EAAe,eAAA;AAAA,EACf,eAAA,EAAiB,iBAAA;AAAA,EACjB,mBAAA,EAAqB,qBAAA;AAAA,EACrB,mBAAA,EAAqB,qBAAA;AAAA,EACrB,qBAAA,EAAuB;AAC3B;AAqDA,IAAM,iBAAA,GAA6C;AAAA,EAC/C;AAAA,IACI,OAAO,aAAA,CAAc,SAAA;AAAA,IACrB,OAAA,EAAS,iCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA4B;AAAA,MACpC,IAAA,EAAM,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC;AAAA,KACzB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,oBAAA;AAAA,IACrB,OAAA,EAAS,wCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAsC;AAAA,MAC9C,QAAA,EAAA,CAAW,KAAA,CAAM,CAAC,CAAA,IAAK,IAAI,IAAA;AAAK,KACpC;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,wBAAA;AAAA,IACrB,OAAA,EAAS,oDAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA0C;AAAA,MAClD,UAAA,EAAY,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC;AAAA,KAC/B;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,cAAA;AAAA,IACrB,OAAA,EAAS,iCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA+B;AAAA,MACvC,GAAA,EAAK,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACrB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,cAAA;AAAA,IACrB,OAAA,EAAS,iCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA+B;AAAA,MACvC,GAAA,EAAK,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACrB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,aAAA;AAAA,IACrB,OAAA,EAAS,gCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA8B;AAAA,MACtC,GAAA,EAAK,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACrB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,eAAA;AAAA,IACrB,OAAA,EAAS,kCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAgC;AAAA,MACxC,GAAA,EAAK,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACrB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,mBAAA;AAAA,IACrB,OAAA,EAAS,sBAAA;AAAA,IACT,WAAW,MAAM;AAAA,GACrB;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,mBAAA;AAAA,IACrB,OAAA,EAAS,oBAAA;AAAA,IACT,WAAW,MAAM;AAAA,GACrB;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,qBAAA;AAAA,IACrB,OAAA,EAAS,0CAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAsC;AAAA,MAC9C,OAAA,EAAS,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACzB;AAAA;AAER;AAGA,IAAM,wCAA6C,IAAI,GAAA,CAAI,CAAC,aAAA,CAAc,qBAAqB,CAAC;;;AClEhG,IAAM,qBAAA,GAAwBC,EACzB,MAAA,CAAO;AAAA,EACJ,UAAA,EAAYA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,MAAA,CAAO,UAAA,EAAY,EAAE,OAAA,EAAS,uCAAA,EAAyC,CAAA;AAAA,EACrG,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA,CAAE,QAAA,EAAS;AAAA,EAClD,aAAA,EAAeA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACpC,SAAA,EAAWA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EAChC,SAAA,EAAWA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EAChC,UAAA,EAAYA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACjC,MAAA,EAAQA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI,CAAE,GAAA,CAAI,IAAI,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA,CAAE,QAAA,EAAS;AAAA,EACxD,WAAA,EAAaA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EAClD,YAAA,EAAcA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACnD,OAAA,EAASA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EAC9B,cAAA,EAAgBA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACrD,cAAA,EAAgBA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACrD,MAAA,EAAQA,CAAAA,CAAE,UAAA,CAAW,WAAW,EAAE,QAAA;AACtC,CAAC,EACA,MAAA,EAAO;AAOZ,SAASC,WAAU,OAAA,EAAoC;AACnD,EAAA,MAAM,OAAiB,EAAC;AAExB,EAAA,IAAI,OAAA,CAAQ,YAAY,KAAA,EAAO;AAC3B,IAAA,IAAA,CAAK,KAAK,WAAW,CAAA;AAAA,EACzB;AAEA,EAAA,IAAA,CAAK,IAAA,CAAK,UAAA,EAAY,OAAA,CAAQ,UAAU,CAAA;AAExC,EAAA,IAAI,OAAA,CAAQ,kBAAkB,IAAA,EAAM;AAChC,IAAA,IAAA,CAAK,KAAK,IAAI,CAAA;AAAA,EAClB;AACA,EAAA,IAAI,OAAA,CAAQ,cAAc,IAAA,EAAM;AAC5B,IAAA,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,EACnB;AACA,EAAA,IAAI,OAAA,CAAQ,cAAc,IAAA,EAAM;AAC5B,IAAA,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,EACnB;AACA,EAAA,IAAI,OAAA,CAAQ,eAAe,IAAA,EAAM;AAC7B,IAAA,IAAA,CAAK,KAAK,eAAe,CAAA;AAAA,EAC7B;AAEA,EAAAS,iBAAAA,CAAiB,MAAM,OAAO,CAAA;AAE9B,EAAA,IAAI,OAAA,CAAQ,SAAS,MAAA,EAAW;AAC5B,IAAA,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAC,CAAA;AAAA,EAClC;AAEA,EAAA,OAAO,IAAA;AACX;AAGA,SAASA,iBAAAA,CAAiB,MAAgB,OAAA,EAAgC;AACtE,EAAA,IAAI,OAAA,CAAQ,WAAW,MAAA,EAAW;AAC9B,IAAA,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,EACjD;AACA,EAAA,IAAI,OAAA,CAAQ,gBAAgB,MAAA,EAAW;AACnC,IAAA,IAAA,CAAK,IAAA,CAAK,gBAAA,EAAkB,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAC,CAAA;AAAA,EAC3D;AACA,EAAA,IAAI,OAAA,CAAQ,iBAAiB,MAAA,EAAW;AACpC,IAAA,IAAA,CAAK,IAAA,CAAK,iBAAA,EAAmB,MAAA,CAAO,OAAA,CAAQ,YAAY,CAAC,CAAA;AAAA,EAC7D;AACJ;AAsBA,IAAM,QAAA,GAAN,MAAM,SAAA,SAAiB,YAAA,CAAa;AAAA,EAKxB,WAAA,CAAY,MAAA,EAA4BX,OAAAA,EAAoB,MAAA,EAAsB;AACtF,IAAA,KAAA,CAAM,MAAM,CAAA;AALhB,IAAA,aAAA,CAAA,IAAA,EAAiB,QAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAQ,aAAA,CAAA;AACR,IAAA,aAAA,CAAA,IAAA,EAAQ,cAAA,CAAA;AAIJ,IAAA,IAAA,CAAK,MAAA,GAASA,OAAAA;AACd,IAAA,IAAA,CAAK,UAAA,EAAW;AAChB,IAAA,IAAI,WAAW,MAAA,EAAW;AACtB,MAAA,IAAA,CAAK,gBAAgB,MAAM,CAAA;AAAA,IAC/B;AAAA,EACJ;AAAA;AAAA,EAGA,CAAC,MAAA,CAAO,OAAO,CAAA,GAAU;AACrB,IAAA,IAAI,IAAA,CAAK,WAAA,KAAgB,MAAA,IAAa,IAAA,CAAK,iBAAiB,MAAA,EAAW;AACnE,MAAA,IAAA,CAAK,WAAA,CAAY,mBAAA,CAAoB,OAAA,EAAS,IAAA,CAAK,YAAY,CAAA;AAAA,IACnE;AACA,IAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA,EAAE;AAC5B,IAAA,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,EAAE;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAA,CAA0C,OAAU,QAAA,EAAwD;AACxG,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,KAAA,EAAiB,QAAiB,CAAA;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,QAAA,EAAuE;AAClF,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,gBAAA,EAAkB,QAAQ,CAAA;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,QAAA,EAAuE;AAClF,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,gBAAA,EAAkB,QAAQ,CAAA;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OAAO,OAAA,EAA4C;AACtD,IAAA,MAAM,UAAA,GAAa,qBAAA,CAAsB,SAAA,CAAU,OAAO,CAAA;AAC1D,IAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACrB,MAAA,OAAO,GAAA,CAAI,qBAAA,CAAsB,UAAA,EAAY,UAAA,CAAW,KAAK,CAAC,CAAA;AAAA,IAClE;AAEA,IAAA,MAAM,YAAA,GAAe,cAAc,UAAU,CAAA;AAC7C,IAAA,IAAI,CAAC,aAAa,EAAA,EAAI;AAClB,MAAA,OAAO,GAAA,CAAI,aAAa,KAAK,CAAA;AAAA,IACjC;AAEA,IAAA,MAAM,IAAA,GAAOE,WAAU,OAAO,CAAA;AAC9B,IAAA,MAAMF,OAAAA,GAAS,IAAI,UAAA,EAAW;AAC9B,IAAA,KAAA,MAAW,WAAW,iBAAA,EAAmB;AACrC,MAAA,MAAM,SAAA,GAAYA,OAAAA,CAAO,UAAA,CAAW,OAAO,CAAA;AAC3C,MAAA,IAAI,CAAC,UAAU,EAAA,EAAI;AACf,QAAA,OAAO,GAAA,CAAI,UAAU,KAAK,CAAA;AAAA,MAC9B;AAAA,IACJ;AAKA,IAAA,MAAM,MAAA,GAA6B;AAAA,MAC/B,QAAQ,YAAA,CAAa,KAAA;AAAA,MACrB,IAAA;AAAA,MACA,gBAAgB,OAAA,CAAQ,cAAA;AAAA,MACxB,gBAAgB,OAAA,CAAQ;AAAA,KAC5B;AAEA,IAAA,OAAO,GAAG,IAAI,SAAA,CAAS,QAAQA,OAAAA,EAAQ,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,EAC1D;AAAA;AAAA,EAGQ,UAAA,GAAmB;AACvB,IAAA,IAAA,CAAK,EAAA,CAAG,MAAA,EAAQ,CAAC,EAAE,MAAK,KAAM;AAC1B,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,IAAI,CAAA;AAAA,IACzB,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,OAAO,EAAA,CAAG,OAAA,EAAS,CAAC,EAAE,KAAA,EAAO,MAAK,KAAM;AACzC,MAAA,IAAI,qBAAA,CAAsB,GAAA,CAAI,KAAK,CAAA,EAAG;AAClC,QAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,EAAE,KAAA,EAAO,IAAI,KAAA,CAAM,CAAA,OAAA,EAAU,KAAK,CAAA,CAAE,CAAA,EAAG,KAAA,EAAO,IAAA,EAAM,CAAA;AACvE,QAAA,KAAK,KAAK,IAAA,EAAK;AAAA,MACnB;AACA,MAAA,IAAA,CAAK,IAAA,CAAK,OAAO,IAAI,CAAA;AAAA,IACzB,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,gBAAgB,MAAA,EAA2B;AAC/C,IAAA,IAAI,OAAO,OAAA,EAAS;AAChB,MAAA,KAAK,KAAK,IAAA,EAAK;AACf,MAAA;AAAA,IACJ;AACA,IAAA,IAAA,CAAK,WAAA,GAAc,MAAA;AACnB,IAAA,IAAA,CAAK,eAAe,MAAY;AAC5B,MAAA,KAAK,KAAK,IAAA,EAAK;AAAA,IACnB,CAAA;AACA,IAAA,MAAA,CAAO,iBAAiB,OAAA,EAAS,IAAA,CAAK,cAAc,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EACtE;AACJ;;;ACnRA,IAAM,aAAA,GAAgB;AAAA,EAClB,SAAA,EAAW,WAAA;AAAA,EACX,oBAAA,EAAsB,sBAAA;AAAA,EACtB,wBAAA,EAA0B,0BAAA;AAAA,EAC1B,cAAA,EAAgB,gBAAA;AAAA,EAChB,mBAAA,EAAqB,qBAAA;AAAA,EACrB,mBAAA,EAAqB,qBAAA;AAAA,EACrB,YAAA,EAAc,cAAA;AAAA,EACd,qBAAA,EAAuB;AAC3B;AAsCA,IAAM,iBAAA,GAA6C;AAAA,EAC/C;AAAA,IACI,OAAO,aAAA,CAAc,SAAA;AAAA,IACrB,OAAA,EAAS,iCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA6B;AAAA,MACrC,IAAA,EAAM,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC;AAAA,KACzB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,oBAAA;AAAA,IACrB,OAAA,EAAS,wCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAuC;AAAA,MAC/C,QAAA,EAAA,CAAW,KAAA,CAAM,CAAC,CAAA,IAAK,IAAI,IAAA;AAAK,KACpC;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,wBAAA;AAAA,IACrB,OAAA,EAAS,oDAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAA2C;AAAA,MACnD,UAAA,EAAY,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC;AAAA,KAC/B;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,cAAA;AAAA,IACrB,OAAA,EAAS,mCAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAgC;AAAA,MACxC,GAAA,EAAK,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACrB;AAAA,GACJ;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,mBAAA;AAAA,IACrB,OAAA,EAAS,sBAAA;AAAA,IACT,WAAW,MAAM;AAAA,GACrB;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,mBAAA;AAAA,IACrB,OAAA,EAAS,oBAAA;AAAA,IACT,WAAW,MAAM;AAAA,GACrB;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,YAAA;AAAA,IACrB,OAAA,EAAS,mCAAA;AAAA,IACT,WAAW,MAAM;AAAA,GACrB;AAAA,EACA;AAAA,IACI,OAAO,aAAA,CAAc,qBAAA;AAAA,IACrB,OAAA,EAAS,0CAAA;AAAA,IACT,SAAA,EAAW,CAAC,KAAA,MAAuC;AAAA,MAC/C,OAAA,EAAS,KAAA,CAAM,CAAC,CAAA,IAAK;AAAA,KACzB;AAAA;AAER;AAGA,IAAM,wCAA6C,IAAI,GAAA,CAAI,CAAC,aAAA,CAAc,qBAAqB,CAAC;;;AC1ChG,IAAM,qBAAA,GAAwBC,EACzB,MAAA,CAAO;AAAA,EACJ,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA;AAAA,EACvC,iBAAA,EAAmBA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,MAAA,CAAO,UAAA,EAAY,EAAE,OAAA,EAAS,8CAAA,EAAgD,CAAA;AAAA,EACnH,mBAAA,EAAqBA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EAC1C,MAAA,EAAQA,CAAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI,CAAE,GAAA,CAAI,IAAI,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA,CAAE,QAAA,EAAS;AAAA,EACxD,WAAA,EAAaA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EAClD,YAAA,EAAcA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACnD,eAAA,EAAiBA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACtD,OAAA,EAASA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EAC9B,cAAA,EAAgBA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACrD,cAAA,EAAgBA,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EACrD,MAAA,EAAQA,CAAAA,CAAE,UAAA,CAAW,WAAW,EAAE,QAAA;AACtC,CAAC,EACA,MAAA,EAAO;AAOZ,SAASC,WAAU,OAAA,EAAoC;AACnD,EAAA,MAAM,OAAiB,EAAC;AAExB,EAAA,IAAI,OAAA,CAAQ,YAAY,KAAA,EAAO;AAC3B,IAAA,IAAA,CAAK,KAAK,WAAW,CAAA;AAAA,EACzB;AAEA,EAAA,IAAA,CAAK,IAAA,CAAK,MAAA,EAAQ,OAAA,CAAQ,iBAAiB,CAAA;AAE3C,EAAA,IAAI,OAAA,CAAQ,wBAAwB,KAAA,EAAO;AACvC,IAAA,IAAA,CAAK,KAAK,MAAM,CAAA;AAAA,EACpB,CAAA,MAAO;AACH,IAAA,IAAA,CAAK,KAAK,MAAM,CAAA;AAAA,EACpB;AAEA,EAAAS,iBAAAA,CAAiB,MAAM,OAAO,CAAA;AAE9B,EAAA,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAC,CAAA;AAE9B,EAAA,OAAO,IAAA;AACX;AAGA,SAASA,iBAAAA,CAAiB,MAAgB,OAAA,EAAgC;AACtE,EAAA,IAAI,OAAA,CAAQ,WAAW,MAAA,EAAW;AAC9B,IAAA,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,EACjD;AACA,EAAA,IAAI,OAAA,CAAQ,gBAAgB,MAAA,EAAW;AACnC,IAAA,IAAA,CAAK,IAAA,CAAK,gBAAA,EAAkB,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAC,CAAA;AAAA,EAC3D;AACA,EAAA,IAAI,OAAA,CAAQ,iBAAiB,MAAA,EAAW;AACpC,IAAA,IAAA,CAAK,IAAA,CAAK,iBAAA,EAAmB,MAAA,CAAO,OAAA,CAAQ,YAAY,CAAC,CAAA;AAAA,EAC7D;AACA,EAAA,IAAI,OAAA,CAAQ,oBAAoB,MAAA,EAAW;AACvC,IAAA,IAAA,CAAK,IAAA,CAAK,oBAAA,EAAsB,MAAA,CAAO,OAAA,CAAQ,eAAe,CAAC,CAAA;AAAA,EACnE;AACJ;AAyBA,IAAM,QAAA,GAAN,MAAM,SAAA,SAAiB,YAAA,CAAa;AAAA,EAKxB,WAAA,CAAY,MAAA,EAA4BX,OAAAA,EAAoB,MAAA,EAAsB;AACtF,IAAA,KAAA,CAAM,MAAM,CAAA;AALhB,IAAA,aAAA,CAAA,IAAA,EAAiB,QAAA,CAAA;AACjB,IAAA,aAAA,CAAA,IAAA,EAAQ,aAAA,CAAA;AACR,IAAA,aAAA,CAAA,IAAA,EAAQ,cAAA,CAAA;AAIJ,IAAA,IAAA,CAAK,MAAA,GAASA,OAAAA;AACd,IAAA,IAAA,CAAK,UAAA,EAAW;AAChB,IAAA,IAAI,WAAW,MAAA,EAAW;AACtB,MAAA,IAAA,CAAK,gBAAgB,MAAM,CAAA;AAAA,IAC/B;AAAA,EACJ;AAAA;AAAA,EAGA,CAAC,MAAA,CAAO,OAAO,CAAA,GAAU;AACrB,IAAA,IAAI,IAAA,CAAK,WAAA,KAAgB,MAAA,IAAa,IAAA,CAAK,iBAAiB,MAAA,EAAW;AACnE,MAAA,IAAA,CAAK,WAAA,CAAY,mBAAA,CAAoB,OAAA,EAAS,IAAA,CAAK,YAAY,CAAA;AAAA,IACnE;AACA,IAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA,EAAE;AAC5B,IAAA,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,EAAE;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAA,CAA0C,OAAU,QAAA,EAAwD;AACxG,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,KAAA,EAAiB,QAAiB,CAAA;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,QAAA,EAAuE;AAClF,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,gBAAA,EAAkB,QAAQ,CAAA;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,QAAA,EAAkE;AAC1E,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,WAAA,EAAa,QAAQ,CAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OAAO,OAAA,EAA4C;AACtD,IAAA,MAAM,UAAA,GAAa,qBAAA,CAAsB,SAAA,CAAU,OAAO,CAAA;AAC1D,IAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACrB,MAAA,OAAO,GAAA,CAAI,qBAAA,CAAsB,UAAA,EAAY,UAAA,CAAW,KAAK,CAAC,CAAA;AAAA,IAClE;AAEA,IAAA,MAAM,YAAA,GAAe,cAAc,UAAU,CAAA;AAC7C,IAAA,IAAI,CAAC,aAAa,EAAA,EAAI;AAClB,MAAA,OAAO,GAAA,CAAI,aAAa,KAAK,CAAA;AAAA,IACjC;AAEA,IAAA,MAAM,IAAA,GAAOE,WAAU,OAAO,CAAA;AAC9B,IAAA,MAAMF,OAAAA,GAAS,IAAI,UAAA,EAAW;AAC9B,IAAA,KAAA,MAAW,WAAW,iBAAA,EAAmB;AACrC,MAAA,MAAM,SAAA,GAAYA,OAAAA,CAAO,UAAA,CAAW,OAAO,CAAA;AAC3C,MAAA,IAAI,CAAC,UAAU,EAAA,EAAI;AACf,QAAA,OAAO,GAAA,CAAI,UAAU,KAAK,CAAA;AAAA,MAC9B;AAAA,IACJ;AAEA,IAAA,MAAM,MAAA,GAA6B;AAAA,MAC/B,QAAQ,YAAA,CAAa,KAAA;AAAA,MACrB,IAAA;AAAA,MACA,gBAAgB,OAAA,CAAQ,cAAA;AAAA,MACxB,gBAAgB,OAAA,CAAQ;AAAA;AAAA,KAE5B;AAEA,IAAA,OAAO,GAAG,IAAI,SAAA,CAAS,QAAQA,OAAAA,EAAQ,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,EAC1D;AAAA;AAAA,EAGQ,UAAA,GAAmB;AACvB,IAAA,IAAA,CAAK,EAAA,CAAG,MAAA,EAAQ,CAAC,EAAE,MAAK,KAAM;AAC1B,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,IAAI,CAAA;AAAA,IACzB,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,OAAO,EAAA,CAAG,OAAA,EAAS,CAAC,EAAE,KAAA,EAAO,MAAK,KAAM;AACzC,MAAA,IAAI,qBAAA,CAAsB,GAAA,CAAI,KAAK,CAAA,EAAG;AAClC,QAAA,IAAA,CAAK,IAAA,CAAK,OAAA,EAAS,EAAE,KAAA,EAAO,IAAI,KAAA,CAAM,CAAA,OAAA,EAAU,KAAK,CAAA,CAAE,CAAA,EAAG,KAAA,EAAO,IAAA,EAAM,CAAA;AACvE,QAAA,KAAK,KAAK,IAAA,EAAK;AAAA,MACnB;AACA,MAAA,IAAA,CAAK,IAAA,CAAK,OAAO,IAAI,CAAA;AAAA,IACzB,CAAC,CAAA;AAAA,EACL;AAAA;AAAA,EAGQ,gBAAgB,MAAA,EAA2B;AAC/C,IAAA,IAAI,OAAO,OAAA,EAAS;AAChB,MAAA,KAAK,KAAK,IAAA,EAAK;AACf,MAAA;AAAA,IACJ;AACA,IAAA,IAAA,CAAK,WAAA,GAAc,MAAA;AACnB,IAAA,IAAA,CAAK,eAAe,MAAY;AAC5B,MAAA,KAAK,KAAK,IAAA,EAAK;AAAA,IACnB,CAAA;AACA,IAAA,MAAA,CAAO,iBAAiB,OAAA,EAAS,IAAA,CAAK,cAAc,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EACtE;AACJ","file":"servers.js","sourcesContent":["/**\n * Represents the outcome of an operation that can succeed or fail.\n *\n * @typeParam T - The type of the success value\n * @typeParam E - The type of the error (defaults to Error)\n *\n * @example\n * ```ts\n * function divide(a: number, b: number): Result<number> {\n * if (b === 0) {\n * return err(new Error('Division by zero'));\n * }\n * return ok(a / b);\n * }\n *\n * const result = divide(10, 2);\n * if (result.ok) {\n * console.log(result.value); // 5\n * } else {\n * console.error(result.error.message);\n * }\n * ```\n */\ntype Result<T, E = Error> = { readonly ok: true; readonly value: T } | { readonly ok: false; readonly error: E };\n\n/**\n * Creates a successful Result containing the given value.\n *\n * @param value - The success value to wrap\n * @returns A Result representing success\n *\n * @example\n * ```ts\n * const result = ok(42);\n * // result.ok === true, result.value === 42\n * ```\n */\nfunction ok<T>(value: T): Result<T, never> {\n return { ok: true, value };\n}\n\n/**\n * Creates a failed Result containing the given error.\n *\n * @param error - The error to wrap\n * @returns A Result representing failure\n *\n * @example\n * ```ts\n * const result = err(new Error('not found'));\n * // result.ok === false, result.error.message === 'not found'\n * ```\n */\nfunction err<E>(error: E): Result<never, E> {\n return { ok: false, error };\n}\n\n/**\n * Exhaustive check helper for discriminated unions and switch statements.\n * Calling this in a default case ensures all variants are handled at compile time.\n *\n * @param x - A value that should be of type `never` if all cases are handled\n * @returns Never returns; always throws\n * @throws Always throws an Error indicating an unhandled case\n *\n * @example\n * ```ts\n * type Shape = { kind: 'circle' } | { kind: 'square' };\n *\n * function area(shape: Shape): number {\n * switch (shape.kind) {\n * case 'circle': return Math.PI;\n * case 'square': return 1;\n * default: assertUnreachable(shape);\n * }\n * }\n * ```\n */\nfunction assertUnreachable(x: never): never {\n throw new Error(`Exhaustive check failed: ${JSON.stringify(x)}`);\n}\n\n// ---------------------------------------------------------------------------\n// Process result types (Rule 7.1: immutable)\n// ---------------------------------------------------------------------------\n\n/**\n * The result of executing a short-lived DCMTK binary.\n * All properties are readonly to enforce immutability.\n */\ninterface DcmtkProcessResult {\n /** The captured stdout output from the process. */\n readonly stdout: string;\n /** The captured stderr output from the process. */\n readonly stderr: string;\n /** The exit code of the process (0 typically means success). */\n readonly exitCode: number;\n}\n\n// ---------------------------------------------------------------------------\n// Common option types (Rule 8.4: options objects for > 4 params)\n// ---------------------------------------------------------------------------\n\n/**\n * Options for short-lived DCMTK process execution.\n * Provides configurable timeout and abort support per Rule 4.2.\n */\ninterface ExecOptions {\n /** Working directory for the child process. */\n readonly cwd?: string | undefined;\n /** Timeout in milliseconds. Defaults to DEFAULT_TIMEOUT_MS. */\n readonly timeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n/**\n * Options for spawning a DCMTK process with user-supplied arguments.\n * Uses spawn() instead of exec() to avoid shell injection (Rule 7.4).\n */\ninterface SpawnOptions extends ExecOptions {\n /** Additional environment variables merged with process.env. */\n readonly env?: Readonly<Record<string, string>> | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Event types (Rule 8.3: discriminated unions)\n// ---------------------------------------------------------------------------\n\n/**\n * Line source discriminant for output parsing.\n */\ntype LineSource = 'stdout' | 'stderr';\n\n/**\n * A single line of output from a DCMTK process.\n */\ninterface ProcessLine {\n readonly source: LineSource;\n readonly text: string;\n}\n\n// ---------------------------------------------------------------------------\n// Result utility functions\n// ---------------------------------------------------------------------------\n\n/**\n * Transforms the success value of a Result, passing through errors unchanged.\n *\n * @param result - The Result to transform\n * @param fn - The transformation function\n * @returns A new Result with the transformed value, or the original error\n *\n * @example\n * ```ts\n * const result = ok(42);\n * const doubled = mapResult(result, x => x * 2);\n * // doubled.ok === true, doubled.value === 84\n * ```\n */\nfunction mapResult<T, U>(result: Result<T>, fn: (value: T) => U): Result<U> {\n if (result.ok) {\n return ok(fn(result.value));\n }\n return result;\n}\n\n/**\n * Extracts the success type from a Result.\n * Useful for extracting branded types from factory function returns.\n *\n * @example\n * ```ts\n * type Tag = ResultValue<ReturnType<typeof createDicomTag>>; // DicomTag\n * ```\n */\ntype ResultValue<R> = R extends Result<infer T> ? T : never;\n\nexport { ok, err, assertUnreachable, mapResult };\nexport type { Result, ResultValue, DcmtkProcessResult, ExecOptions, SpawnOptions, LineSource, ProcessLine };\n","/**\n * Application-wide constants.\n *\n * All values use `as const` assertions per Rule 3.5 (no traditional enums).\n * All bounds are documented per Rule 8.1 (bounded loops/buffers).\n *\n * @module constants\n */\n\n// ---------------------------------------------------------------------------\n// Timeouts (Rule 4.2: mandatory timeouts on all async operations)\n// ---------------------------------------------------------------------------\n\n/** Default timeout for short-lived process execution (30 seconds). */\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/** Default timeout for long-lived process startup (10 seconds). */\nconst DEFAULT_START_TIMEOUT_MS = 10_000;\n\n/** Default timeout for graceful shutdown drain (5 seconds). */\nconst DEFAULT_DRAIN_TIMEOUT_MS = 5_000;\n\n/** Default timeout for multi-line block accumulation in line parser (1 second). */\nconst DEFAULT_BLOCK_TIMEOUT_MS = 1_000;\n\n// ---------------------------------------------------------------------------\n// DICOM network constants\n// ---------------------------------------------------------------------------\n\n/** DICOM protocol default PDU sizes. */\nconst PDU_SIZE = {\n /** Default maximum PDU receive size (16 KB). */\n DEFAULT: 16_384,\n /** Minimum allowed PDU size (4 KB). */\n MIN: 4_096,\n /** Maximum allowed PDU size (128 KB). */\n MAX: 131_072,\n} as const;\n\n/** Default DICOM port used by DCMTK tools. */\nconst DEFAULT_DICOM_PORT = 104;\n\n// ---------------------------------------------------------------------------\n// Platform-specific known DCMTK install paths\n// ---------------------------------------------------------------------------\n\n/** Known DCMTK binary locations on Windows. */\nconst WINDOWS_SEARCH_PATHS = ['C:\\\\Program Files\\\\DCMTK\\\\bin', 'C:\\\\Program Files (x86)\\\\DCMTK\\\\bin', 'C:\\\\ProgramData\\\\chocolatey\\\\bin'] as const;\n\n/** Known DCMTK binary locations on Unix/macOS. */\nconst UNIX_SEARCH_PATHS = ['/usr/local/bin', '/usr/bin', '/opt/local/bin', '/opt/homebrew/bin'] as const;\n\n// ---------------------------------------------------------------------------\n// Required DCMTK binaries (minimum set for core functionality)\n// ---------------------------------------------------------------------------\n\n/** Binaries that must be present for the library to function. */\nconst REQUIRED_BINARIES = ['dcm2json', 'dcm2xml', 'dcmodify', 'dcmdump', 'dcmrecv', 'dcmsend', 'echoscu'] as const;\n\n// ---------------------------------------------------------------------------\n// Bounded limits (Rule 8.1: all loops and buffers must have upper bounds)\n// ---------------------------------------------------------------------------\n\n/** Maximum lines accumulated in multi-line block parser. */\nconst MAX_BLOCK_LINES = 1_000;\n\n/** Maximum number of event patterns a line parser can hold. */\nconst MAX_EVENT_PATTERNS = 200;\n\n/** Maximum loop iterations for iterative traversal (e.g., nested sequences). */\nconst MAX_TRAVERSAL_DEPTH = 50;\n\n/** Maximum number of operations (modifications + erasures) in a single ChangeSet. */\nconst MAX_CHANGESET_OPERATIONS = 10_000;\n\n/** Maximum bytes allowed for stdout + stderr buffering (100 MB). */\nconst MAX_OUTPUT_BYTES = 100 * 1024 * 1024;\n\nexport {\n DEFAULT_TIMEOUT_MS,\n DEFAULT_START_TIMEOUT_MS,\n DEFAULT_DRAIN_TIMEOUT_MS,\n DEFAULT_BLOCK_TIMEOUT_MS,\n PDU_SIZE,\n DEFAULT_DICOM_PORT,\n WINDOWS_SEARCH_PATHS,\n UNIX_SEARCH_PATHS,\n REQUIRED_BINARIES,\n MAX_BLOCK_LINES,\n MAX_EVENT_PATTERNS,\n MAX_TRAVERSAL_DEPTH,\n MAX_CHANGESET_OPERATIONS,\n MAX_OUTPUT_BYTES,\n};\n","/**\n * Base class for long-lived DCMTK processes (servers).\n *\n * Manages spawning, line-by-line output buffering, typed event emission,\n * lifecycle (start/stop), mandatory timeouts, and graceful shutdown.\n *\n * Implements `Disposable` for deterministic cleanup (Rule 5.1).\n *\n * @module DcmtkProcess\n */\n\nimport { EventEmitter } from 'node:events';\nimport { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport { stderr } from 'stderr-lib';\nimport kill from 'tree-kill';\nimport type { Result, LineSource } from './types';\nimport { ok, err } from './types';\nimport { DEFAULT_START_TIMEOUT_MS, DEFAULT_DRAIN_TIMEOUT_MS, MAX_OUTPUT_BYTES } from './constants';\n\n// ---------------------------------------------------------------------------\n// Event types\n// ---------------------------------------------------------------------------\n\n/** Events emitted by a DcmtkProcess. */\ninterface DcmtkProcessEventMap {\n started: [];\n stopped: [{ readonly reason: string }];\n error: [{ readonly error: Error; readonly fatal: boolean }];\n line: [{ readonly source: LineSource; readonly text: string }];\n}\n\n/** Configuration for a DcmtkProcess instance. */\ninterface DcmtkProcessConfig {\n /** Full path to the DCMTK binary. */\n readonly binary: string;\n /** Command-line arguments. */\n readonly args: readonly string[];\n /** Working directory. */\n readonly cwd?: string | undefined;\n /** Timeout for start() to resolve, in milliseconds. */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop(), in milliseconds. */\n readonly drainTimeoutMs?: number | undefined;\n /**\n * A function that inspects each output line and returns `true` when\n * the process is considered \"started\" (e.g., \"listening on port X\").\n * If not provided, start() resolves immediately after spawn.\n */\n readonly isStartedPredicate?: ((line: string) => boolean) | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// State enum (as const, not traditional enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\nconst ProcessState = {\n IDLE: 'IDLE',\n STARTING: 'STARTING',\n RUNNING: 'RUNNING',\n STOPPING: 'STOPPING',\n STOPPED: 'STOPPED',\n} as const;\n\ntype ProcessStateValue = (typeof ProcessState)[keyof typeof ProcessState];\n\n// ---------------------------------------------------------------------------\n// DcmtkProcess class\n// ---------------------------------------------------------------------------\n\n/**\n * Base class for persistent DCMTK processes (e.g., dcmrecv, storescp).\n *\n * @example\n * ```ts\n * const proc = new DcmtkProcess({\n * binary: '/usr/local/bin/dcmrecv',\n * args: ['--config', 'storescp.cfg', '11112'],\n * isStartedPredicate: line => line.includes('listening'),\n * });\n *\n * const result = await proc.start();\n * if (result.ok) {\n * // Process is running\n * proc.on('line', ({ source, text }) => console.log(`[${source}] ${text}`));\n * }\n *\n * await proc.stop();\n * ```\n */\nclass DcmtkProcess extends EventEmitter<DcmtkProcessEventMap> {\n private state: ProcessStateValue = ProcessState.IDLE;\n private child: ChildProcess | null = null;\n private stdoutBuffer = '';\n private stderrBuffer = '';\n private readonly config: DcmtkProcessConfig;\n\n constructor(config: DcmtkProcessConfig) {\n super();\n // Servers can have up to ~15 event types plus internal listeners;\n // raise above the default 10 to avoid MaxListenersExceeded warnings.\n this.setMaxListeners(20);\n this.config = config;\n // Prevent unhandled 'error' events from crashing the process (Node.js\n // throws if 'error' is emitted with no listener). Consumers should\n // register their own 'error' listener before calling start() to receive\n // errors. Startup errors are also returned via Result from start().\n this.on('error', () => {});\n }\n\n /** Whether the process is currently running. */\n get isRunning(): boolean {\n return this.state === ProcessState.RUNNING;\n }\n\n /** Current process state. */\n get currentState(): ProcessStateValue {\n return this.state;\n }\n\n /**\n * Starts the DCMTK process.\n *\n * Single-use enforcement: returns an error if called more than once.\n * Waits for the `isStartedPredicate` to match an output line, or resolves\n * immediately after spawn if no predicate is configured.\n *\n * @returns A Result indicating success or failure\n */\n async start(): Promise<Result<void>> {\n if (this.state !== ProcessState.IDLE) {\n return err(new Error(`Cannot start: process is in state \"${this.state}\"`));\n }\n this.state = ProcessState.STARTING;\n const timeoutMs = this.config.startTimeoutMs ?? DEFAULT_START_TIMEOUT_MS;\n\n return new Promise<Result<void>>(resolve => {\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n this.state = ProcessState.STOPPED;\n this.killChild();\n resolve(err(new Error(`Process failed to start within ${timeoutMs}ms`)));\n }, timeoutMs);\n\n // Safe from races: Node.js is single-threaded, so the `settled`\n // flag check + set is atomic within each event handler invocation.\n const settle = (result: Result<void>): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(result);\n };\n\n try {\n this.child = spawn(this.config.binary, [...this.config.args], {\n cwd: this.config.cwd,\n windowsHide: true,\n });\n /* v8 ignore start -- spawn() rarely throws synchronously */\n } catch (e: unknown) {\n settle(err(new Error(`Failed to spawn process: ${stderr(e).message}`)));\n return;\n }\n /* v8 ignore stop */\n this.wireChildEvents(settle);\n });\n }\n\n /**\n * Stops the process gracefully.\n *\n * Waits up to `drainTimeoutMs` for the process to exit, then force-kills.\n */\n async stop(): Promise<void> {\n if (this.state === ProcessState.STOPPED || this.state === ProcessState.IDLE) {\n return;\n }\n\n this.state = ProcessState.STOPPING;\n const drainMs = this.config.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS;\n\n return new Promise<void>(resolve => {\n /* v8 ignore next 4 -- drain timeout is a safety net for unresponsive processes */\n const timer = setTimeout(() => {\n this.killChild();\n this.state = ProcessState.STOPPED;\n resolve();\n }, drainMs);\n\n // Safe: Node.js is single-threaded, so `this.child` cannot become null\n // between the check and the `.once('close', ...)` registration. The\n // drain timeout handles the edge case where the child exits before\n // the close listener is registered.\n if (this.child) {\n this.child.once('close', () => {\n clearTimeout(timer);\n this.state = ProcessState.STOPPED;\n resolve();\n });\n this.killChild();\n /* v8 ignore start -- edge case: state is RUNNING but child is already null */\n } else {\n clearTimeout(timer);\n this.state = ProcessState.STOPPED;\n resolve();\n }\n /* v8 ignore stop */\n });\n }\n\n /**\n * Implements Disposable for deterministic cleanup (Rule 5.1).\n */\n [Symbol.dispose](): void {\n if (this.child) {\n this.killChild();\n this.child = null;\n }\n this.state = ProcessState.STOPPED;\n this.removeAllListeners();\n }\n\n // -----------------------------------------------------------------------\n // Private helpers\n // -----------------------------------------------------------------------\n\n private killChild(): void {\n if (this.child?.pid !== undefined && this.child.pid !== null) {\n try {\n kill(this.child.pid);\n /* v8 ignore next */\n } catch {\n // Process may already be dead\n }\n }\n }\n\n /**\n * Wires all child process event handlers for startup.\n */\n private wireChildEvents(settle: (result: Result<void>) => void): void {\n const child = this.child;\n if (!child) return;\n\n child.on('error', (error: Error) => {\n this.emit('error', { error, fatal: true });\n if (this.state === ProcessState.STARTING) {\n this.state = ProcessState.STOPPED;\n settle(err(new Error(`Process error during start: ${error.message}`)));\n }\n });\n\n child.on('close', (code: number | null) => {\n const prevState = this.state;\n this.state = ProcessState.STOPPED;\n this.child = null;\n const reason = `Process exited with code ${String(code ?? 'null')}`;\n this.emit('stopped', { reason });\n if (prevState === ProcessState.STARTING) settle(err(new Error(reason)));\n });\n\n child.stdout?.on('data', (chunk: Buffer | string) => {\n this.handleData('stdout', chunk);\n });\n child.stderr?.on('data', (chunk: Buffer | string) => {\n this.handleData('stderr', chunk);\n });\n\n child.on('spawn', () => {\n if (!this.config.isStartedPredicate) {\n this.state = ProcessState.RUNNING;\n this.emit('started');\n settle(ok(undefined));\n }\n });\n\n if (this.config.isStartedPredicate) {\n this.wireStartedPredicate(settle);\n }\n }\n\n /**\n * Wires a line listener that resolves start() when the predicate matches.\n */\n private wireStartedPredicate(settle: (result: Result<void>) => void): void {\n const onLine = ({ text }: { readonly source: LineSource; readonly text: string }): void => {\n if (this.config.isStartedPredicate?.(text)) {\n this.removeListener('line', onLine);\n this.state = ProcessState.RUNNING;\n this.emit('started');\n settle(ok(undefined));\n }\n };\n this.on('line', onLine);\n }\n\n private handleData(source: LineSource, chunk: Buffer | string): void {\n if (source === 'stdout') {\n this.stdoutBuffer += String(chunk);\n } else {\n this.stderrBuffer += String(chunk);\n }\n\n if (this.stdoutBuffer.length + this.stderrBuffer.length > MAX_OUTPUT_BYTES) {\n this.emit('error', { error: new Error(`Process output exceeded ${MAX_OUTPUT_BYTES} bytes`), fatal: true });\n this.killChild();\n return;\n }\n\n this.processLines(source, source === 'stdout' ? 'stdoutBuffer' : 'stderrBuffer');\n }\n\n private processLines(source: LineSource, bufferKey: 'stdoutBuffer' | 'stderrBuffer'): void {\n // Handle bare \\r (CR-only) line endings by converting to \\n\n this[bufferKey] = this[bufferKey].replace(/\\r(?!\\n)/g, '\\n');\n\n let newlineIdx = this[bufferKey].indexOf('\\n');\n\n // Iterative line extraction — no recursion (Rule 8.2)\n while (newlineIdx !== -1) {\n const current = this[bufferKey];\n const line = current.substring(0, newlineIdx).replace(/\\r$/, '');\n this[bufferKey] = current.substring(newlineIdx + 1);\n this.emit('line', { source, text: line });\n newlineIdx = this[bufferKey].indexOf('\\n');\n }\n }\n}\n\nexport { DcmtkProcess, ProcessState };\nexport type { DcmtkProcessEventMap, DcmtkProcessConfig, ProcessStateValue };\n","/**\n * Line-by-line parser for DCMTK process output.\n *\n * Matches output lines against registered EventPattern objects and emits\n * structured events. Supports both single-line and multi-line block matching.\n *\n * All algorithms are iterative (Rule 8.2: no recursion).\n * All buffers are bounded (Rule 8.1).\n *\n * @module parsers/LineParser\n */\n\nimport { EventEmitter } from 'node:events';\nimport { stderr } from 'stderr-lib';\nimport type { EventPattern } from './EventPattern';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { MAX_BLOCK_LINES, MAX_EVENT_PATTERNS, DEFAULT_BLOCK_TIMEOUT_MS } from '../constants';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Events emitted by the LineParser. */\ninterface LineParserEventMap {\n /** Emitted when a pattern matches. Carries the event name and extracted data. */\n match: [{ readonly event: string; readonly data: unknown }];\n /** Emitted when a multi-line block times out before the footer is matched. Consumers should listen for this event to detect and handle incomplete blocks. */\n blockTimeout: [{ readonly event: string; readonly lines: readonly string[] }];\n /** Emitted when a pattern processor throws. */\n error: [Error];\n}\n\n/** Tracks the state of an in-progress multi-line block. */\ninterface BlockState {\n readonly pattern: EventPattern;\n readonly lines: string[];\n readonly timer: ReturnType<typeof setTimeout>;\n}\n\n// ---------------------------------------------------------------------------\n// LineParser class\n// ---------------------------------------------------------------------------\n\n/**\n * Parses DCMTK output lines against registered event patterns.\n *\n * @example\n * ```ts\n * const parser = new LineParser();\n * parser.addPattern({\n * event: 'LISTENING',\n * pattern: /listening on port (\\d+)/i,\n * processor: match => ({ port: Number(match[1]) }),\n * });\n *\n * parser.on('match', ({ event, data }) => {\n * console.log(`${event}:`, data);\n * });\n *\n * parser.feed('I: listening on port 11112');\n * // Emits: match { event: 'LISTENING', data: { port: 11112 } }\n * ```\n */\nclass LineParser extends EventEmitter<LineParserEventMap> {\n private readonly patterns: EventPattern[] = [];\n private activeBlock: BlockState | null = null;\n\n constructor() {\n super();\n // LineParser is used internally and the number of patterns can be\n // large — disable the listener limit (0 = unlimited) to avoid\n // MaxListenersExceeded warnings.\n this.setMaxListeners(0);\n // Prevent unhandled 'error' events from crashing the process.\n // Consumers should register their own 'error' listener.\n this.on('error', () => {});\n }\n\n /**\n * Registers an event pattern.\n *\n * @param pattern - The pattern to register\n * @returns Result indicating success or failure if pattern limit exceeded\n */\n addPattern(pattern: EventPattern): Result<void> {\n if (this.patterns.length >= MAX_EVENT_PATTERNS) {\n return err(new Error(`Maximum event patterns (${MAX_EVENT_PATTERNS}) exceeded`));\n }\n this.patterns.push(pattern);\n return ok(undefined);\n }\n\n /**\n * Feeds a single line of output to the parser.\n *\n * The line is matched against all registered patterns (iteratively, Rule 8.2).\n * If a multi-line block is active, the line is accumulated until the footer matches.\n *\n * @param line - A single line of DCMTK output (without trailing newline)\n */\n feed(line: string): void {\n // If a multi-line block is active, accumulate lines\n if (this.activeBlock !== null) {\n this.feedToBlock(line);\n return;\n }\n\n // Check for multi-line block headers first\n for (let i = 0; i < this.patterns.length; i++) {\n const pattern = this.patterns[i];\n /* v8 ignore next -- safety guard for noUncheckedIndexedAccess */\n if (pattern === undefined) continue;\n\n if (pattern.multiLine) {\n const headerMatch = pattern.multiLine.header.exec(line);\n if (headerMatch) {\n this.startBlock(pattern, line);\n return;\n }\n }\n }\n\n // Check single-line patterns\n this.matchSingleLine(line);\n }\n\n /**\n * Feeds multiple lines of output (e.g., from a chunk split by newlines).\n *\n * @param lines - Array of lines to process\n */\n feedLines(lines: readonly string[]): void {\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line !== undefined) {\n this.feed(line);\n }\n }\n }\n\n /**\n * Resets the parser state, clearing any active multi-line block.\n */\n reset(): void {\n if (this.activeBlock !== null) {\n clearTimeout(this.activeBlock.timer);\n this.activeBlock = null;\n }\n }\n\n /**\n * Implements Disposable for cleanup (Rule 5.1).\n */\n [Symbol.dispose](): void {\n this.reset();\n this.removeAllListeners();\n }\n\n // -----------------------------------------------------------------------\n // Private helpers\n // -----------------------------------------------------------------------\n\n private matchSingleLine(line: string): void {\n for (let i = 0; i < this.patterns.length; i++) {\n const pattern = this.patterns[i];\n /* v8 ignore next -- safety guard for noUncheckedIndexedAccess */\n if (pattern === undefined) continue;\n\n // Skip multi-line-only patterns for single-line matching\n if (pattern.multiLine) continue;\n\n const match = pattern.pattern.exec(line);\n if (match) {\n try {\n const data = pattern.processor(match);\n this.emit('match', { event: pattern.event, data });\n } catch (thrown: unknown) {\n this.emit('error', stderr(thrown));\n }\n return; // First match wins\n }\n }\n }\n\n private startBlock(pattern: EventPattern, headerLine: string): void {\n /* v8 ignore next -- multiLine is always defined when startBlock is called */\n const timeoutMs = pattern.multiLine?.timeoutMs ?? DEFAULT_BLOCK_TIMEOUT_MS;\n\n const timer = setTimeout(() => {\n if (this.activeBlock !== null) {\n const lines = [...this.activeBlock.lines];\n const evt = this.activeBlock.pattern.event;\n this.activeBlock = null;\n this.emit('blockTimeout', { event: evt, lines });\n }\n }, timeoutMs);\n\n this.activeBlock = {\n pattern,\n lines: [headerLine],\n timer,\n };\n }\n\n private feedToBlock(line: string): void {\n /* v8 ignore next -- safety guard: activeBlock is always set when feedToBlock is called */\n if (this.activeBlock === null) return;\n\n const { pattern, lines, timer } = this.activeBlock;\n /* v8 ignore next -- multiLine is always defined for block patterns */\n const maxLines = pattern.multiLine?.maxLines ?? MAX_BLOCK_LINES;\n\n lines.push(line);\n\n // Check footer\n if (pattern.multiLine?.footer.test(line)) {\n clearTimeout(timer);\n const blockText = lines.join('\\n');\n const match = pattern.pattern.exec(blockText);\n this.activeBlock = null;\n\n if (match) {\n try {\n const data = pattern.processor(match);\n this.emit('match', { event: pattern.event, data });\n } catch (thrown: unknown) {\n this.emit('error', stderr(thrown));\n }\n }\n return;\n }\n\n // Enforce bounded accumulation (Rule 8.1)\n if (lines.length >= maxLines) {\n clearTimeout(timer);\n const evt = pattern.event;\n const accumulated = [...lines];\n this.activeBlock = null;\n this.emit('blockTimeout', { event: evt, lines: accumulated });\n }\n }\n}\n\nexport { LineParser };\nexport type { LineParserEventMap };\n","/**\n * Shared validation regex patterns and constants.\n *\n * Centralises all DICOM-related validation patterns so that brands,\n * validation schemas, and server modules reference a single source\n * of truth rather than maintaining duplicated copies.\n *\n * @module patterns\n */\n\n// ---------------------------------------------------------------------------\n// DICOM tag and UID patterns\n// ---------------------------------------------------------------------------\n\n/** Matches a DICOM tag in `(XXXX,XXXX)` format where X is a hex digit. */\nconst DICOM_TAG_PATTERN = /^\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)$/;\n\n/** Matches a DICOM AE Title: printable ASCII excluding backslash (DICOM PS3.5 default repertoire). */\nconst AE_TITLE_PATTERN = /^[\\x20-\\x5b\\x5d-\\x7e]+$/;\n\n/**\n * Matches a dotted numeric OID (e.g. `1.2.840.10008`).\n *\n * Note: This intentionally accepts any syntactically valid dotted-numeric form.\n * DICOM PS3.5 §9.1 requires UIDs start with a non-zero root (e.g., `0.0.0` is\n * technically invalid), but real-world DICOM datasets contain such UIDs, so we\n * validate syntax only and leave semantic UID validation to the application layer.\n */\nconst UID_PATTERN = /^[0-9]+(\\.[0-9]+)*$/;\n\n/** Matches a single DICOM tag path segment with optional array index. */\nconst TAG_PATH_SEGMENT = /\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)(\\[\\d+\\])?/;\n\n/** Matches a full dot-separated DICOM tag path (e.g. `(0040,A730)[0].(0010,0010)`). */\nconst DICOM_TAG_PATH_PATTERN = new RegExp(`^${TAG_PATH_SEGMENT.source}(\\\\.${TAG_PATH_SEGMENT.source})*$`);\n\n// ---------------------------------------------------------------------------\n// Validation constants\n// ---------------------------------------------------------------------------\n\n/** Minimum length for an AE Title. */\nconst AE_TITLE_MIN_LENGTH = 1;\n\n/** Maximum length for an AE Title. */\nconst AE_TITLE_MAX_LENGTH = 16;\n\n/** Maximum length for a DICOM UID. */\nconst UID_MAX_LENGTH = 64;\n\n/** Minimum valid network port number. */\nconst PORT_MIN = 1;\n\n/** Maximum valid network port number. */\nconst PORT_MAX = 65535;\n\n// ---------------------------------------------------------------------------\n// DICOM query key patterns\n// ---------------------------------------------------------------------------\n\n/**\n * Matches a valid DICOM query key for `-k` arguments.\n *\n * Accepted formats:\n * - `XXXX,XXXX` — bare tag\n * - `XXXX,XXXX=value` — tag with value\n * - `XXXX,XXXX[0].XXXX,XXXX=value` — nested path with value\n * - `XXXX,XXXX.XXXX,XXXX=value` — dotted path with value\n *\n * The tag portion must start with a valid hex tag pair. Value after `=` is unconstrained.\n */\n// eslint-disable-next-line no-useless-escape\nconst DICOM_QUERY_KEY_PATTERN = /^[0-9A-Fa-f]{4},[0-9A-Fa-f]{4}(?:[\\[.\\]0-9A-Fa-f,]*)?(?:=.*)?$/;\n\n/**\n * Returns true if the string is a valid DICOM query key for `-k` arguments.\n */\nfunction isValidDicomKey(key: string): boolean {\n return DICOM_QUERY_KEY_PATTERN.test(key);\n}\n\n// ---------------------------------------------------------------------------\n// Path safety\n// ---------------------------------------------------------------------------\n\n/** Pattern matching `..` as a path segment (between separators, or at start/end). */\nconst PATH_TRAVERSAL_PATTERN = /(?:^|[\\\\/])\\.\\.(?:[\\\\/]|$)/;\n\n/**\n * Returns true if the string contains only valid DICOM AE Title characters.\n */\nfunction isValidAETitle(value: string): boolean {\n return AE_TITLE_PATTERN.test(value);\n}\n\n/**\n * Returns true if the path does not contain traversal sequences.\n *\n * @param p - The filesystem path to check\n * @returns `true` when the path is safe (no `..` segments)\n */\nfunction isSafePath(p: string): boolean {\n return !PATH_TRAVERSAL_PATTERN.test(p);\n}\n\nexport {\n DICOM_TAG_PATTERN,\n AE_TITLE_PATTERN,\n UID_PATTERN,\n TAG_PATH_SEGMENT,\n DICOM_TAG_PATH_PATTERN,\n AE_TITLE_MIN_LENGTH,\n AE_TITLE_MAX_LENGTH,\n UID_MAX_LENGTH,\n PORT_MIN,\n PORT_MAX,\n DICOM_QUERY_KEY_PATTERN,\n isValidDicomKey,\n isValidAETitle,\n PATH_TRAVERSAL_PATTERN,\n isSafePath,\n};\n","/**\n * Locates DCMTK binaries on the host system.\n *\n * Search order:\n * 1. `DCMTK_PATH` environment variable\n * 2. Platform-specific known install locations\n * 3. System PATH (via `which`/`where` lookup)\n *\n * @module findDcmtkPath\n */\n\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport type { Result } from './types';\nimport { ok, err } from './types';\nimport { WINDOWS_SEARCH_PATHS, UNIX_SEARCH_PATHS, REQUIRED_BINARIES } from './constants';\nimport { isSafePath } from './patterns';\n\n/** Cached path result. Cleared only by passing `noCache: true`. */\nlet cachedPath: string | undefined;\n\nconst isWindows = process.platform === 'win32';\n\n/**\n * Returns the binary filename with platform-appropriate extension.\n *\n * @param name - The base binary name (e.g., `\"dcm2json\"`)\n * @returns The binary name with `.exe` appended on Windows\n */\nfunction binaryName(name: string): string {\n /* v8 ignore next -- platform-specific branch */\n return isWindows ? `${name}.exe` : name;\n}\n\n/**\n * Checks whether a directory contains all required DCMTK binaries.\n *\n * @param dir - The directory to check\n * @returns `true` if all required binaries exist in the directory\n */\nfunction hasRequiredBinaries(dir: string): boolean {\n for (const bin of REQUIRED_BINARIES) {\n if (!existsSync(join(dir, binaryName(bin)))) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Attempts to locate a binary via the system PATH using `which` (Unix) or `where` (Windows).\n *\n * @param name - The binary name to search for\n * @returns The directory containing the binary, or `undefined` if not found\n */\nfunction findViaSystemPath(name: string): string | undefined {\n try {\n /* v8 ignore next -- platform-specific branch */\n const cmd = isWindows ? `where ${binaryName(name)}` : `which ${name}`;\n const result = execSync(cmd, { encoding: 'utf-8', timeout: 5_000, windowsHide: true }).trim();\n const firstLine = result.split('\\n')[0]?.trim();\n if (firstLine) {\n /* v8 ignore next -- platform-specific branch */\n const lastSep = firstLine.lastIndexOf(isWindows ? '\\\\' : '/');\n if (lastSep >= 0) {\n return firstLine.substring(0, lastSep);\n }\n }\n } catch {\n // Binary not in PATH — this is expected, not exceptional\n }\n return undefined;\n}\n\n/**\n * Checks the DCMTK_PATH environment variable for a valid DCMTK installation.\n *\n * @returns A Result if the env var is set (success or error), or `undefined` if unset\n */\nfunction searchEnvPath(): Result<string> | undefined {\n const envPath = process.env['DCMTK_PATH'];\n if (envPath === undefined || envPath.length === 0) {\n return undefined;\n }\n if (!isSafePath(envPath)) {\n return err(new Error(`DCMTK_PATH=\"${envPath}\" contains path traversal sequences`));\n }\n if (hasRequiredBinaries(envPath)) {\n return ok(envPath);\n }\n return err(new Error(`DCMTK_PATH=\"${envPath}\" is set but required binaries are missing`));\n}\n\n/**\n * Searches platform-specific known install locations for DCMTK binaries.\n *\n * @returns The directory path if found, or `undefined`\n */\nfunction searchKnownPaths(): string | undefined {\n /* v8 ignore next -- platform-specific branch */\n const searchPaths = isWindows ? WINDOWS_SEARCH_PATHS : UNIX_SEARCH_PATHS;\n for (const candidate of searchPaths) {\n if (hasRequiredBinaries(candidate)) {\n return candidate;\n }\n }\n return undefined;\n}\n\n/**\n * Searches the system PATH for DCMTK binaries.\n *\n * @returns The directory path if found, or `undefined`\n */\nfunction searchSystemPath(): string | undefined {\n /* v8 ignore next -- fallback never used since REQUIRED_BINARIES is non-empty */\n const systemDir = findViaSystemPath(REQUIRED_BINARIES[0] ?? 'dcm2json');\n if (systemDir !== undefined && hasRequiredBinaries(systemDir)) {\n return systemDir;\n }\n return undefined;\n}\n\n/**\n * Options for {@link findDcmtkPath}.\n */\ninterface FindDcmtkPathOptions {\n /** Bypass the cached result and perform a fresh search. */\n readonly noCache?: boolean | undefined;\n}\n\n/**\n * Locates the directory containing DCMTK command-line binaries.\n *\n * Searches in the following order:\n * 1. `DCMTK_PATH` environment variable (if set)\n * 2. Platform-specific known install locations\n * 3. System PATH lookup via `which`/`where`\n *\n * The result is cached after the first successful call. Pass `{ noCache: true }`\n * to force a fresh search.\n *\n * @param options - Optional configuration\n * @returns A Result containing the DCMTK binary directory path, or an error if not found\n * @throws Never throws for expected failures (Rule 6.1)\n *\n * @example\n * ```ts\n * const result = findDcmtkPath();\n * if (result.ok) {\n * console.log(`DCMTK found at: ${result.value}`);\n * } else {\n * console.error(result.error.message);\n * }\n * ```\n */\nfunction findDcmtkPath(options?: FindDcmtkPathOptions): Result<string> {\n if (cachedPath !== undefined && !options?.noCache) {\n return ok(cachedPath);\n }\n\n const envResult = searchEnvPath();\n if (envResult !== undefined) {\n if (envResult.ok) {\n cachedPath = envResult.value;\n }\n return envResult;\n }\n\n const knownPath = searchKnownPaths();\n if (knownPath !== undefined) {\n cachedPath = knownPath;\n return ok(knownPath);\n }\n\n const systemPath = searchSystemPath();\n if (systemPath !== undefined) {\n cachedPath = systemPath;\n return ok(systemPath);\n }\n\n return err(\n new Error(\n 'DCMTK binaries not found. Install DCMTK and either:\\n' +\n ' - Set the DCMTK_PATH environment variable, or\\n' +\n ' - Install DCMTK to a standard location, or\\n' +\n ' - Ensure DCMTK binaries are on the system PATH'\n )\n );\n}\n\n/**\n * Clears the cached DCMTK path. Primarily for testing.\n */\nfunction clearDcmtkPathCache(): void {\n cachedPath = undefined;\n}\n\nexport { findDcmtkPath, clearDcmtkPathCache };\nexport type { FindDcmtkPathOptions };\n","/**\n * Resolves the full path to a DCMTK binary.\n *\n * Wraps {@link findDcmtkPath} + `path.join` and appends `.exe` on Windows.\n *\n * @module _resolveBinary\n * @internal\n */\n\nimport { join } from 'node:path';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { findDcmtkPath } from '../findDcmtkPath';\n\nconst isWindows = process.platform === 'win32';\n\n/**\n * Resolves the full filesystem path to a named DCMTK binary.\n *\n * @param toolName - The DCMTK binary name (e.g., \"dcm2xml\")\n * @returns A Result containing the full binary path or an error if DCMTK is not found\n */\nfunction resolveBinary(toolName: string): Result<string> {\n const pathResult = findDcmtkPath();\n if (!pathResult.ok) {\n return err(pathResult.error);\n }\n /* v8 ignore next -- platform-specific branch */\n const binaryName = isWindows ? `${toolName}.exe` : toolName;\n return ok(join(pathResult.value, binaryName));\n}\n\nexport { resolveBinary };\n","/**\n * Standardized error factory for tool wrappers.\n *\n * Produces consistent error messages that include the tool name, sanitized\n * arguments (truncated), exit code, and a stderr excerpt.\n *\n * @module _toolError\n * @internal\n */\n\n/** Maximum length for the arguments portion of the error message. */\nconst MAX_ARGS_LENGTH = 200;\n\n/** Maximum length for the stderr excerpt in the error message. */\nconst MAX_STDERR_LENGTH = 500;\n\n/**\n * Truncates a string to a maximum length, appending \"...\" if truncated.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum allowed length\n * @returns The original string or a truncated version\n */\nfunction truncate(value: string, maxLength: number): string {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.substring(0, maxLength)}...`;\n}\n\n/**\n * Error thrown by tool wrappers when the underlying binary exits non-zero\n * (or otherwise reports failure). Carries the full captured stdout/stderr\n * and exit code so callers can surface diagnostic output without parsing\n * the message string.\n */\nclass ToolExecutionError extends Error {\n readonly stdout: string;\n readonly stderr: string;\n readonly exitCode: number;\n\n constructor(message: string, details: { readonly stdout: string; readonly stderr: string; readonly exitCode: number }) {\n super(message);\n this.name = 'ToolExecutionError';\n this.stdout = details.stdout;\n this.stderr = details.stderr;\n this.exitCode = details.exitCode;\n }\n}\n\n/**\n * Creates a standardized error for a tool wrapper failure.\n *\n * **Privacy note:** Arguments are included in the error message for debugging.\n * These may contain file paths. Callers exposing errors to end users or external\n * logs should sanitize sensitive paths before display.\n *\n * @param toolName - The DCMTK binary name (e.g., \"dcm2xml\")\n * @param args - The command-line arguments passed to the tool\n * @param exitCode - The process exit code\n * @param stderr - The captured stderr output\n * @param stdout - The captured stdout output (default '')\n * @returns A ToolExecutionError carrying the full output for diagnostic use\n */\n// eslint-disable-next-line max-params -- 5 cohesive params describing one process result; refactoring to an options bag would churn 50+ call sites\nfunction createToolError(toolName: string, args: readonly string[], exitCode: number, stderr: string, stdout: string = ''): ToolExecutionError {\n const argsStr = truncate(args.join(' '), MAX_ARGS_LENGTH);\n const stderrStr = truncate(stderr.trim(), MAX_STDERR_LENGTH);\n const parts = [`${toolName} failed (exit code ${String(exitCode)})`];\n if (argsStr.length > 0) {\n parts.push(`args: ${argsStr}`);\n }\n if (stderrStr.length > 0) {\n parts.push(`stderr: ${stderrStr}`);\n }\n return new ToolExecutionError(parts.join(' | '), { stdout, stderr, exitCode });\n}\n\n/**\n * Formats a Zod validation error into a concise, human-readable string.\n *\n * Flattens nested Zod issues into `field: message` pairs, producing\n * cleaner output than the raw Zod `.message` JSON string.\n *\n * @param toolName - The DCMTK tool name for context\n * @param zodError - The Zod error object (must have `.issues` array)\n * @returns A formatted Error\n */\nfunction createValidationError(\n toolName: string,\n zodError: { readonly issues: ReadonlyArray<{ readonly path: ReadonlyArray<PropertyKey>; readonly message: string }> }\n): Error {\n const parts: string[] = [];\n for (let i = 0; i < zodError.issues.length; i++) {\n const issue = zodError.issues[i];\n /* v8 ignore next */\n if (issue === undefined) continue;\n const path = issue.path.length > 0 ? issue.path.map(String).join('.') : '(root)';\n parts.push(`${path}: ${issue.message}`);\n }\n const detail = parts.length > 0 ? parts.join('; ') : 'unknown validation error';\n return new Error(`${toolName}: invalid options — ${detail}`);\n}\n\nexport { ToolExecutionError, createToolError, createValidationError, truncate, MAX_ARGS_LENGTH, MAX_STDERR_LENGTH };\n","/**\n * Event patterns and types for dcmrecv output parsing.\n *\n * Defines regex patterns that match DCMTK dcmrecv verbose output,\n * along with typed event data interfaces for each event.\n *\n * @module events/dcmrecv\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmrecv process output. */\nconst DcmrecvEvent = {\n LISTENING: 'LISTENING',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n C_STORE_REQUEST: 'C_STORE_REQUEST',\n STORED_FILE: 'STORED_FILE',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n ECHO_REQUEST: 'ECHO_REQUEST',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n REFUSING_ASSOCIATION: 'REFUSING_ASSOCIATION',\n /** Synthetic: STORED_FILE enriched with association context. */\n FILE_RECEIVED: 'FILE_RECEIVED',\n /** Synthetic: emitted on association release/abort with summary. */\n ASSOCIATION_COMPLETE: 'ASSOCIATION_COMPLETE',\n} as const;\n\ntype DcmrecvEventValue = (typeof DcmrecvEvent)[keyof typeof DcmrecvEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface AssociationReceivedData {\n readonly source: string;\n readonly callingAE: string;\n readonly calledAE: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface AssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for C_STORE_REQUEST event. */\ninterface CStoreRequestData {\n readonly raw: string;\n}\n\n/** Data for STORED_FILE event. */\ninterface StoredFileData {\n readonly filePath: string;\n}\n\n/** Data for REFUSING_ASSOCIATION event. */\ninterface RefusingAssociationData {\n readonly reason: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface CannotStartListenerData {\n readonly message: string;\n}\n\n/** Data for FILE_RECEIVED synthetic event. */\ninterface FileReceivedData {\n readonly filePath: string;\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Data for ASSOCIATION_COMPLETE synthetic event. */\ninterface AssociationCompleteData {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly durationMs: number;\n readonly endReason: 'release' | 'abort';\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmrecv verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmrecv verbose output. */\nconst DCMRECV_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmrecvEvent.LISTENING,\n pattern: /listening/i,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{1,100}(\\S+):\\s+(\\S+)\\s+->\\s+(\\S+)/,\n processor: (match): AssociationReceivedData => ({\n source: match[1] ?? '',\n callingAE: match[2] ?? '',\n calledAE: match[3] ?? '',\n }),\n },\n {\n event: DcmrecvEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): AssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmrecvEvent.C_STORE_REQUEST,\n pattern: /Received Store Request/i,\n processor: (match): CStoreRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmrecvEvent.STORED_FILE,\n pattern: /Stored received object to file:\\s{0,20}(.{1,1024})/,\n processor: (match): StoredFileData => ({\n filePath: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmrecvEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.ASSOCIATION_ABORTED,\n pattern: /Received Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.ECHO_REQUEST,\n pattern: /Received C-ECHO Request/,\n processor: () => undefined,\n },\n {\n event: DcmrecvEvent.CANNOT_START_LISTENER,\n pattern: /cannot (?:start SCP and )?listen on port/i,\n processor: (match): CannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmrecvEvent.REFUSING_ASSOCIATION,\n pattern: /Refusing Association\\s{0,20}\\((.{1,500})\\)/,\n processor: (match): RefusingAssociationData => ({\n reason: match[1] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMRECV_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmrecvEvent.CANNOT_START_LISTENER]);\n\nexport { DcmrecvEvent, DCMRECV_PATTERNS, DCMRECV_FATAL_EVENTS };\nexport type {\n DcmrecvEventValue,\n AssociationReceivedData,\n AssociationAcknowledgedData,\n CStoreRequestData,\n StoredFileData,\n RefusingAssociationData,\n CannotStartListenerData,\n FileReceivedData,\n AssociationCompleteData,\n};\n","/**\n * Pure state machine tracking DICOM association lifecycle.\n *\n * No I/O, no async, no EventEmitter — just state transitions.\n * Used by Dcmrecv and StoreSCP to correlate files to associations.\n *\n * State machine:\n * ```\n * IDLE -> [beginAssociation] -> ACTIVE -> [trackFile]* -> [endAssociation] -> IDLE\n * ```\n *\n * This single-slot design is safe because all DCMTK server binaries\n * (dcmrecv, storescp, etc.) are single-threaded and handle one\n * association at a time. Concurrent connections queue at the TCP level,\n * so associations never interleave in the output stream.\n *\n * @module servers/AssociationTracker\n */\n\n// ---------------------------------------------------------------------------\n// Interfaces\n// ---------------------------------------------------------------------------\n\n/** Context for the currently active association. */\ninterface AssociationContext {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly startTime: number;\n readonly files: string[];\n}\n\n/** A file enriched with association context. */\ninterface TrackedFile {\n readonly filePath: string;\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Summary emitted when an association completes. */\ninterface AssociationSummary {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly durationMs: number;\n readonly endReason: 'release' | 'abort';\n}\n\n// ---------------------------------------------------------------------------\n// AssociationTracker class\n// ---------------------------------------------------------------------------\n\n/**\n * Tracks DICOM association lifecycle for file-to-source correlation.\n *\n * Maintains a simple IDLE/ACTIVE state machine. While active, all tracked\n * files are enriched with the current association context. Only one\n * association can be active at a time — this is safe because DCMTK\n * servers are single-threaded and process associations sequentially.\n *\n * @example\n * ```ts\n * const tracker = new AssociationTracker();\n * const id = tracker.beginAssociation({ callingAE: 'SCU', calledAE: 'SCP', source: 'db' });\n * const file = tracker.trackFile('/path/to/received.dcm');\n * const summary = tracker.endAssociation('release');\n * ```\n */\nclass AssociationTracker {\n private association: AssociationContext | undefined;\n private counter = 0;\n\n /**\n * Begins a new association, transitioning from IDLE to ACTIVE.\n *\n * If an association is already active, it is silently ended (abort)\n * and the new one begins.\n *\n * @param data - Association metadata\n * @returns The unique association ID\n */\n beginAssociation(data: { readonly callingAE: string; readonly calledAE: string; readonly source: string }): string {\n this.counter++;\n const associationId = `assoc-${String(this.counter)}`;\n this.association = {\n associationId,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n startTime: Date.now(),\n files: [],\n };\n return associationId;\n }\n\n /**\n * Tracks a file received during the current association.\n *\n * If no association is active, returns a TrackedFile with empty context.\n *\n * @param filePath - Path to the received file\n * @returns A TrackedFile enriched with association context\n */\n trackFile(filePath: string): TrackedFile {\n if (this.association === undefined) {\n return {\n filePath,\n associationId: '',\n callingAE: '',\n calledAE: '',\n source: '',\n };\n }\n this.association.files.push(filePath);\n return {\n filePath,\n associationId: this.association.associationId,\n callingAE: this.association.callingAE,\n calledAE: this.association.calledAE,\n source: this.association.source,\n };\n }\n\n /**\n * Ends the current association, transitioning from ACTIVE to IDLE.\n *\n * @param reason - Why the association ended\n * @returns An AssociationSummary, or undefined if no association was active\n */\n endAssociation(reason: 'release' | 'abort'): AssociationSummary | undefined {\n if (this.association === undefined) return undefined;\n\n const summary: AssociationSummary = {\n associationId: this.association.associationId,\n callingAE: this.association.callingAE,\n calledAE: this.association.calledAE,\n source: this.association.source,\n files: [...this.association.files],\n durationMs: Date.now() - this.association.startTime,\n endReason: reason,\n };\n\n this.association = undefined;\n return summary;\n }\n\n /** The currently active association context, or undefined. */\n get current(): AssociationContext | undefined {\n return this.association;\n }\n\n /** Whether an association is currently active. */\n get isActive(): boolean {\n return this.association !== undefined;\n }\n\n /** Resets the tracker to IDLE, discarding any active association. */\n reset(): void {\n this.association = undefined;\n }\n}\n\nexport { AssociationTracker };\nexport type { AssociationContext, TrackedFile, AssociationSummary };\n","/**\n * DICOM receiver server wrapping the dcmrecv binary.\n *\n * Provides a type-safe, event-driven API for receiving DICOM objects\n * via C-STORE. Uses a static factory pattern because binary resolution\n * must happen before the constructor call.\n *\n * @module servers/Dcmrecv\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath, isValidAETitle } from '../patterns';\nimport { DcmrecvEvent, DCMRECV_PATTERNS, DCMRECV_FATAL_EVENTS } from '../events/dcmrecv';\nimport type {\n AssociationReceivedData,\n AssociationAcknowledgedData,\n CStoreRequestData,\n StoredFileData,\n RefusingAssociationData,\n CannotStartListenerData,\n FileReceivedData,\n AssociationCompleteData,\n} from '../events/dcmrecv';\nimport { AssociationTracker } from './AssociationTracker';\n\n// ---------------------------------------------------------------------------\n// Event map type (for documentation — consumers see typed overloads on class)\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the Dcmrecv server. */\ninterface DcmrecvEventMap {\n LISTENING: [];\n ASSOCIATION_RECEIVED: [AssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [AssociationAcknowledgedData];\n C_STORE_REQUEST: [CStoreRequestData];\n STORED_FILE: [StoredFileData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n ECHO_REQUEST: [];\n CANNOT_START_LISTENER: [CannotStartListenerData];\n REFUSING_ASSOCIATION: [RefusingAssociationData];\n FILE_RECEIVED: [FileReceivedData];\n ASSOCIATION_COMPLETE: [AssociationCompleteData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Subdirectory generation mode for received files. */\nconst SubdirectoryMode = {\n NONE: 'none',\n SERIES_DATE: 'series-date',\n} as const;\n\ntype SubdirectoryModeValue = (typeof SubdirectoryMode)[keyof typeof SubdirectoryMode];\n\n/** Filename generation mode for received files. */\nconst FilenameMode = {\n DEFAULT: 'default',\n UNIQUE: 'unique',\n SHORT_UNIQUE: 'short-unique',\n SYSTEM_TIME: 'system-time',\n} as const;\n\ntype FilenameModeValue = (typeof FilenameMode)[keyof typeof FilenameMode];\n\n/** Storage mode for received DICOM objects. */\nconst StorageMode = {\n NORMAL: 'normal',\n BIT_PRESERVING: 'bit-preserving',\n IGNORE: 'ignore',\n} as const;\n\ntype StorageModeValue = (typeof StorageMode)[keyof typeof StorageMode];\n\n/** Options for creating a Dcmrecv server instance. */\ninterface DcmrecvOptions {\n /** Port to listen on (required). */\n readonly port: number;\n /** Application Entity Title. */\n readonly aeTitle?: string | undefined;\n /** Output directory for received files. */\n readonly outputDirectory?: string | undefined;\n /** Path to an association negotiation configuration file. */\n readonly configFile?: string | undefined;\n /** Profile name within the configuration file. */\n readonly configProfile?: string | undefined;\n /** Subdirectory generation mode. */\n readonly subdirectory?: SubdirectoryModeValue | undefined;\n /** Filename generation mode. */\n readonly filenameMode?: FilenameModeValue | undefined;\n /** File extension for received files. */\n readonly filenameExtension?: string | undefined;\n /** Storage mode for received DICOM objects. */\n readonly storageMode?: StorageModeValue | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmrecvOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n aeTitle: z.string().min(1).max(16).refine(isValidAETitle, { message: 'AE Title contains invalid characters' }).optional(),\n outputDirectory: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in outputDirectory' }).optional(),\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }).optional(),\n configProfile: z.string().min(1).optional(),\n subdirectory: z.enum(['none', 'series-date']).optional(),\n filenameMode: z.enum(['default', 'unique', 'short-unique', 'system-time']).optional(),\n filenameExtension: z.string().min(1).optional(),\n storageMode: z.enum(['normal', 'bit-preserving', 'ignore']).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builders (each <= 40 lines)\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmrecvOptions): string[] {\n const args: string[] = ['--verbose'];\n\n if (options.aeTitle !== undefined) {\n args.push('--aetitle', options.aeTitle);\n }\n if (options.outputDirectory !== undefined) {\n args.push('--output-directory', options.outputDirectory);\n }\n if (options.configFile !== undefined && options.configProfile !== undefined) {\n args.push('--config-file', options.configFile, options.configProfile);\n }\n\n addFilenameArgs(args, options);\n addStorageArgs(args, options);\n addNetworkArgs(args, options);\n\n args.push(String(options.port));\n return args;\n}\n\n/** Appends filename-related CLI flags. */\nfunction addFilenameArgs(args: string[], options: DcmrecvOptions): void {\n if (options.subdirectory === 'series-date') {\n args.push('--sort-on-patientsname');\n }\n if (options.filenameMode === 'unique') {\n args.push('--unique-filenames');\n } else if (options.filenameMode === 'short-unique') {\n args.push('--short-unique-filenames');\n } else if (options.filenameMode === 'system-time') {\n args.push('--system-time-filenames');\n }\n if (options.filenameExtension !== undefined) {\n args.push('--filename-extension', options.filenameExtension);\n }\n}\n\n/** Appends storage-related CLI flags. */\nfunction addStorageArgs(args: string[], options: DcmrecvOptions): void {\n if (options.storageMode === 'bit-preserving') {\n args.push('--bit-preserving');\n } else if (options.storageMode === 'ignore') {\n args.push('--ignore');\n }\n}\n\n/** Appends network-related CLI flags. */\nfunction addNetworkArgs(args: string[], options: DcmrecvOptions): void {\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Dcmrecv class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM receiver server wrapping the dcmrecv binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Server-specific events (LISTENING, STORED_FILE, etc.) are emitted dynamically\n * via the LineParser. Use `onEvent()` for typed listeners on server events.\n *\n * @example\n * ```ts\n * const result = Dcmrecv.create({ port: 11112, outputDirectory: '/tmp/received' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('STORED_FILE', (data) => console.log('Stored:', data.filePath));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass Dcmrecv extends DcmtkProcess {\n private readonly parser: LineParser;\n private readonly tracker: AssociationTracker;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.tracker = new AssociationTracker();\n this.wireParser();\n this.wireTracker();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /**\n * Registers a typed listener for a dcmrecv-specific event.\n *\n * @param event - The event name from DcmrecvEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n onEvent<K extends keyof DcmrecvEventMap>(event: K, listener: (...args: DcmrecvEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (...args: DcmrecvEventMap['ASSOCIATION_RECEIVED']) => void): this {\n return this.onEvent('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for stored files.\n *\n * @param listener - Callback receiving stored file data\n * @returns this for chaining\n */\n onStoredFile(listener: (...args: DcmrecvEventMap['STORED_FILE']) => void): this {\n return this.onEvent('STORED_FILE', listener);\n }\n\n /**\n * Registers a listener for received files enriched with association context.\n *\n * @param listener - Callback receiving tracked file data\n * @returns this for chaining\n */\n onFileReceived(listener: (...args: DcmrecvEventMap['FILE_RECEIVED']) => void): this {\n return this.onEvent('FILE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for completed associations.\n *\n * @param listener - Callback receiving association summary\n * @returns this for chaining\n */\n onAssociationComplete(listener: (...args: DcmrecvEventMap['ASSOCIATION_COMPLETE']) => void): this {\n return this.onEvent('ASSOCIATION_COMPLETE', listener);\n }\n\n /**\n * Creates a new Dcmrecv server instance.\n *\n * @param options - Configuration options for the dcmrecv server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmrecvOptions): Result<Dcmrecv> {\n const validation = DcmrecvOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmrecv', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmrecv');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMRECV_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n isStartedPredicate: line => /listening/i.test(line),\n };\n\n return ok(new Dcmrecv(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMRECV_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires the AssociationTracker to server events. */\n private wireTracker(): void {\n this.onEvent('ASSOCIATION_RECEIVED', data => {\n this.tracker.beginAssociation(data);\n });\n\n this.onEvent('STORED_FILE', data => {\n const tracked = this.tracker.trackFile(data.filePath);\n this.emit(DcmrecvEvent.FILE_RECEIVED as string, tracked);\n });\n\n this.onEvent('ASSOCIATION_RELEASE', () => {\n const summary = this.tracker.endAssociation('release');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n\n this.onEvent('ASSOCIATION_ABORTED', () => {\n const summary = this.tracker.endAssociation('abort');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { Dcmrecv, SubdirectoryMode, FilenameMode, StorageMode };\nexport type { DcmrecvOptions, DcmrecvEventMap, SubdirectoryModeValue, FilenameModeValue, StorageModeValue };\n","/**\n * Event patterns and types for storescp output parsing.\n *\n * Extends dcmrecv patterns with storescp-specific events like\n * file storage progress and subdirectory creation.\n *\n * @module events/storescp\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\nimport { DcmrecvEvent, DCMRECV_PATTERNS, DCMRECV_FATAL_EVENTS } from './dcmrecv';\nimport type { AssociationReceivedData } from './dcmrecv';\n\n// ---------------------------------------------------------------------------\n// Event constants (superset of dcmrecv — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by storescp process output. */\nconst StorescpEvent = {\n ...DcmrecvEvent,\n STORING_FILE: 'STORING_FILE',\n SUBDIRECTORY_CREATED: 'SUBDIRECTORY_CREATED',\n} as const;\n\ntype StorescpEventValue = (typeof StorescpEvent)[keyof typeof StorescpEvent];\n\n// ---------------------------------------------------------------------------\n// Additional event data interfaces\n// ---------------------------------------------------------------------------\n\n/** Data for STORING_FILE event. */\ninterface StoringFileData {\n readonly filePath: string;\n}\n\n/** Data for SUBDIRECTORY_CREATED event. */\ninterface SubdirectoryCreatedData {\n readonly directory: string;\n}\n\n// ---------------------------------------------------------------------------\n// storescp-specific patterns\n// ---------------------------------------------------------------------------\n\n/**\n * storescp-specific ASSOCIATION_RECEIVED pattern.\n * storescp --verbose outputs only \"Association Received\" (no AE details),\n * so this pattern returns empty fields for source/callingAE/calledAE.\n */\nconst STORESCP_ASSOCIATION_RECEIVED: EventPattern = {\n event: StorescpEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received/i,\n processor: (): AssociationReceivedData => ({ source: '', callingAE: '', calledAE: '' }),\n};\n\nconst STORESCP_ADDITIONAL_PATTERNS: readonly EventPattern[] = [\n {\n event: StorescpEvent.STORING_FILE,\n pattern: /storing DICOM file:\\s{0,20}(.{1,1024})/i,\n processor: (match): StoringFileData => ({\n filePath: (match[1] ?? '').trim(),\n }),\n },\n {\n event: StorescpEvent.SUBDIRECTORY_CREATED,\n pattern: /created new subdirectory[:\\s]{0,20}(.{1,1024})/i,\n processor: (match): SubdirectoryCreatedData => ({\n directory: (match[1] ?? '').trim(),\n }),\n },\n];\n\n/** Combined event patterns for parsing storescp verbose output. */\nconst STORESCP_PATTERNS: readonly EventPattern[] = [\n ...DCMRECV_PATTERNS.filter(p => p.event !== DcmrecvEvent.ASSOCIATION_RECEIVED),\n STORESCP_ASSOCIATION_RECEIVED,\n ...STORESCP_ADDITIONAL_PATTERNS,\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst STORESCP_FATAL_EVENTS: ReadonlySet<string> = new Set([...DCMRECV_FATAL_EVENTS]);\n\nexport { StorescpEvent, STORESCP_PATTERNS, STORESCP_FATAL_EVENTS };\nexport type { StorescpEventValue, StoringFileData, SubdirectoryCreatedData };\n","/**\n * DICOM Storage SCP server wrapping the storescp binary.\n *\n * Provides a type-safe, event-driven API for receiving DICOM objects\n * via the storescp command-line tool. Supports sorting, exec hooks,\n * custom transfer syntaxes, and all standard storescp options.\n *\n * @module servers/StoreSCP\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath, isValidAETitle } from '../patterns';\nimport { STORESCP_PATTERNS, STORESCP_FATAL_EVENTS } from '../events/storescp';\nimport { DcmrecvEvent } from '../events/dcmrecv';\nimport type {\n AssociationReceivedData,\n AssociationAcknowledgedData,\n CStoreRequestData,\n StoredFileData,\n RefusingAssociationData,\n CannotStartListenerData,\n FileReceivedData,\n AssociationCompleteData,\n} from '../events/dcmrecv';\nimport type { StoringFileData, SubdirectoryCreatedData } from '../events/storescp';\nimport { AssociationTracker } from './AssociationTracker';\n\n// ---------------------------------------------------------------------------\n// Event map type (for documentation — consumers see typed overloads on class)\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the StoreSCP server. */\ninterface StoreSCPEventMap {\n LISTENING: [];\n ASSOCIATION_RECEIVED: [AssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [AssociationAcknowledgedData];\n C_STORE_REQUEST: [CStoreRequestData];\n STORED_FILE: [StoredFileData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n ECHO_REQUEST: [];\n CANNOT_START_LISTENER: [CannotStartListenerData];\n REFUSING_ASSOCIATION: [RefusingAssociationData];\n STORING_FILE: [StoringFileData];\n SUBDIRECTORY_CREATED: [SubdirectoryCreatedData];\n FILE_RECEIVED: [FileReceivedData];\n ASSOCIATION_COMPLETE: [AssociationCompleteData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Preferred transfer syntax for incoming associations. */\nconst PreferredTransferSyntax = {\n LITTLE_ENDIAN: 'little-endian',\n BIG_ENDIAN: 'big-endian',\n IMPLICIT: 'implicit',\n ACCEPT_ALL: 'accept-all',\n} as const;\n\ntype PreferredTransferSyntaxValue = (typeof PreferredTransferSyntax)[keyof typeof PreferredTransferSyntax];\n\n/** Options for creating a StoreSCP server instance. */\ninterface StoreSCPOptions {\n /** Port to listen on (required). */\n readonly port: number;\n /** Application Entity Title. */\n readonly aeTitle?: string | undefined;\n /** Output directory for received files. */\n readonly outputDirectory?: string | undefined;\n /** Path to an association negotiation configuration file. */\n readonly configFile?: string | undefined;\n /** Profile name within the configuration file. */\n readonly configProfile?: string | undefined;\n /** Preferred transfer syntax (not valid with configFile). */\n readonly preferredTransferSyntax?: PreferredTransferSyntaxValue | undefined;\n /** Sort studies into subdirectories. */\n readonly sortByStudy?: boolean | undefined;\n /** Sort by Study Instance UID. */\n readonly sortByStudyUID?: boolean | undefined;\n /** Sort by patient name. */\n readonly sortByPatientName?: boolean | undefined;\n /** Generate unique filenames. */\n readonly uniqueFilenames?: boolean | undefined;\n /** Use bit-preserving mode. */\n readonly bitPreserving?: boolean | undefined;\n /** Execute command on each received file. */\n readonly execOnReception?: string | undefined;\n /** Execute command at end of study. */\n readonly execOnEndOfStudy?: string | undefined;\n /** Timeout for end-of-study detection in seconds (passed to DCMTK as-is). */\n readonly endOfStudyTimeout?: number | undefined;\n /** Rename files at end of study. */\n readonly renameOnEndOfStudy?: boolean | undefined;\n /** Socket timeout in seconds (passed to DCMTK as-is). */\n readonly socketTimeout?: number | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** Filename extension for received files. */\n readonly filenameExtension?: string | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Configuration presets\n// ---------------------------------------------------------------------------\n\n/**\n * Pre-configured option sets for common StoreSCP deployment patterns.\n * Spread a preset into your options to avoid specifying boilerplate.\n *\n * @example\n * ```ts\n * StoreSCP.create({ ...StoreSCPPreset.PRODUCTION, port: 11112, outputDirectory: '/data' });\n * ```\n */\nconst StoreSCPPreset = {\n /** Basic storage: unique filenames to avoid collisions. */\n BASIC_STORAGE: {\n uniqueFilenames: true,\n },\n /** Testing: unique filenames, preserving raw transfer syntax. */\n TESTING: {\n uniqueFilenames: true,\n bitPreserving: true,\n },\n /** Production: unique filenames with reasonable timeouts. */\n PRODUCTION: {\n uniqueFilenames: true,\n acseTimeout: 30,\n dimseTimeout: 60,\n },\n} as const satisfies Record<string, Partial<StoreSCPOptions>>;\n\n/** Names of the available StoreSCP configuration presets. */\ntype StoreSCPPresetName = keyof typeof StoreSCPPreset;\n\nconst StoreSCPOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n aeTitle: z.string().min(1).max(16).refine(isValidAETitle, { message: 'AE Title contains invalid characters' }).optional(),\n outputDirectory: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in outputDirectory' }).optional(),\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }).optional(),\n configProfile: z.string().min(1).optional(),\n preferredTransferSyntax: z.enum(['little-endian', 'big-endian', 'implicit', 'accept-all']).optional(),\n sortByStudy: z.boolean().optional(),\n sortByStudyUID: z.boolean().optional(),\n sortByPatientName: z.boolean().optional(),\n uniqueFilenames: z.boolean().optional(),\n bitPreserving: z.boolean().optional(),\n execOnReception: z.string().min(1).optional(),\n execOnEndOfStudy: z.string().min(1).optional(),\n endOfStudyTimeout: z.number().int().positive().optional(),\n renameOnEndOfStudy: z.boolean().optional(),\n socketTimeout: z.number().int().positive().optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n filenameExtension: z.string().min(1).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builders (each <= 40 lines)\n// ---------------------------------------------------------------------------\n\n/** Builds the full CLI arguments array. */\nfunction buildArgs(options: StoreSCPOptions): string[] {\n const args: string[] = ['--verbose'];\n\n if (options.aeTitle !== undefined) {\n args.push('--aetitle', options.aeTitle);\n }\n if (options.configFile !== undefined && options.configProfile !== undefined) {\n args.push('--config-file', options.configFile, options.configProfile);\n }\n\n buildTransferSyntaxArgs(args, options);\n buildSortArgs(args, options);\n buildOutputArgs(args, options);\n buildNetworkArgs(args, options);\n buildExecArgs(args, options);\n\n args.push(String(options.port));\n return args;\n}\n\n/** Appends transfer syntax CLI flags. */\nfunction buildTransferSyntaxArgs(args: string[], options: StoreSCPOptions): void {\n if (options.preferredTransferSyntax === 'little-endian') {\n args.push('+xe');\n } else if (options.preferredTransferSyntax === 'big-endian') {\n args.push('+xb');\n } else if (options.preferredTransferSyntax === 'implicit') {\n args.push('+xi');\n } else if (options.preferredTransferSyntax === 'accept-all') {\n args.push('+xa');\n }\n}\n\n/** Appends sorting-related CLI flags. */\nfunction buildSortArgs(args: string[], options: StoreSCPOptions): void {\n if (options.sortByStudy === true) {\n args.push('--sort-conc-studies');\n }\n if (options.sortByStudyUID === true) {\n args.push('--sort-on-study-uid');\n }\n if (options.sortByPatientName === true) {\n args.push('--sort-on-patientsname');\n }\n}\n\n/** Appends output-related CLI flags. */\nfunction buildOutputArgs(args: string[], options: StoreSCPOptions): void {\n if (options.outputDirectory !== undefined) {\n args.push('--output-directory', options.outputDirectory);\n }\n if (options.uniqueFilenames === true) {\n args.push('--unique-filenames');\n }\n if (options.bitPreserving === true) {\n args.push('--bit-preserving');\n }\n if (options.filenameExtension !== undefined) {\n args.push('--filename-extension', options.filenameExtension);\n }\n}\n\n/** Appends network-related CLI flags. */\nfunction buildNetworkArgs(args: string[], options: StoreSCPOptions): void {\n if (options.socketTimeout !== undefined) {\n args.push('--socket-timeout', String(options.socketTimeout));\n }\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n}\n\n/** Appends exec-related CLI flags. */\nfunction buildExecArgs(args: string[], options: StoreSCPOptions): void {\n if (options.execOnReception !== undefined) {\n args.push('--exec-on-reception', options.execOnReception);\n }\n if (options.execOnEndOfStudy !== undefined) {\n args.push('--exec-on-eostudy', options.execOnEndOfStudy);\n }\n if (options.endOfStudyTimeout !== undefined) {\n args.push('--eostudy-timeout', String(options.endOfStudyTimeout));\n }\n if (options.renameOnEndOfStudy === true) {\n args.push('--rename-on-eostudy');\n }\n}\n\n// ---------------------------------------------------------------------------\n// StoreSCP class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Storage SCP server wrapping the storescp binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Note: storescp does not print a \"listening\" message, so `start()` resolves\n * on spawn. If the port is busy, storescp exits immediately and `start()`\n * returns an error via the close handler.\n *\n * Server-specific events are emitted dynamically via the LineParser.\n * Use `onEvent()` for typed listeners on server events.\n *\n * @example\n * ```ts\n * const result = StoreSCP.create({ port: 11112, outputDirectory: '/tmp/received' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('STORED_FILE', (data) => console.log('Stored:', data.filePath));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass StoreSCP extends DcmtkProcess {\n private readonly parser: LineParser;\n private readonly tracker: AssociationTracker;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.tracker = new AssociationTracker();\n this.wireParser();\n this.wireTracker();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n /**\n * Registers a typed listener for a storescp-specific event.\n *\n * @param event - The event name from StoreSCPEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof StoreSCPEventMap>(event: K, listener: (...args: StoreSCPEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (...args: StoreSCPEventMap['ASSOCIATION_RECEIVED']) => void): this {\n return this.onEvent('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for files being stored to disk.\n *\n * @param listener - Callback receiving storing file data\n * @returns this for chaining\n */\n onStoringFile(listener: (...args: StoreSCPEventMap['STORING_FILE']) => void): this {\n return this.onEvent('STORING_FILE', listener);\n }\n\n /**\n * Registers a listener for received files enriched with association context.\n *\n * @param listener - Callback receiving tracked file data\n * @returns this for chaining\n */\n onFileReceived(listener: (...args: StoreSCPEventMap['FILE_RECEIVED']) => void): this {\n return this.onEvent('FILE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for completed associations.\n *\n * @param listener - Callback receiving association summary\n * @returns this for chaining\n */\n onAssociationComplete(listener: (...args: StoreSCPEventMap['ASSOCIATION_COMPLETE']) => void): this {\n return this.onEvent('ASSOCIATION_COMPLETE', listener);\n }\n\n /**\n * Creates a new StoreSCP server instance.\n *\n * @param options - Configuration options for the storescp server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: StoreSCPOptions): Result<StoreSCP> {\n const validation = StoreSCPOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('storescp', validation.error));\n }\n\n const binaryResult = resolveBinary('storescp');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of STORESCP_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n // storescp doesn't print \"listening\" — resolve on spawn\n };\n\n return ok(new StoreSCP(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (STORESCP_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires the AssociationTracker to server events. */\n private wireTracker(): void {\n this.onEvent('ASSOCIATION_RECEIVED', data => {\n this.tracker.beginAssociation(data);\n });\n\n // storescp outputs \"storing DICOM file:\" (STORING_FILE), not\n // \"Stored received object to file:\" (STORED_FILE) like dcmrecv.\n // Listen to both so the tracker works regardless of which fires.\n this.onEvent('STORING_FILE', data => {\n const tracked = this.tracker.trackFile(data.filePath);\n this.emit(DcmrecvEvent.FILE_RECEIVED as string, tracked);\n });\n\n this.onEvent('STORED_FILE', data => {\n const tracked = this.tracker.trackFile(data.filePath);\n this.emit(DcmrecvEvent.FILE_RECEIVED as string, tracked);\n });\n\n this.onEvent('ASSOCIATION_RELEASE', () => {\n const summary = this.tracker.endAssociation('release');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n\n this.onEvent('ASSOCIATION_ABORTED', () => {\n const summary = this.tracker.endAssociation('abort');\n if (summary !== undefined) {\n this.emit(DcmrecvEvent.ASSOCIATION_COMPLETE as string, summary);\n }\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { StoreSCP, PreferredTransferSyntax, StoreSCPPreset };\nexport type { StoreSCPOptions, StoreSCPEventMap, PreferredTransferSyntaxValue, StoreSCPPresetName };\n","/**\n * Shared filesystem utilities returning Result types.\n *\n * @module utils/fs\n */\n\nimport { mkdir, rename, copyFile, unlink, stat, rm } from 'node:fs/promises';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\n\n/**\n * Ensures a directory exists, creating it recursively if needed.\n *\n * @param dirPath - Directory path to create\n * @returns A Result indicating success or failure\n */\nasync function ensureDirectory(dirPath: string): Promise<Result<void>> {\n try {\n await mkdir(dirPath, { recursive: true });\n return ok(undefined);\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n return err(new Error(`Failed to create directory ${dirPath}: ${msg}`));\n }\n}\n\n/**\n * Moves a file from src to dest, falling back to copy+delete on cross-device.\n *\n * @param src - Source file path\n * @param dest - Destination file path\n * @returns A Result indicating success or failure\n */\nasync function moveFile(src: string, dest: string): Promise<Result<void>> {\n try {\n await rename(src, dest);\n return ok(undefined);\n } catch {\n try {\n await copyFile(src, dest);\n await unlink(src);\n return ok(undefined);\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n return err(new Error(`Failed to move file ${src} → ${dest}: ${msg}`));\n }\n }\n}\n\n/**\n * Returns the file size in bytes, or 0 on error.\n *\n * @param filePath - Path to the file\n * @returns The file size in bytes, or 0 if the file cannot be stat'd\n */\nasync function statFileSafe(filePath: string): Promise<number> {\n try {\n const s = await stat(filePath);\n return s.size;\n } catch {\n /* v8 ignore next */\n return 0;\n }\n}\n\n/**\n * Removes a directory recursively, ignoring errors.\n *\n * @param dirPath - Directory path to remove\n */\nasync function removeDirSafe(dirPath: string): Promise<void> {\n try {\n await rm(dirPath, { recursive: true, force: true });\n } catch {\n /* best-effort cleanup */\n }\n}\n\nexport { ensureDirectory, moveFile, statFileSafe, removeDirSafe };\n","/**\n * Branded types for domain primitives.\n *\n * Branded types use TypeScript's structural type system to prevent accidental\n * mixing of semantically different values that share the same underlying type.\n * A `DicomTag` cannot be used where an `AETitle` is expected, even though both\n * are strings at runtime.\n *\n * @module brands\n */\n\nimport { normalize } from 'node:path';\nimport type { Result } from './types';\nimport { ok, err } from './types';\nimport {\n DICOM_TAG_PATTERN,\n AE_TITLE_PATTERN,\n UID_PATTERN,\n DICOM_TAG_PATH_PATTERN,\n AE_TITLE_MIN_LENGTH,\n AE_TITLE_MAX_LENGTH,\n UID_MAX_LENGTH,\n PORT_MIN,\n PORT_MAX,\n PATH_TRAVERSAL_PATTERN,\n} from './patterns';\n\ndeclare const __brand: unique symbol;\n\n/** Intersects a base type with a phantom brand property for nominal typing. */\ntype Brand<T, TBrand extends string> = T & { readonly [__brand]: TBrand };\n\n// ---------------------------------------------------------------------------\n// Branded types\n// ---------------------------------------------------------------------------\n\n/**\n * A validated DICOM tag string, e.g. `\"(0010,0010)\"`.\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createDicomTag} to obtain a branded value from a raw string.\n */\ntype DicomTag = Brand<string, 'DicomTag'>;\n\n/**\n * A validated AE Title (1-16 chars: uppercase letters, digits, spaces, hyphens).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createAETitle} to obtain a branded value from a raw string.\n */\ntype AETitle = Brand<string, 'AETitle'>;\n\n/**\n * A validated DICOM tag path, e.g. `\"(0040,A730)[0].(0010,0010)\"`.\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createDicomTagPath} to obtain a branded value from a raw string.\n */\ntype DicomTagPath = Brand<string, 'DicomTagPath'>;\n\n/**\n * A validated SOP Class UID (dotted numeric OID, 1-64 chars).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createSOPClassUID} to obtain a branded value from a raw string.\n */\ntype SOPClassUID = Brand<string, 'SOPClassUID'>;\n\n/**\n * A validated Transfer Syntax UID (dotted numeric OID, 1-64 chars).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createTransferSyntaxUID} to obtain a branded value from a raw string.\n */\ntype TransferSyntaxUID = Brand<string, 'TransferSyntaxUID'>;\n\n/**\n * A validated filesystem path to a DICOM file.\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createDicomFilePath} to obtain a branded value from a raw string.\n */\ntype DicomFilePath = Brand<string, 'DicomFilePath'>;\n\n/**\n * A validated network port number (1-65535).\n *\n * @remarks\n * Branded types enforce type safety when passing values between functions.\n * They are not required for direct API calls (which validate internally via Zod).\n * Use {@link createPort} to obtain a branded value from a raw number.\n */\ntype Port = Brand<number, 'Port'>;\n\n// Validation patterns and constants imported from ./patterns\n\n// ---------------------------------------------------------------------------\n// Factory functions\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a validated DicomTag from a raw string.\n *\n * @param input - A string expected to be in format `(XXXX,XXXX)` where X is a hex digit\n * @returns A Result containing the branded DicomTag or an error\n */\nfunction createDicomTag(input: string): Result<DicomTag> {\n if (!DICOM_TAG_PATTERN.test(input)) {\n return err(new Error(`Invalid DICOM tag: \"${input}\". Expected format (XXXX,XXXX) where X is a hex digit`));\n }\n return ok(input as DicomTag);\n}\n\n/**\n * Creates a validated AETitle from a raw string.\n *\n * @param input - A string expected to be 1-16 printable ASCII chars (no backslash)\n * @returns A Result containing the branded AETitle or an error\n */\nfunction createAETitle(input: string): Result<AETitle> {\n if (input.length < AE_TITLE_MIN_LENGTH || input.length > AE_TITLE_MAX_LENGTH) {\n return err(new Error(`Invalid AE Title: \"${input}\". Must be ${AE_TITLE_MIN_LENGTH}-${AE_TITLE_MAX_LENGTH} characters`));\n }\n if (!AE_TITLE_PATTERN.test(input)) {\n return err(new Error(`Invalid AE Title: \"${input}\". Only printable ASCII characters (no backslash) are allowed`));\n }\n return ok(input as AETitle);\n}\n\n/**\n * Creates a validated DicomTagPath from a raw string.\n *\n * @param input - A dot-separated path of DICOM tags with optional array indices\n * @returns A Result containing the branded DicomTagPath or an error\n */\nfunction createDicomTagPath(input: string): Result<DicomTagPath> {\n // Empty check is duplicated in the Zod DicomTagPathSchema (.min(1)), but\n // kept here for a clearer error message from the brands factory.\n if (input.length === 0) {\n return err(new Error('Invalid DICOM tag path: empty string'));\n }\n if (!DICOM_TAG_PATH_PATTERN.test(input)) {\n return err(new Error(`Invalid DICOM tag path: \"${input}\". Expected format like (XXXX,XXXX) or (XXXX,XXXX)[0].(XXXX,XXXX)`));\n }\n return ok(input as DicomTagPath);\n}\n\n/**\n * Creates a validated SOPClassUID from a raw string.\n *\n * @param input - A dotted numeric OID string, 1-64 characters\n * @returns A Result containing the branded SOPClassUID or an error\n */\nfunction createSOPClassUID(input: string): Result<SOPClassUID> {\n if (input.length === 0 || input.length > UID_MAX_LENGTH) {\n return err(new Error(`Invalid SOP Class UID: \"${input}\". Must be 1-${UID_MAX_LENGTH} characters`));\n }\n if (!UID_PATTERN.test(input)) {\n return err(new Error(`Invalid SOP Class UID: \"${input}\". Must be a dotted numeric OID`));\n }\n return ok(input as SOPClassUID);\n}\n\n/**\n * Creates a validated TransferSyntaxUID from a raw string.\n *\n * @param input - A dotted numeric OID string, 1-64 characters\n * @returns A Result containing the branded TransferSyntaxUID or an error\n */\nfunction createTransferSyntaxUID(input: string): Result<TransferSyntaxUID> {\n if (input.length === 0 || input.length > UID_MAX_LENGTH) {\n return err(new Error(`Invalid Transfer Syntax UID: \"${input}\". Must be 1-${UID_MAX_LENGTH} characters`));\n }\n if (!UID_PATTERN.test(input)) {\n return err(new Error(`Invalid Transfer Syntax UID: \"${input}\". Must be a dotted numeric OID`));\n }\n return ok(input as TransferSyntaxUID);\n}\n\n/**\n * Creates a branded DicomFilePath from a raw string.\n * Validates that the path is non-empty and does not contain path traversal sequences.\n *\n * @param input - A filesystem path string\n * @returns A Result containing the branded DicomFilePath or an error\n */\nfunction createDicomFilePath(input: string): Result<DicomFilePath> {\n if (input.length === 0) {\n return err(new Error('Invalid DICOM file path: empty string'));\n }\n if (PATH_TRAVERSAL_PATTERN.test(input)) {\n return err(new Error(`Invalid DICOM file path: path traversal detected in \"${input}\"`));\n }\n // normalize() resolves `.` segments and trailing separators, ensuring\n // consistent path comparison regardless of input style (e.g., `a//b` → `a/b`).\n const normalized = normalize(input);\n return ok(normalized as DicomFilePath);\n}\n\n/**\n * Creates a validated Port from a raw number.\n *\n * @param input - A number expected to be an integer between 1 and 65535\n * @returns A Result containing the branded Port or an error\n */\nfunction createPort(input: number): Result<Port> {\n if (!Number.isInteger(input) || input < PORT_MIN || input > PORT_MAX) {\n return err(new Error(`Invalid port: ${String(input)}. Must be an integer between ${PORT_MIN} and ${PORT_MAX}`));\n }\n return ok(input as Port);\n}\n\n/**\n * Shorthand for creating a DicomTagPath, throwing on invalid input.\n *\n * Use this when you know the tag path is valid (e.g. hardcoded constants).\n * For user-supplied input, use {@link createDicomTagPath} which returns a Result.\n *\n * @param input - A DICOM tag path string, e.g. `'(0010,0010)'`\n * @returns The branded DicomTagPath\n * @throws Error if the input is not a valid DICOM tag path\n */\nfunction tag(input: string): DicomTagPath {\n const result = createDicomTagPath(input);\n if (!result.ok) throw result.error;\n return result.value;\n}\n\nexport { createDicomTag, createAETitle, createDicomTagPath, createSOPClassUID, createTransferSyntaxUID, createDicomFilePath, createPort, tag };\nexport type { Brand, DicomTag, AETitle, DicomTagPath, SOPClassUID, TransferSyntaxUID, DicomFilePath, Port };\n","/**\n * DICOM tag path parser and serializer.\n *\n * Provides iterative (no recursion) parsing of DICOM tag paths like\n * `(0040,A730)[0].(0040,A160)` into structured segments, and conversion\n * back to dcmodify-compatible strings.\n *\n * Supports wildcard indices `[*]` for use with DicomDataset.findValues.\n *\n * @module dicom/tagPath\n */\n\nimport type { DicomTag, DicomTagPath } from '../brands';\nimport { createDicomTag } from '../brands';\nimport { MAX_TRAVERSAL_DEPTH } from '../constants';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** A single segment of a parsed DICOM tag path. */\ninterface TagSegment {\n /** The DICOM tag for this segment. */\n readonly tag: DicomTag;\n /** The array index for sequence items, or undefined for non-sequence tags. */\n readonly index?: number | undefined;\n /** Whether this segment uses a wildcard index `[*]`. */\n readonly isWildcard?: boolean | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Patterns\n// ---------------------------------------------------------------------------\n\n// Matches a tag segment: (XXXX,XXXX) optionally followed by [N] or [*]\nconst SEGMENT_PATTERN = /^\\(([0-9A-Fa-f]{4}),([0-9A-Fa-f]{4})\\)(?:\\[(\\d+|\\*)\\])?/;\n\n// ---------------------------------------------------------------------------\n// Internal helpers (extracted for complexity/line limits)\n// ---------------------------------------------------------------------------\n\n/** Parses a single regex match into a TagSegment. */\nfunction matchToSegment(match: RegExpExecArray): TagSegment {\n const group = match[1];\n const element = match[2];\n const indexStr = match[3];\n\n /* v8 ignore next 3 */\n if (group === undefined || element === undefined) {\n throw new Error('Failed to parse tag group/element');\n }\n\n const tagResult = createDicomTag(`(${group},${element})`);\n /* v8 ignore next 2 */\n if (!tagResult.ok) throw new Error(`Invalid tag in path: (${group},${element})`);\n\n if (indexStr === '*') return { tag: tagResult.value, isWildcard: true };\n if (indexStr !== undefined) return { tag: tagResult.value, index: Number(indexStr) };\n return { tag: tagResult.value };\n}\n\n/** Advances past the current match and any dot separator. Returns the updated remaining string. */\nfunction advancePastMatch(remaining: string, matchLength: number): string {\n const after = remaining.slice(matchLength);\n if (!after.startsWith('.')) return after;\n if (after.length === 1) throw new Error('Tag path cannot end with a dot separator');\n return after.slice(1);\n}\n\n// ---------------------------------------------------------------------------\n// Parser\n// ---------------------------------------------------------------------------\n\n/**\n * Parses a DICOM tag path into an array of segments.\n *\n * Uses iterative parsing with bounded loop (Rule 8.2: no recursion).\n *\n * @param path - A branded DicomTagPath string\n * @returns An array of TagSegment objects\n * @throws Error if the path is malformed or exceeds MAX_TRAVERSAL_DEPTH\n *\n * @example\n * ```ts\n * tagPathToSegments('(0040,A730)[0].(0040,A160)' as DicomTagPath)\n * // => [\n * // { tag: '(0040,A730)' as DicomTag, index: 0 },\n * // { tag: '(0040,A160)' as DicomTag }\n * // ]\n * ```\n */\nfunction tagPathToSegments(path: DicomTagPath): ReadonlyArray<TagSegment> {\n const segments: TagSegment[] = [];\n let remaining: string = path;\n\n for (let i = 0; i < MAX_TRAVERSAL_DEPTH && remaining.length > 0; i++) {\n const match = SEGMENT_PATTERN.exec(remaining);\n if (match === null) {\n throw new Error(`Invalid tag path segment at position ${path.length - remaining.length}: \"${remaining}\"`);\n }\n segments.push(matchToSegment(match));\n remaining = advancePastMatch(remaining, match[0].length);\n }\n\n if (remaining.length > 0) throw new Error(`Tag path exceeds maximum depth of ${MAX_TRAVERSAL_DEPTH}`);\n if (segments.length === 0) throw new Error('Tag path is empty');\n return segments;\n}\n\n// ---------------------------------------------------------------------------\n// Serializers\n// ---------------------------------------------------------------------------\n\n/**\n * Converts tag segments back to a dcmodify-compatible path string.\n *\n * Format: `(0040,A730)[0].(0040,A160)`\n *\n * @param segments - An array of TagSegment objects\n * @returns A dcmodify-compatible path string\n */\nfunction segmentsToModifyPath(segments: ReadonlyArray<TagSegment>): string {\n const parts: string[] = [];\n for (const seg of segments) {\n let part: string = seg.tag;\n if (seg.isWildcard === true) {\n part += '[*]';\n } else if (seg.index !== undefined) {\n part += `[${seg.index}]`;\n }\n parts.push(part);\n }\n return parts.join('.');\n}\n\n/**\n * Converts tag segments to a canonical display string.\n *\n * Same format as dcmodify path: `(0040,A730)[0].(0040,A160)`\n *\n * @param segments - An array of TagSegment objects\n * @returns A human-readable path string\n */\nfunction segmentsToString(segments: ReadonlyArray<TagSegment>): string {\n return segmentsToModifyPath(segments);\n}\n\nexport { tagPathToSegments, segmentsToModifyPath, segmentsToString };\nexport type { TagSegment };\n","/**\n * Utility for iterating all DICOM tags in a JSON Model dataset.\n *\n * Supports VR filtering and bounded recursion into sequences.\n *\n * @module dicom/walkTags\n */\n\nimport type { DicomJsonElement, DicomJsonModel } from '../tools/_xmlToJson';\n\n/** Maximum default recursion depth for sequence traversal. */\nconst DEFAULT_MAX_DEPTH = 16;\n\n/** Information about a visited DICOM tag. */\ninterface WalkTagEntry {\n /** 8-char hex tag key (e.g., '00100010'). */\n readonly tag: string;\n /** The DICOM JSON element with vr, Value, etc. */\n readonly element: DicomJsonElement;\n /** VR code (e.g., 'PN', 'US', 'SQ'). */\n readonly vr: string;\n /** Nesting depth (0 = top-level). */\n readonly depth: number;\n /** Dot-separated path (e.g., '00081115[0].0020000E'). */\n readonly path: string;\n}\n\n/** Options for walkTags. */\ninterface WalkTagsOptions {\n /** Only visit tags with these VR codes. Omit to visit all. */\n readonly vrFilter?: ReadonlyArray<string> | undefined;\n /** Max recursion depth into sequences. Default: 16. */\n readonly maxDepth?: number | undefined;\n}\n\n/** Internal context passed through recursion to avoid excessive parameters. */\ninterface WalkContext {\n readonly maxDepth: number;\n readonly vrSet: Set<string> | undefined;\n readonly results: WalkTagEntry[];\n}\n\n/**\n * Walks all tags in a DICOM JSON Model dataset.\n *\n * Iterates every tag, optionally filtering by VR and recursing into sequences.\n * Sequences are always recursed into (even if SQ is filtered out) so nested\n * tags can match the VR filter.\n *\n * @param data - A DICOM JSON Model object\n * @param options - Optional VR filter and max depth\n * @returns A readonly array of all matching tag entries\n */\nfunction walkTags(data: DicomJsonModel, options?: WalkTagsOptions): ReadonlyArray<WalkTagEntry> {\n const ctx: WalkContext = {\n maxDepth: options?.maxDepth ?? DEFAULT_MAX_DEPTH,\n vrSet: options?.vrFilter !== undefined ? new Set(options.vrFilter) : undefined,\n results: [],\n };\n walkLevel(data, 0, '', ctx);\n return ctx.results;\n}\n\n/** Recursive helper that walks one level of a DICOM JSON Model. */\nfunction walkLevel(data: DicomJsonModel, depth: number, pathPrefix: string, ctx: WalkContext): void {\n const keys = Object.keys(data);\n for (let i = 0; i < keys.length; i++) {\n const tag = keys[i];\n /* v8 ignore next */\n if (tag === undefined) continue;\n const element = data[tag];\n /* v8 ignore next */\n if (element === undefined) continue;\n const vr = element.vr;\n const path = pathPrefix.length > 0 ? `${pathPrefix}.${tag}` : tag;\n\n if (ctx.vrSet === undefined || ctx.vrSet.has(vr)) {\n ctx.results.push({ tag, element, vr, depth, path });\n }\n\n if (vr === 'SQ' && element.Value !== undefined && depth < ctx.maxDepth) {\n walkSequenceItems(element.Value, depth, path, ctx);\n }\n }\n}\n\n/** Recurses into each item of a sequence Value array. */\nfunction walkSequenceItems(items: ReadonlyArray<unknown>, depth: number, parentPath: string, ctx: WalkContext): void {\n for (let idx = 0; idx < items.length; idx++) {\n const item = items[idx];\n if (typeof item !== 'object' || item === null) continue;\n const itemPath = `${parentPath}[${idx}]`;\n walkLevel(item as DicomJsonModel, depth + 1, itemPath, ctx);\n }\n}\n\nexport { walkTags };\nexport type { WalkTagEntry, WalkTagsOptions };\n","/**\n * Immutable DICOM dataset wrapper with type-safe accessors.\n *\n * Wraps DICOM JSON Model data (PS3.18 F.2) from dcm2json/dcm2xml with\n * convenient read-only accessors. No setters — mutations go through ChangeSet.\n *\n * @module dicom/DicomDataset\n */\n\nimport { stderr } from 'stderr-lib';\nimport type { DicomTag, DicomTagPath, SOPClassUID } from '../brands';\nimport { createSOPClassUID } from '../brands';\nimport { MAX_TRAVERSAL_DEPTH } from '../constants';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport type { TagSegment } from './tagPath';\nimport { tagPathToSegments } from './tagPath';\nimport type { DicomJsonElement, DicomJsonModel } from '../tools/_xmlToJson';\nimport { walkTags as walkTagsFn } from './walkTags';\nimport type { WalkTagEntry, WalkTagsOptions } from './walkTags';\n\n// ---------------------------------------------------------------------------\n// Structural validation\n// ---------------------------------------------------------------------------\n\nconst HEX_TAG_KEY = /^[0-9A-Fa-f]{8}$/;\n\n/**\n * Returns true if the value looks like a DicomJsonElement (has a string `vr` property).\n * This is a lightweight structural check, not a full VR validation.\n */\nfunction isDicomJsonElement(value: unknown): value is DicomJsonElement {\n return typeof value === 'object' && value !== null && 'vr' in value && typeof (value as Record<string, unknown>)['vr'] === 'string';\n}\n\n/**\n * Returns true if the object looks like a DicomJsonModel.\n * Every key must be an 8-char hex string and every value must have { vr: string }.\n */\nfunction isValidDicomJsonModel(obj: Record<string, unknown>): boolean {\n const keys = Object.keys(obj);\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n /* v8 ignore next */\n if (key === undefined) continue;\n if (!HEX_TAG_KEY.test(key)) return false;\n if (!isDicomJsonElement(obj[key])) return false;\n }\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Tag normalization\n// ---------------------------------------------------------------------------\n\nconst TAG_WITH_PARENS = /^\\(([0-9A-Fa-f]{4}),([0-9A-Fa-f]{4})\\)$/;\nconst TAG_HEX_ONLY = /^[0-9A-Fa-f]{8}$/;\n\n/**\n * Normalizes a DICOM tag to 8-char uppercase hex.\n * Accepts `(0010,0010)` or `00100010` formats.\n */\nfunction normalizeTag(tag: DicomTag | string): Result<string> {\n const parenMatch = TAG_WITH_PARENS.exec(tag);\n if (parenMatch !== null) {\n const group = parenMatch[1];\n const element = parenMatch[2];\n /* v8 ignore next */\n if (group === undefined || element === undefined) return err(new Error(`Invalid tag: \"${tag}\"`));\n return ok(`${group}${element}`.toUpperCase());\n }\n if (TAG_HEX_ONLY.test(tag)) {\n return ok(tag.toUpperCase());\n }\n return err(new Error(`Invalid tag format: \"${tag}\". Expected (XXXX,XXXX) or XXXXXXXX`));\n}\n\n// ---------------------------------------------------------------------------\n// Element extraction helpers\n// ---------------------------------------------------------------------------\n\n/** Resolves an element from the data by normalized tag key. */\nfunction resolveElement(data: DicomJsonModel, tagKey: string): DicomJsonElement | undefined {\n return data[tagKey];\n}\n\n/**\n * Extracts the Alphabetic component from a PN (PersonName) value.\n * Returns empty string if the Alphabetic component is missing or the\n * value is not a valid PN object — consistent with DICOM PS3.5 which\n * treats missing components as empty strings.\n */\nfunction extractPNAlphabetic(first: unknown): string {\n if (typeof first !== 'object' || first === null) return '';\n const pn = first as Record<string, unknown>;\n const alphabetic = pn['Alphabetic'];\n return typeof alphabetic === 'string' ? alphabetic : '';\n}\n\n/** Converts a primitive value to string. */\nfunction primitiveToString(value: unknown): string {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n return '';\n}\n\n/** Extracts a string from a DicomJsonElement, handling PN values. */\nfunction extractString(element: DicomJsonElement): string {\n const values = element.Value;\n if (values === undefined || values.length === 0) return '';\n\n const first = values[0];\n if (first === undefined || first === null) return '';\n\n if (element.vr === 'PN') return extractPNAlphabetic(first);\n return primitiveToString(first);\n}\n\n/** Extracts a number from a DicomJsonElement with validation. */\nfunction extractNumber(element: DicomJsonElement): Result<number> {\n const values = element.Value;\n if (values === undefined || values.length === 0) {\n return err(new Error('Element has no Value array'));\n }\n const first = values[0];\n if (typeof first === 'number') return ok(first);\n if (typeof first === 'string') {\n const parsed = Number(first);\n if (Number.isNaN(parsed)) {\n return err(new Error(`Cannot convert \"${first}\" to number`));\n }\n return ok(parsed);\n }\n return err(new Error(`Value is not numeric: ${typeof first}`));\n}\n\n/** Extracts all values as strings from a DicomJsonElement. */\nfunction extractStrings(element: DicomJsonElement): ReadonlyArray<string> {\n const values = element.Value;\n if (values === undefined) return [];\n const result: string[] = [];\n for (const v of values) {\n if (typeof v === 'string') {\n result.push(v);\n } else if (typeof v === 'number' || typeof v === 'boolean') {\n result.push(String(v));\n } else {\n result.push('');\n }\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Path traversal helpers (iterative, no recursion — Rule 8.2)\n// ---------------------------------------------------------------------------\n\n/** Gets the sequence items array from a DicomJsonElement. */\nfunction getSequenceItems(element: DicomJsonElement): ReadonlyArray<unknown> | undefined {\n if (element.vr !== 'SQ' || element.Value === undefined) return undefined;\n return element.Value;\n}\n\n/** Returns true if the value is a plausible DicomJsonModel (non-null object with no array). */\nfunction isPlausibleModel(value: unknown): value is DicomJsonModel {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Descends into a sequence item, returning the nested dataset or an error. */\nfunction descendIntoSequence(element: DicomJsonElement, seg: TagSegment): Result<DicomJsonModel> {\n const items = getSequenceItems(element);\n if (items === undefined) {\n return err(new Error(`Tag ${seg.tag} is not a sequence`));\n }\n const idx = seg.index ?? 0;\n const item = items[idx];\n if (!isPlausibleModel(item)) {\n return err(new Error(`Sequence ${seg.tag} has no valid item at index ${idx}`));\n }\n return ok(item);\n}\n\n/** Traverses a non-wildcard path iteratively through nested sequences. */\nfunction traversePath(data: DicomJsonModel, segments: ReadonlyArray<TagSegment>): Result<DicomJsonElement> {\n let current: DicomJsonModel = data;\n\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i];\n /* v8 ignore next */\n if (seg === undefined) return err(new Error('Unexpected undefined segment'));\n\n const tagResult = normalizeTag(seg.tag);\n if (!tagResult.ok) return err(tagResult.error);\n\n const element = resolveElement(current, tagResult.value);\n if (element === undefined) return err(new Error(`Tag ${seg.tag} not found`));\n\n if (i === segments.length - 1) return ok(element);\n\n const descent = descendIntoSequence(element, seg);\n if (!descent.ok) return err(descent.error);\n current = descent.value;\n }\n\n /* v8 ignore next */\n return err(new Error('Empty path segments'));\n}\n\n// ---------------------------------------------------------------------------\n// Wildcard collection (iterative queue — Rule 8.2)\n// ---------------------------------------------------------------------------\n\ninterface QueueEntry {\n readonly data: DicomJsonModel;\n readonly segmentIndex: number;\n}\n\ninterface WildcardResult {\n readonly values: ReadonlyArray<unknown>;\n readonly truncated: boolean;\n}\n\n/** Collects all values matching a wildcard path using an iterative BFS queue. */\nfunction collectWildcard(data: DicomJsonModel, segments: ReadonlyArray<TagSegment>): WildcardResult {\n const results: unknown[] = [];\n const queue: QueueEntry[] = [{ data, segmentIndex: 0 }];\n const maxIterations = MAX_TRAVERSAL_DEPTH * 100;\n\n let iteration = 0;\n for (; iteration < maxIterations && queue.length > 0; iteration++) {\n const entry = queue.shift();\n /* v8 ignore next */\n if (entry === undefined) break;\n processQueueEntry(entry, segments, results, queue);\n }\n\n return { values: results, truncated: iteration >= maxIterations && queue.length > 0 };\n}\n\n/** Processes a single queue entry for wildcard collection. */\nfunction processQueueEntry(entry: QueueEntry, segments: ReadonlyArray<TagSegment>, results: unknown[], queue: QueueEntry[]): void {\n const seg = segments[entry.segmentIndex];\n /* v8 ignore next */\n if (seg === undefined) return;\n\n const tagResult = normalizeTag(seg.tag);\n if (!tagResult.ok) return;\n\n const element = resolveElement(entry.data, tagResult.value);\n if (element === undefined) return;\n\n const isLast = entry.segmentIndex === segments.length - 1;\n\n if (isLast) {\n collectLeafValues(element, results);\n return;\n }\n\n enqueueSequenceItems(element, seg, entry.segmentIndex, queue);\n}\n\n/** Collects values from a leaf element into the results array. */\nfunction collectLeafValues(element: DicomJsonElement, results: unknown[]): void {\n if (element.Value !== undefined) {\n for (const v of element.Value) {\n results.push(v);\n }\n }\n}\n\n/** Enqueues child sequence items for further wildcard processing. */\nfunction enqueueSequenceItems(element: DicomJsonElement, seg: TagSegment, segmentIndex: number, queue: QueueEntry[]): void {\n const items = getSequenceItems(element);\n if (items === undefined) return;\n\n if (seg.isWildcard === true) {\n for (const item of items) {\n if (isPlausibleModel(item)) {\n queue.push({ data: item, segmentIndex: segmentIndex + 1 });\n }\n }\n } else {\n const idx = seg.index ?? 0;\n const item = items[idx];\n if (isPlausibleModel(item)) {\n queue.push({ data: item, segmentIndex: segmentIndex + 1 });\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Well-known DICOM tag keys (8-char hex, uppercase)\n// ---------------------------------------------------------------------------\n\nconst TAGS = {\n AccessionNumber: '00080050',\n PatientName: '00100010',\n PatientID: '00100020',\n StudyDate: '00080020',\n Modality: '00080060',\n SOPClassUID: '00080016',\n StudyInstanceUID: '0020000D',\n SeriesInstanceUID: '0020000E',\n SOPInstanceUID: '00080018',\n TransferSyntaxUID: '00020010',\n} as const;\n\n// ---------------------------------------------------------------------------\n// DicomDataset class\n// ---------------------------------------------------------------------------\n\n/**\n * Immutable wrapper around DICOM JSON Model data.\n *\n * Provides type-safe read-only accessors for DICOM tag values.\n * Construct via the static {@link DicomDataset.fromJson} factory.\n *\n * @example\n * ```ts\n * const result = DicomDataset.fromJson(jsonData);\n * if (result.ok) {\n * const ds = result.value;\n * console.log(ds.patientName);\n * console.log(ds.modality);\n * }\n * ```\n */\nclass DicomDataset {\n private readonly data: DicomJsonModel;\n\n private constructor(data: DicomJsonModel) {\n this.data = data;\n }\n\n /**\n * Creates a DicomDataset from a DICOM JSON Model object.\n *\n * Performs structural validation only — verifies the input is a non-null object.\n *\n * @param json - A DICOM JSON Model object (typically from dcm2json)\n * @returns A Result containing the DicomDataset or an error\n */\n static fromJson(json: unknown): Result<DicomDataset> {\n if (json === null || json === undefined || typeof json !== 'object' || Array.isArray(json)) {\n return err(new Error('Invalid DICOM JSON: expected a non-null, non-array object'));\n }\n const obj = json as Record<string, unknown>;\n if (!isValidDicomJsonModel(obj)) {\n return err(new Error('Invalid DICOM JSON: every key must be an 8-char hex tag and every value must have a \"vr\" string property'));\n }\n return ok(new DicomDataset(json as DicomJsonModel));\n }\n\n /**\n * Gets the full DICOM JSON element for a tag.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the element or an error if not found\n */\n getElement(tag: DicomTag | string): Result<DicomJsonElement> {\n const norm = normalizeTag(tag);\n if (!norm.ok) return err(norm.error);\n const element = resolveElement(this.data, norm.value);\n if (element === undefined) return err(new Error(`Tag ${tag} not found`));\n return ok(element);\n }\n\n /**\n * Gets the Value array for a tag.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the readonly Value array or an error\n */\n getValue(tag: DicomTag | string): Result<ReadonlyArray<unknown>> {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return err(elemResult.error);\n const values = elemResult.value.Value;\n if (values === undefined) return err(new Error(`Tag ${tag} has no Value`));\n return ok(values);\n }\n\n /**\n * Gets the first element of the Value array for a tag.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the first value or an error\n */\n getFirstValue(tag: DicomTag | string): Result<unknown> {\n const valResult = this.getValue(tag);\n if (!valResult.ok) return err(valResult.error);\n const first = valResult.value[0];\n if (first === undefined) return err(new Error(`Tag ${tag} Value array is empty`));\n return ok(first);\n }\n\n /**\n * Gets a tag value as a string with optional fallback.\n *\n * Returns the fallback (default empty string) if the tag is missing or has no value.\n * Handles PN (PersonName) values by extracting the Alphabetic component.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @param fallback - Value to return if tag is missing (default: `''`)\n * @returns The string value or the fallback\n */\n getString(tag: DicomTag | string, fallback = ''): string {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return fallback;\n const str = extractString(elemResult.value);\n return str.length > 0 ? str : fallback;\n }\n\n /**\n * Gets a tag value as a validated number.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the number or an error\n */\n getNumber(tag: DicomTag | string): Result<number> {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return err(elemResult.error);\n return extractNumber(elemResult.value);\n }\n\n /**\n * Gets all values of a tag as strings.\n *\n * Useful for multi-valued tags like CS (Code String).\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns Result containing the readonly string array or an error\n */\n getStrings(tag: DicomTag | string): Result<ReadonlyArray<string>> {\n const elemResult = this.getElement(tag);\n if (!elemResult.ok) return err(elemResult.error);\n return ok(extractStrings(elemResult.value));\n }\n\n /**\n * Checks whether a tag exists in the dataset.\n *\n * @param tag - A DicomTag `(0010,0010)` or hex string `00100010`\n * @returns `true` if the tag is present\n */\n hasTag(tag: DicomTag | string): boolean {\n const norm = normalizeTag(tag);\n if (!norm.ok) return false;\n return resolveElement(this.data, norm.value) !== undefined;\n }\n\n /**\n * Gets an element by traversing a dotted tag path through sequences.\n *\n * @param path - A branded DicomTagPath, e.g. `(0040,A730)[0].(0040,A160)`\n * @returns Result containing the element at the path or an error\n */\n getElementAtPath(path: DicomTagPath): Result<DicomJsonElement> {\n let segments: ReadonlyArray<TagSegment>;\n try {\n segments = tagPathToSegments(path);\n } catch (e: unknown) {\n return err(stderr(e));\n }\n return traversePath(this.data, segments);\n }\n\n /**\n * Finds all values matching a path with wildcard `[*]` indices.\n *\n * Traverses all items in wildcard sequence positions using an iterative BFS queue.\n * The traversal is bounded to {@link MAX_TRAVERSAL_DEPTH} * 100 iterations (5 000).\n * For extremely large datasets this may truncate results silently; callers\n * needing completeness guarantees should verify dataset size independently.\n *\n * @param path - A branded DicomTagPath, e.g. `(0040,A730)[*].(0040,A160)`\n * @returns A readonly array of all matching values (may be empty)\n */\n findValues(path: DicomTagPath): ReadonlyArray<unknown> {\n let segments: ReadonlyArray<TagSegment>;\n try {\n segments = tagPathToSegments(path);\n } catch {\n return [];\n }\n const result = collectWildcard(this.data, segments);\n return result.values;\n }\n\n /**\n * Walks all tags in this dataset, optionally filtering by VR and recursing into sequences.\n *\n * @param options - Optional VR filter and max depth\n * @returns A readonly array of all matching tag entries\n */\n walkTags(options?: WalkTagsOptions): ReadonlyArray<WalkTagEntry> {\n return walkTagsFn(this.data, options);\n }\n\n // -----------------------------------------------------------------------\n // Convenience readonly getters\n // -----------------------------------------------------------------------\n\n /** Accession Number (0008,0050). */\n get accession(): string {\n return this.getString(TAGS.AccessionNumber);\n }\n\n /** Patient's Name (0010,0010). */\n get patientName(): string {\n return this.getString(TAGS.PatientName);\n }\n\n /** Patient ID (0010,0020). */\n get patientID(): string {\n return this.getString(TAGS.PatientID);\n }\n\n /** Study Date (0008,0020). */\n get studyDate(): string {\n return this.getString(TAGS.StudyDate);\n }\n\n /** Modality (0008,0060). */\n get modality(): string {\n return this.getString(TAGS.Modality);\n }\n\n /** SOP Class UID (0008,0016) as a branded SOPClassUID, or undefined if missing/invalid. */\n get sopClassUID(): SOPClassUID | undefined {\n const uid = this.getString(TAGS.SOPClassUID);\n if (uid.length === 0) return undefined;\n const result = createSOPClassUID(uid);\n return result.ok ? result.value : undefined;\n }\n\n /** Study Instance UID (0020,000D). */\n get studyInstanceUID(): string {\n return this.getString(TAGS.StudyInstanceUID);\n }\n\n /** Series Instance UID (0020,000E). */\n get seriesInstanceUID(): string {\n return this.getString(TAGS.SeriesInstanceUID);\n }\n\n /** SOP Instance UID (0008,0018). */\n get sopInstanceUID(): string {\n return this.getString(TAGS.SOPInstanceUID);\n }\n\n /** Transfer Syntax UID (0002,0010). */\n get transferSyntaxUID(): string {\n return this.getString(TAGS.TransferSyntaxUID);\n }\n}\n\nexport { DicomDataset };\n","/**\n * Immutable mutation tracking for DICOM datasets.\n *\n * Every mutation method returns a new ChangeSet instance, preserving immutability.\n * Bridge methods produce dcmodify-compatible arguments for applying changes to files.\n *\n * @module dicom/ChangeSet\n */\n\nimport type { TagModification } from '../tools/dcmodify';\nimport { MAX_CHANGESET_OPERATIONS } from '../constants';\nimport type { DicomTagPath } from '../brands';\nimport { tagPathToSegments } from './tagPath';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Sentinel value in the erasures set to indicate erasing all private tags. */\nconst ERASE_PRIVATE_SENTINEL = '__ERASE_PRIVATE__';\n\n// ---------------------------------------------------------------------------\n// Helpers (extracted for complexity/line limits)\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true if a char code is a control character to strip.\n * Strips 0x00-0x09, 0x0B, 0x0C, 0x0E-0x1F, 0x7F.\n * Preserves LF (0x0A), CR (0x0D), and backslash.\n */\nfunction isControlChar(code: number): boolean {\n if (code <= 0x09) return true;\n if (code === 0x0b || code === 0x0c) return true;\n if (code >= 0x0e && code <= 0x1f) return true;\n return code === 0x7f;\n}\n\n/** Strips control characters from a value while preserving LF, CR, and backslash. */\nfunction sanitizeValue(value: string): string {\n let result = '';\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n if (!isControlChar(code)) {\n result += value[i];\n }\n }\n return result;\n}\n\n/** Merges two modification maps, with `other` winning conflicts. Removes keys present in erasures. */\nfunction buildMergedModifications(\n base: ReadonlyMap<string, string>,\n other: ReadonlyMap<string, string>,\n erasures: ReadonlySet<string>\n): ReadonlyMap<string, string> {\n const merged = new Map<string, string>(base);\n for (const [key, value] of other) {\n merged.set(key, value);\n }\n for (const key of erasures) {\n merged.delete(key);\n }\n return merged;\n}\n\n/** Iteratively applies all entries to a ChangeSet, returning the final result. */\nfunction applyBatchEntries(initial: ChangeSet, entries: Readonly<Record<string, string>>): ChangeSet {\n const keys = Object.keys(entries);\n let cs = initial;\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n /* v8 ignore next */\n if (key === undefined) continue;\n const value = entries[key];\n /* v8 ignore next */\n if (value === undefined) continue;\n cs = cs.setTag(key, value);\n }\n return cs;\n}\n\n// ---------------------------------------------------------------------------\n// ChangeSet class\n// ---------------------------------------------------------------------------\n\n/**\n * Immutable mutation tracker for DICOM datasets.\n *\n * Every mutation method returns a **new** ChangeSet — the original is never modified.\n * Use {@link ChangeSet.toModifications} and {@link ChangeSet.toErasureArgs} to bridge\n * to the dcmodify tool wrapper.\n *\n * @example\n * ```ts\n * const cs = ChangeSet.empty()\n * .setTag('(0010,0010)' as DicomTagPath, 'Anonymous')\n * .eraseTag('(0010,0020)' as DicomTagPath)\n * .erasePrivateTags();\n * ```\n */\nclass ChangeSet {\n private readonly mods: ReadonlyMap<string, string>;\n private readonly erased: ReadonlySet<string>;\n\n private constructor(mods: ReadonlyMap<string, string>, erasures: ReadonlySet<string>) {\n this.mods = mods;\n this.erased = erasures;\n }\n\n /** Creates an empty ChangeSet with no modifications or erasures. */\n static empty(): ChangeSet {\n return new ChangeSet(new Map(), new Set());\n }\n\n /**\n * Sets a tag value, returning a new ChangeSet.\n *\n * Control characters (except LF/CR) are stripped from the value.\n * If the tag was previously erased, it is removed from the erasure set.\n *\n * @param path - The DICOM tag path to set (e.g. `'(0010,0010)'`)\n * @param value - The new value for the tag\n * @returns A new ChangeSet with the modification applied\n * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS\n */\n setTag(path: string, value: string): ChangeSet {\n const totalOps = this.mods.size + this.erased.size;\n if (totalOps >= MAX_CHANGESET_OPERATIONS) {\n throw new Error(`ChangeSet operation limit (${MAX_CHANGESET_OPERATIONS}) exceeded`);\n }\n tagPathToSegments(path as DicomTagPath);\n const sanitized = sanitizeValue(value);\n const newMods = new Map(this.mods);\n newMods.set(path, sanitized);\n const newErasures = new Set(this.erased);\n newErasures.delete(path);\n return new ChangeSet(newMods, newErasures);\n }\n\n /**\n * Marks a tag for erasure, returning a new ChangeSet.\n *\n * If the tag was previously set, the modification is removed.\n *\n * @param path - The DICOM tag path to erase (e.g. `'(0010,0010)'`)\n * @returns A new ChangeSet with the erasure applied\n * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS\n */\n eraseTag(path: string): ChangeSet {\n const totalOps = this.mods.size + this.erased.size;\n if (totalOps >= MAX_CHANGESET_OPERATIONS) {\n throw new Error(`ChangeSet operation limit (${MAX_CHANGESET_OPERATIONS}) exceeded`);\n }\n tagPathToSegments(path as DicomTagPath);\n const newMods = new Map(this.mods);\n newMods.delete(path);\n const newErasures = new Set(this.erased);\n newErasures.add(path);\n return new ChangeSet(newMods, newErasures);\n }\n\n /**\n * Marks all private tags for erasure, returning a new ChangeSet.\n *\n * @returns A new ChangeSet with the erase-private flag set\n * @throws Error if operation count would exceed MAX_CHANGESET_OPERATIONS\n */\n erasePrivateTags(): ChangeSet {\n const totalOps = this.mods.size + this.erased.size;\n if (totalOps >= MAX_CHANGESET_OPERATIONS) {\n throw new Error(`ChangeSet operation limit (${MAX_CHANGESET_OPERATIONS}) exceeded`);\n }\n const newErasures = new Set(this.erased);\n newErasures.add(ERASE_PRIVATE_SENTINEL);\n return new ChangeSet(new Map(this.mods), newErasures);\n }\n\n // -----------------------------------------------------------------------\n // Convenience setters for common DICOM tags\n // -----------------------------------------------------------------------\n\n /** Sets Patient's Name (0010,0010). */\n setPatientName(value: string): ChangeSet {\n return this.setTag('(0010,0010)', value);\n }\n\n /** Sets Patient ID (0010,0020). */\n setPatientID(value: string): ChangeSet {\n return this.setTag('(0010,0020)', value);\n }\n\n /** Sets Study Date (0008,0020). */\n setStudyDate(value: string): ChangeSet {\n return this.setTag('(0008,0020)', value);\n }\n\n /** Sets Modality (0008,0060). */\n setModality(value: string): ChangeSet {\n return this.setTag('(0008,0060)', value);\n }\n\n /** Sets Accession Number (0008,0050). */\n setAccessionNumber(value: string): ChangeSet {\n return this.setTag('(0008,0050)', value);\n }\n\n /** Sets Study Description (0008,1030). */\n setStudyDescription(value: string): ChangeSet {\n return this.setTag('(0008,1030)', value);\n }\n\n /** Sets Series Description (0008,103E). */\n setSeriesDescription(value: string): ChangeSet {\n return this.setTag('(0008,103E)', value);\n }\n\n /** Sets Institution Name (0008,0080). */\n setInstitutionName(value: string): ChangeSet {\n return this.setTag('(0008,0080)', value);\n }\n\n /**\n * Sets multiple tags at once, returning a new ChangeSet.\n *\n * @param entries - A record of tag path → value pairs\n * @returns A new ChangeSet with all modifications applied\n */\n setBatch(entries: Readonly<Record<string, string>>): ChangeSet {\n return applyBatchEntries(this, entries);\n }\n\n /** All pending tag modifications as a readonly map of path → value. */\n get modifications(): ReadonlyMap<string, string> {\n return this.mods;\n }\n\n /** All pending tag erasures as a readonly set of paths. */\n get erasures(): ReadonlySet<string> {\n return this.erased;\n }\n\n /** Total number of operations (modifications + erasures) in this ChangeSet. */\n get operationCount(): number {\n return this.mods.size + this.erased.size;\n }\n\n /** Whether the ChangeSet has no modifications and no erasures. */\n get isEmpty(): boolean {\n return this.mods.size === 0 && this.erased.size === 0;\n }\n\n /** Whether the erase-all-private-tags flag is set. */\n get erasePrivate(): boolean {\n return this.erased.has(ERASE_PRIVATE_SENTINEL);\n }\n\n /**\n * Merges another ChangeSet into this one, returning a new ChangeSet.\n *\n * The `other` ChangeSet wins on conflicts: if the same tag is modified in both,\n * `other`'s value is used. Erasures from both sets are unioned. An erasure in\n * `other` removes a modification from `base`.\n *\n * @param other - The ChangeSet to merge in\n * @returns A new ChangeSet with merged modifications and erasures\n */\n merge(other: ChangeSet): ChangeSet {\n const mergedErasures = new Set([...this.erased, ...other.erased]);\n const mergedMods = buildMergedModifications(this.mods, other.mods, mergedErasures);\n return new ChangeSet(mergedMods, mergedErasures);\n }\n\n /**\n * Converts modifications to dcmodify-compatible TagModification array.\n *\n * @returns A readonly array of TagModification objects\n */\n toModifications(): ReadonlyArray<TagModification> {\n const result: TagModification[] = [];\n for (const [tag, value] of this.mods) {\n result.push({ tag, value });\n }\n return result;\n }\n\n /**\n * Converts erasures to dcmodify-compatible argument strings.\n *\n * The erase-private sentinel is excluded — use {@link erasePrivate} to check\n * whether `-ep` should be passed.\n *\n * @returns A readonly array of tag path strings for `-e` arguments\n */\n toErasureArgs(): ReadonlyArray<string> {\n const result: string[] = [];\n for (const path of this.erased) {\n if (path !== ERASE_PRIVATE_SENTINEL) {\n result.push(path);\n }\n }\n return result;\n }\n}\n\nexport { ChangeSet };\n","/**\n * Short-lived DCMTK process execution.\n *\n * Two execution modes:\n * - `execCommand()` — convenience wrapper; uses `spawn()` internally for safety\n * - `spawnCommand()` — uses `child_process.spawn()`, safer for user-supplied values (Rule 7.4)\n *\n * Both enforce mandatory timeouts (Rule 4.2) and return `Result<DcmtkProcessResult>`.\n *\n * @module exec\n */\n\nimport { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport kill from 'tree-kill';\nimport type { Result, DcmtkProcessResult, ExecOptions, SpawnOptions } from './types';\nimport { ok, err } from './types';\nimport { DEFAULT_TIMEOUT_MS, MAX_OUTPUT_BYTES } from './constants';\n\n/**\n * Kills a process tree by PID. Wraps tree-kill in a promise.\n *\n * @param pid - The process ID to kill\n */\nfunction killTree(pid: number): void {\n try {\n kill(pid);\n /* v8 ignore next */\n } catch {\n // Process may already be dead — not exceptional\n }\n}\n\n/**\n * Executes a DCMTK binary as a short-lived process.\n *\n * **Security:** This function uses `child_process.spawn()` internally, passing\n * arguments as an array to avoid shell interpretation. This eliminates shell\n * injection risks regardless of argument content (Rule 7.4).\n *\n * @param binary - Full path to the DCMTK binary\n * @param args - Command-line arguments (passed directly, no shell interpolation)\n * @param options - Execution options (timeout, cwd, signal)\n * @returns A Result containing the process output or an error\n * @throws Never throws for expected failures (Rule 6.1)\n *\n * @example\n * ```ts\n * const result = await execCommand('/usr/local/bin/dcm2json', ['+ll', 'input.dcm']);\n * if (result.ok) {\n * console.log(result.value.stdout);\n * }\n * ```\n */\nasync function execCommand(binary: string, args: readonly string[], options?: ExecOptions): Promise<Result<DcmtkProcessResult>> {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n return new Promise(resolve => {\n const child = spawn(binary, [...args], {\n cwd: options?.cwd,\n windowsHide: true,\n signal: options?.signal,\n });\n wireSpawnListeners(binary, child, timeoutMs, resolve);\n });\n}\n\n/**\n * Wires event listeners on a spawned child process with timeout, bounded buffering, and settle logic.\n */\nfunction wireSpawnListeners(binary: string, child: ChildProcess, timeoutMs: number, resolve: (result: Result<DcmtkProcessResult>) => void): void {\n let stdout = '';\n let stderr = '';\n let settled = false;\n const name = binary.split('/').pop() ?? binary;\n\n const settle = (result: Result<DcmtkProcessResult>): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(result);\n };\n\n const timer = setTimeout(() => {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`${name} timed out after ${timeoutMs}ms (pid: ${String(child.pid ?? 'unknown')})`)));\n }, timeoutMs);\n\n child.stdout?.on('data', (chunk: Buffer | string) => {\n stdout += String(chunk);\n if (stdout.length + stderr.length > MAX_OUTPUT_BYTES) {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`${name} output exceeded ${MAX_OUTPUT_BYTES} bytes`)));\n }\n });\n\n child.stderr?.on('data', (chunk: Buffer | string) => {\n stderr += String(chunk);\n if (stdout.length + stderr.length > MAX_OUTPUT_BYTES) {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`${name} output exceeded ${MAX_OUTPUT_BYTES} bytes`)));\n }\n });\n\n child.on('error', (error: Error) => {\n if (child.pid !== undefined && child.pid !== null) killTree(child.pid);\n settle(err(new Error(`${name} error: ${error.message}`)));\n });\n\n child.on('close', (code: number | null) => {\n settle(ok({ stdout, stderr, exitCode: code ?? 1 }));\n });\n}\n\n/**\n * Executes a DCMTK binary using `child_process.spawn()`.\n *\n * Like {@link execCommand}, arguments are passed as an array to avoid shell\n * injection (Rule 7.4). This variant additionally supports custom environment\n * variables via the `env` option.\n *\n * @param binary - Full path to the DCMTK binary\n * @param args - Command-line arguments (passed directly, no shell interpolation)\n * @param options - Execution options (timeout, cwd, signal, env)\n * @returns A Result containing the process output or an error\n * @throws Never throws for expected failures (Rule 6.1)\n *\n * @example\n * ```ts\n * const result = await spawnCommand('/usr/local/bin/dcmodify', ['-m', '(0010,0010)=Smith^John', 'input.dcm']);\n * ```\n */\nasync function spawnCommand(binary: string, args: readonly string[], options?: SpawnOptions): Promise<Result<DcmtkProcessResult>> {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n return new Promise(resolve => {\n const child = spawn(binary, [...args], {\n cwd: options?.cwd,\n env: options?.env ? { ...process.env, ...options.env } : undefined,\n windowsHide: true,\n signal: options?.signal,\n });\n wireSpawnListeners(binary, child, timeoutMs, resolve);\n });\n}\n\nexport { execCommand, spawnCommand };\n","/**\n * Converts dcm2xml \"Native DICOM Model\" XML into the DICOM JSON Model (PS3.18 F.2).\n *\n * dcm2xml outputs XML in the DCMTK native format:\n * ```xml\n * <NativeDicomModel>\n * <DicomAttribute tag=\"00100010\" vr=\"PN\" keyword=\"PatientName\">\n * <PersonName number=\"1\">\n * <Alphabetic><FamilyName>Smith</FamilyName></Alphabetic>\n * </PersonName>\n * </DicomAttribute>\n * <DicomAttribute tag=\"00100020\" vr=\"LO\" keyword=\"PatientID\">\n * <Value number=\"1\">12345</Value>\n * </DicomAttribute>\n * </NativeDicomModel>\n * ```\n *\n * The DICOM JSON Model output:\n * ```json\n * {\n * \"00100010\": { \"vr\": \"PN\", \"Value\": [{\"Alphabetic\": \"Smith\"}] },\n * \"00100020\": { \"vr\": \"LO\", \"Value\": [\"12345\"] }\n * }\n * ```\n *\n * @module _xmlToJson\n * @internal\n */\n\nimport { XMLParser } from 'fast-xml-parser';\nimport { stderr } from 'stderr-lib';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\n\n/** DICOM JSON Model element. */\ninterface DicomJsonElement {\n readonly vr: string;\n readonly Value?: ReadonlyArray<unknown>;\n readonly InlineBinary?: string;\n readonly BulkDataURI?: string;\n}\n\n/** Mutable builder for DicomJsonElement during conversion. */\ninterface ElementBuilder {\n vr: string;\n Value?: unknown[];\n InlineBinary?: string;\n BulkDataURI?: string;\n}\n\n/** DICOM JSON Model top-level object. */\ntype DicomJsonModel = Record<string, DicomJsonElement>;\n\n/** Parsed XML attribute node from fast-xml-parser. */\ninterface XmlDicomAttribute {\n readonly '@_tag': string;\n readonly '@_vr': string;\n readonly '@_keyword'?: string;\n readonly Value?: unknown;\n readonly PersonName?: unknown;\n readonly InlineBinary?: unknown;\n readonly BulkDataURI?: unknown;\n readonly Item?: unknown;\n}\n\n/** Person name components from XML. */\ninterface XmlPersonNameComponent {\n readonly FamilyName?: string;\n readonly GivenName?: string;\n readonly MiddleName?: string;\n readonly NamePrefix?: string;\n readonly NameSuffix?: string;\n}\n\n/** PN representation types. */\ntype PnRepType = 'Alphabetic' | 'Ideographic' | 'Phonetic';\nconst PN_REPS: readonly PnRepType[] = ['Alphabetic', 'Ideographic', 'Phonetic'];\n\nconst ARRAY_TAG_NAMES = new Set(['DicomAttribute', 'Value', 'PersonName', 'Item']);\n\n/**\n * The 34 standard DICOM VR codes (PS3.5 Table 6.2-1).\n * Used to validate VR values from DCMTK XML output. Unrecognized VRs\n * (e.g. retired/internal codes like \"xs\", \"ox\") fall back to 'UN'.\n */\nconst KNOWN_VR_CODES = new Set([\n 'AE',\n 'AS',\n 'AT',\n 'CS',\n 'DA',\n 'DS',\n 'DT',\n 'FD',\n 'FL',\n 'IS',\n 'LO',\n 'LT',\n 'OB',\n 'OD',\n 'OF',\n 'OL',\n 'OV',\n 'OW',\n 'PN',\n 'SH',\n 'SL',\n 'SQ',\n 'SS',\n 'ST',\n 'SV',\n 'TM',\n 'UC',\n 'UI',\n 'UL',\n 'UN',\n 'UR',\n 'US',\n 'UT',\n 'UV',\n]);\n\n/**\n * Builds a PN string from name components.\n */\nfunction buildPnString(comp: XmlPersonNameComponent): string {\n const parts = [comp.FamilyName ?? '', comp.GivenName ?? '', comp.MiddleName ?? '', comp.NamePrefix ?? '', comp.NameSuffix ?? ''];\n let last = parts.length - 1;\n for (; last >= 0; last--) {\n if (parts[last] !== '') break;\n }\n return parts.slice(0, last + 1).join('^');\n}\n\n/** Ensures a value is an array. */\nfunction toArray(val: unknown): readonly unknown[] {\n if (Array.isArray(val)) return val;\n if (val === undefined || val === null) return [];\n return [val];\n}\n\n/**\n * Converts a PersonName XML element to DICOM JSON PN format.\n */\nfunction convertPersonName(pnNode: unknown): Record<string, string> {\n const result: Record<string, string> = {};\n /* v8 ignore next -- defensive guard for malformed XML */\n if (typeof pnNode !== 'object' || pnNode === null) return result;\n const pn = pnNode as Record<string, unknown>;\n\n for (const rep of PN_REPS) {\n const repNode = pn[rep];\n if (repNode !== undefined && typeof repNode === 'object' && repNode !== null) {\n const str = buildPnString(repNode as XmlPersonNameComponent);\n if (str.length > 0) {\n result[rep] = str;\n }\n }\n }\n return result;\n}\n\n/** Safely converts an unknown value to a string without risking [object Object]. */\nfunction safeString(val: unknown): string {\n if (typeof val === 'string') return val;\n if (typeof val === 'number' || typeof val === 'boolean') return String(val);\n /* v8 ignore next */\n return '';\n}\n\n/** Handles InlineBinary elements. */\nfunction convertInlineBinary(attr: XmlDicomAttribute, element: ElementBuilder): void {\n element.InlineBinary = safeString(attr.InlineBinary);\n}\n\n/** Handles BulkDataURI elements. */\nfunction convertBulkDataURI(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const bulkArray = toArray(attr.BulkDataURI);\n const firstBulk = bulkArray[0];\n if (typeof firstBulk === 'object' && firstBulk !== null && '@_uri' in firstBulk) {\n element.BulkDataURI = safeString((firstBulk as Record<string, unknown>)['@_uri']);\n } else {\n element.BulkDataURI = safeString(firstBulk);\n }\n}\n\n/** Handles PersonName (PN VR) elements. */\nfunction convertPNValue(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const pnArray = toArray(attr.PersonName);\n const values: Record<string, string>[] = [];\n for (const pn of pnArray) {\n values.push(convertPersonName(pn));\n }\n if (values.length > 0) element.Value = values;\n}\n\n/** Handles Sequence (SQ) elements. */\nfunction convertSequence(attr: XmlDicomAttribute, element: ElementBuilder): void {\n const items = toArray(attr.Item);\n const values: DicomJsonModel[] = [];\n for (const item of items) {\n /* v8 ignore next -- defensive guard for malformed XML */\n if (typeof item !== 'object' || item === null) continue;\n values.push(convertAttributes(item as Record<string, unknown>));\n }\n if (values.length > 0) element.Value = values;\n}\n\n/** VRs whose values MUST be JSON numbers per DICOM PS3.18 F.2.3. */\nconst NUMERIC_JSON_VRS = new Set(['DS', 'FL', 'FD', 'IS', 'SL', 'SS', 'SV', 'UL', 'US', 'UV']);\n\n/** Unwraps fast-xml-parser attribute wrapper objects (e.g., {@_number: \"1\"}). */\nfunction unwrapValue(v: unknown): unknown {\n if (typeof v !== 'object' || v === null) return v;\n const obj = v as Record<string, unknown>;\n if ('#text' in obj) return obj['#text'];\n const keys = Object.keys(obj);\n if (keys.length === 1 && keys[0] !== undefined && keys[0].startsWith('@_')) {\n return obj[keys[0]];\n }\n return v;\n}\n\n/** Coerces a value to a number. Returns the original if not parseable. */\nfunction coerceNumeric(value: unknown): unknown {\n if (typeof value === 'number') return value;\n if (typeof value !== 'string') return value;\n const trimmed = value.trim();\n if (trimmed.length === 0) return value;\n const num = Number(trimmed);\n return Number.isNaN(num) ? value : num;\n}\n\n/** Handles regular Value elements. */\nfunction convertRegularValue(attr: XmlDicomAttribute, element: ElementBuilder, vr: string): void {\n const valArray = toArray(attr.Value);\n const values: unknown[] = [];\n const isNumeric = NUMERIC_JSON_VRS.has(vr);\n for (const v of valArray) {\n const unwrapped = unwrapValue(v);\n values.push(isNumeric ? coerceNumeric(unwrapped) : unwrapped);\n }\n if (values.length > 0) element.Value = values;\n}\n\n/**\n * Converts a single DicomAttribute XML element to its DICOM JSON element.\n */\nfunction convertElement(attr: XmlDicomAttribute): DicomJsonElement {\n const rawVr = attr['@_vr'];\n const vr = KNOWN_VR_CODES.has(rawVr) ? rawVr : 'UN';\n const element: ElementBuilder = { vr };\n\n if (attr.InlineBinary !== undefined) {\n convertInlineBinary(attr, element);\n } else if (attr.BulkDataURI !== undefined) {\n convertBulkDataURI(attr, element);\n } else if (element.vr === 'PN' && attr.PersonName !== undefined) {\n convertPNValue(attr, element);\n } else if (element.vr === 'SQ' && attr.Item !== undefined) {\n convertSequence(attr, element);\n } else if (attr.Value !== undefined) {\n convertRegularValue(attr, element, vr);\n }\n\n return Object.freeze(element) as DicomJsonElement;\n}\n\n/**\n * Converts an object containing DicomAttribute children into a DICOM JSON Model object.\n */\nfunction convertAttributes(obj: Record<string, unknown>): DicomJsonModel {\n const result: Record<string, DicomJsonElement> = {};\n const attrs = toArray(obj['DicomAttribute']);\n\n for (const attr of attrs) {\n if (typeof attr !== 'object' || attr === null) continue;\n const xmlAttr = attr as XmlDicomAttribute;\n const tag = xmlAttr['@_tag'];\n if (tag === undefined) continue;\n result[tag] = convertElement(xmlAttr);\n }\n\n return result;\n}\n\n/** XML parser configured for the DCMTK Native DICOM Model. */\nconst parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: '@_',\n parseTagValue: false,\n isArray: (name: string): boolean => ARRAY_TAG_NAMES.has(name),\n // DICOM XML does not use XML entities. Disable entity processing to avoid\n // the default expansion limit (1000) which rejects files with >1000 tags.\n // Without this, large studies fall through to dcm2json which hangs on\n // compressed pixel data (DCMTK bug).\n processEntities: false,\n});\n\n/**\n * Converts dcm2xml XML output to DICOM JSON Model.\n *\n * @param xml - The XML string from dcm2xml\n * @returns A Result containing the DICOM JSON Model or an error\n */\nfunction xmlToJson(xml: string): Result<DicomJsonModel> {\n try {\n const parsed = parser.parse(xml) as Record<string, unknown>;\n const root = parsed['NativeDicomModel'];\n if (root === undefined) {\n return err(new Error('Invalid dcm2xml output: missing NativeDicomModel root element'));\n }\n // Empty NativeDicomModel produces an empty string from the parser\n if (typeof root !== 'object' || root === null) {\n return ok({});\n }\n return ok(convertAttributes(root as Record<string, unknown>));\n } catch (error: unknown) {\n return err(new Error(`Failed to parse dcm2xml XML: ${stderr(error).message}`));\n }\n}\n\nexport { xmlToJson };\nexport type { DicomJsonModel, DicomJsonElement };\n","/**\n * Repairs malformed JSON output from the dcm2json binary.\n *\n * DCMTK's dcm2json sometimes emits invalid JSON for numeric-string VRs\n * (DS, IS) by producing unquoted numbers in arrays:\n * ```json\n * \"Value\": [1.5, 2.0] // invalid — DS values must be strings\n * \"Value\": [\"1.5\", \"2.0\"] // valid\n * ```\n *\n * This module detects and repairs these patterns before JSON.parse.\n *\n * @module _repairJson\n * @internal\n */\n\n/**\n * Pattern matching \"Value\" arrays in DICOM JSON.\n * Captures: (prefix including `[`)(inner content)(closing `]`).\n */\nconst VALUE_ARRAY_PATTERN = /(\"Value\"\\s*:\\s*\\[)([\\s\\S]*?)(\\])/g;\n\n/**\n * Matches a bare (unquoted) numeric literal.\n * Handles integers, decimals, scientific notation, and negative values.\n */\nconst BARE_NUMBER = /^-?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][+-]?\\d+)?$/;\n\n/**\n * Quotes a bare number token, leaving already-quoted strings unchanged.\n *\n * @param token - A trimmed token from inside a Value array\n * @returns The token, quoted if it was a bare number\n */\nfunction quoteIfBareNumber(token: string): string {\n const trimmed = token.trim();\n if (BARE_NUMBER.test(trimmed)) {\n return `\"${trimmed}\"`;\n }\n return trimmed;\n}\n\n/**\n * Repairs the inner content of a \"Value\" array by quoting bare numbers.\n *\n * @param inner - The content between `[` and `]`\n * @returns Repaired content with bare numbers quoted\n */\nfunction repairInner(inner: string): string {\n const trimmed = inner.trim();\n if (trimmed.length === 0) return inner;\n\n // Split on commas that are not inside quotes\n const tokens: string[] = [];\n let current = '';\n let inString = false;\n\n for (let i = 0; i < trimmed.length; i++) {\n const ch = trimmed[i]!;\n if (ch === '\"' && (i === 0 || trimmed[i - 1] !== '\\\\')) {\n inString = !inString;\n current += ch;\n } else if (ch === ',' && !inString) {\n tokens.push(current);\n current = '';\n } else {\n current += ch;\n }\n }\n tokens.push(current);\n\n return tokens.map(quoteIfBareNumber).join(', ');\n}\n\n/**\n * Repairs malformed dcm2json output by quoting unquoted numeric values in \"Value\" arrays.\n *\n * @param raw - The raw JSON string from dcm2json\n * @returns The repaired JSON string safe for JSON.parse\n */\nfunction repairJson(raw: string): string {\n return raw.replace(VALUE_ARRAY_PATTERN, (_match, prefix: string, inner: string, suffix: string) => {\n return `${prefix}${repairInner(inner)}${suffix}`;\n });\n}\n\nexport { repairJson };\n","/**\n * DICOM to JSON conversion using a two-phase strategy.\n *\n * Primary: dcm2xml → xmlToJson (more reliable output)\n * Fallback: dcm2json binary → repairJson → JSON.parse\n *\n * The result includes a `source` discriminant indicating which strategy succeeded.\n *\n * @module dcm2json\n */\n\nimport { mkdtemp, rm } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { stderr } from 'stderr-lib';\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { execCommand } from '../exec';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport { resolveBinary } from './_resolveBinary';\nimport { createToolError, createValidationError } from './_toolError';\nimport { xmlToJson } from './_xmlToJson';\nimport { repairJson } from './_repairJson';\nimport type { DicomJsonModel } from './_xmlToJson';\nimport type { ToolBaseOptions } from './_toolTypes';\n\n/** Indicates which conversion strategy produced the result. */\ntype Dcm2jsonSource = 'xml' | 'direct';\n\n/** Options for {@link dcm2json}. */\ninterface Dcm2jsonOptions extends ToolBaseOptions {\n /** Skip the XML primary path and use direct dcm2json only. Defaults to false. */\n readonly directOnly?: boolean | undefined;\n /** Assume the specified character set when SpecificCharacterSet (0008,0005) is absent. Passed to dcm2xml as `+Ca`. Only effective on the XML path (dcm2json binary does not support this flag). */\n readonly charsetAssume?: string | undefined;\n /** Fallback charset to retry with when UTF-8 conversion fails. On charset error, the XML path retries with `+Ca <fallback>`. `'Latin1'` recommended — maps every byte to a valid character. */\n readonly charsetFallback?: string | undefined;\n /** Verbosity level for diagnostic output. `'verbose'` maps to `-v`, `'debug'` maps to `-d`. */\n readonly verbosity?: 'verbose' | 'debug' | undefined;\n}\n\n/** Result of a successful dcm2json conversion. */\ninterface Dcm2jsonResult {\n /** The DICOM JSON Model object. */\n readonly data: DicomJsonModel;\n /** Which conversion strategy produced this result. */\n readonly source: Dcm2jsonSource;\n}\n\nconst Dcm2jsonOptionsSchema = z\n .object({\n timeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n directOnly: z.boolean().optional(),\n charsetAssume: z.string().min(1).optional(),\n charsetFallback: z.string().min(1).optional(),\n verbosity: z.enum(['verbose', 'debug']).optional(),\n })\n .strict()\n .optional();\n\n/** Options forwarded to the XML conversion path. */\ntype XmlPathOpts = { readonly verbosity?: 'verbose' | 'debug'; readonly charsetAssume?: string; readonly charsetFallback?: string };\n\n/** Maps verbosity level to command-line flag. */\nconst VERBOSITY_FLAGS: Record<'verbose' | 'debug', string> = { verbose: '-v', debug: '-d' };\n\n/**\n * Builds verbosity args for internal calls.\n */\nfunction buildVerbosityArgs(verbosity?: 'verbose' | 'debug'): string[] {\n if (verbosity !== undefined) {\n return [VERBOSITY_FLAGS[verbosity]];\n }\n return [];\n}\n\n/** Builds XML-path options, omitting undefined values for exactOptionalPropertyTypes. */\nfunction buildXmlOpts(options?: Dcm2jsonOptions): XmlPathOpts {\n const result: Record<string, string> = {};\n if (options?.verbosity !== undefined) result['verbosity'] = options.verbosity;\n if (options?.charsetAssume !== undefined) result['charsetAssume'] = options.charsetAssume;\n if (options?.charsetFallback !== undefined) result['charsetFallback'] = options.charsetFallback;\n return result;\n}\n\n/** Returns true if dcm2xml failed due to a charset conversion error. */\nfunction isCharsetError(stderrOutput: string): boolean {\n return stderrOutput.includes('convert character encoding') || stderrOutput.includes('Illegal byte sequence');\n}\n\n/** Runs dcm2xml with given args, parses output to DICOM JSON. */\nasync function runXmlAndParse(binary: string, args: string[], execOpts: { timeoutMs: number; signal?: AbortSignal }): Promise<Result<Dcm2jsonResult>> {\n const xmlResult = await execCommand(binary, args, execOpts);\n if (!xmlResult.ok) return err(xmlResult.error);\n if (xmlResult.value.exitCode !== 0) {\n return err(createToolError('dcm2xml', args, xmlResult.value.exitCode, xmlResult.value.stderr));\n }\n const jsonResult = xmlToJson(xmlResult.value.stdout);\n if (!jsonResult.ok) return err(jsonResult.error);\n return ok({ data: jsonResult.value, source: 'xml' as const });\n}\n\n/**\n * Attempts XML-primary conversion: dcm2xml → xmlToJson.\n * If charset conversion fails and a fallback charset is configured, retries with `+Ca <fallback>`.\n */\nasync function tryXmlPath(inputPath: string, timeoutMs: number, signal?: AbortSignal, opts?: XmlPathOpts): Promise<Result<Dcm2jsonResult>> {\n const xmlBinary = resolveBinary('dcm2xml');\n if (!xmlBinary.ok) return err(xmlBinary.error);\n\n const charsetArgs = opts?.charsetAssume !== undefined ? ['+Ca', opts.charsetAssume] : [];\n const xmlArgs = [...buildVerbosityArgs(opts?.verbosity), ...charsetArgs, '-nat', inputPath];\n const execOpts = signal !== undefined ? { timeoutMs, signal } : { timeoutMs };\n\n const result = await runXmlAndParse(xmlBinary.value, xmlArgs, execOpts);\n\n // On charset conversion failure, retry with the fallback charset\n if (!result.ok && opts?.charsetFallback !== undefined && isCharsetError(result.error.message)) {\n const fallbackArgs = [...buildVerbosityArgs(opts.verbosity), '+Ca', opts.charsetFallback, '-nat', inputPath];\n return runXmlAndParse(xmlBinary.value, fallbackArgs, execOpts);\n }\n\n return result;\n}\n\n/**\n * Attempts direct conversion: dcm2json binary → repairJson → JSON.parse.\n *\n * Uses `+b +bd <tmpdir>` to redirect bulk pixel data to a temp directory\n * (discarded after parsing) so compressed pixel data does not cause failures.\n */\nasync function tryDirectPath(inputPath: string, timeoutMs: number, signal?: AbortSignal, verbosity?: 'verbose' | 'debug'): Promise<Result<Dcm2jsonResult>> {\n const jsonBinary = resolveBinary('dcm2json');\n if (!jsonBinary.ok) {\n return err(jsonBinary.error);\n }\n\n const bulkDir = await createBulkTempDir();\n const directArgs = [...buildVerbosityArgs(verbosity), '+b', '+bd', bulkDir, inputPath];\n\n try {\n const execOpts = signal !== undefined ? { timeoutMs, signal } : { timeoutMs };\n return await execAndParse(jsonBinary.value, directArgs, inputPath, execOpts);\n } finally {\n rm(bulkDir, { recursive: true, force: true }).catch(() => {});\n }\n}\n\n/** Creates a temporary directory for dcm2json bulk data output. */\nasync function createBulkTempDir(): Promise<string> {\n return mkdtemp(join(tmpdir(), 'dcm2json-bulk-'));\n}\n\n/** Runs dcm2json and parses the output. */\nasync function execAndParse(\n binary: string,\n args: string[],\n inputPath: string,\n execOpts: { timeoutMs: number; signal?: AbortSignal }\n): Promise<Result<Dcm2jsonResult>> {\n const result = await execCommand(binary, args, execOpts);\n if (!result.ok) {\n return err(result.error);\n }\n\n if (result.value.exitCode !== 0) {\n return err(createToolError('dcm2json', args, result.value.exitCode, result.value.stderr));\n }\n\n try {\n const repaired = repairJson(result.value.stdout);\n const data = JSON.parse(repaired) as DicomJsonModel;\n return ok({ data, source: 'direct' as const });\n } catch (parseError: unknown) {\n return err(createToolError('dcm2json', [inputPath], 1, `Parse error: ${stderr(parseError).message}`));\n }\n}\n\n/**\n * Converts a DICOM file to the DICOM JSON Model.\n *\n * Uses a two-phase strategy:\n * 1. Primary: dcm2xml → XML-to-JSON conversion (more reliable)\n * 2. Fallback: direct dcm2json binary with JSON repair\n *\n * @param inputPath - Path to the DICOM input file\n * @param options - Conversion options\n * @returns A Result containing the DICOM JSON Model with source discriminant\n *\n * @example\n * ```ts\n * const result = await dcm2json('/path/to/study.dcm');\n * if (result.ok) {\n * console.log(result.value.source); // 'xml' or 'direct'\n * console.log(result.value.data['00100010']); // Patient Name\n * }\n * ```\n */\nasync function dcm2json(inputPath: string, options?: Dcm2jsonOptions): Promise<Result<Dcm2jsonResult>> {\n const validation = Dcm2jsonOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcm2json', validation.error));\n }\n\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const signal = options?.signal;\n const startTime = Date.now();\n const remaining = (): number => Math.max(1000, timeoutMs - (Date.now() - startTime));\n\n const verbosity = options?.verbosity;\n\n // Direct-only mode: skip XML path\n if (options?.directOnly === true) {\n return tryDirectPath(inputPath, remaining(), signal, verbosity);\n }\n\n // Try XML path first\n const xmlResult = await tryXmlPath(inputPath, remaining(), signal, buildXmlOpts(options));\n if (xmlResult.ok) {\n return xmlResult;\n }\n\n // Fall back to direct path with remaining time budget\n return tryDirectPath(inputPath, remaining(), signal, verbosity);\n}\n\nexport { dcm2json };\nexport type { Dcm2jsonOptions, Dcm2jsonResult, Dcm2jsonSource, DicomJsonModel };\n","/**\n * Modify DICOM tags using the dcmodify binary.\n *\n * Uses spawnCommand instead of execCommand because user-supplied DICOM values\n * could contain shell metacharacters. Spawn passes args as an array with no\n * shell interpolation (Rule 7.4).\n *\n * @module dcmodify\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { spawnCommand } from '../exec';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport { resolveBinary } from './_resolveBinary';\nimport { createToolError, createValidationError } from './_toolError';\nimport type { ToolBaseOptions } from './_toolTypes';\n\n/** A single tag modification. */\ninterface TagModification {\n /** DICOM tag to modify, e.g. \"(0010,0010)\". */\n readonly tag: string;\n /** New value for the tag. */\n readonly value: string;\n}\n\n/** Options for {@link dcmodify}. */\ninterface DcmodifyOptions extends ToolBaseOptions {\n /** Tag modifications to apply. */\n readonly modifications?: readonly TagModification[] | undefined;\n /** Tag paths to erase (passed as `-e path`). */\n readonly erasures?: readonly string[] | undefined;\n /** Erase all private tags (uses `-ep` flag). */\n readonly erasePrivateTags?: boolean | undefined;\n /** Do not create backup (.bak) file. Defaults to true. */\n readonly noBackup?: boolean | undefined;\n /** Insert tag if it doesn't exist (uses -i flag). Defaults to false. */\n readonly insertIfMissing?: boolean | undefined;\n /** Treat 'tag not found' as success when erasing (uses -imt flag). Defaults to false. */\n readonly ignoreMissingTags?: boolean | undefined;\n /** Verbosity level for diagnostic output. `'verbose'` maps to `-v`, `'debug'` maps to `-d`. */\n readonly verbosity?: 'verbose' | 'debug' | undefined;\n}\n\n/** Result of a successful dcmodify operation. */\ninterface DcmodifyResult {\n /** Path to the modified DICOM file. */\n readonly filePath: string;\n}\n\n/** Matches a single tag or a dotted tag path: (XXXX,XXXX) or (XXXX,XXXX)[N].(XXXX,XXXX) — [N] required before every dot. */\nconst TAG_OR_PATH_PATTERN = /^\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\)(\\[\\d+\\]\\.\\([0-9A-Fa-f]{4},[0-9A-Fa-f]{4}\\))*(\\[\\d+\\])?$/;\n\nconst TagModificationSchema = z.object({\n tag: z.string().regex(TAG_OR_PATH_PATTERN),\n value: z.string(),\n});\n\n/** Maps verbosity level to command-line flag. */\nconst VERBOSITY_FLAGS: Record<'verbose' | 'debug', string> = { verbose: '-v', debug: '-d' };\n\nconst DcmodifyOptionsSchema = z\n .object({\n timeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n modifications: z.array(TagModificationSchema).optional().default([]),\n erasures: z.array(z.string()).optional(),\n erasePrivateTags: z.boolean().optional(),\n noBackup: z.boolean().optional(),\n insertIfMissing: z.boolean().optional(),\n ignoreMissingTags: z.boolean().optional(),\n verbosity: z.enum(['verbose', 'debug']).optional(),\n })\n .strict()\n .refine(data => data.modifications.length > 0 || (data.erasures !== undefined && data.erasures.length > 0) || data.erasePrivateTags === true, {\n message: 'At least one of modifications, erasures, or erasePrivateTags is required',\n });\n\n/**\n * Builds dcmodify command-line arguments from validated options.\n */\nfunction buildArgs(inputPath: string, options: DcmodifyOptions): string[] {\n const args: string[] = [];\n\n if (options.verbosity !== undefined) {\n args.push(VERBOSITY_FLAGS[options.verbosity]);\n }\n\n if (options.noBackup !== false) {\n args.push('-nb');\n }\n\n if (options.ignoreMissingTags === true) {\n args.push('-imt');\n }\n\n const flag = options.insertIfMissing === true ? '-i' : '-m';\n const modifications = options.modifications ?? [];\n\n for (const mod of modifications) {\n args.push(flag, `${mod.tag}=${mod.value}`);\n }\n\n if (options.erasures !== undefined) {\n for (const erasure of options.erasures) {\n args.push('-e', erasure);\n }\n }\n\n if (options.erasePrivateTags === true) {\n args.push('-ep');\n }\n\n args.push(inputPath);\n\n return args;\n}\n\n/**\n * Modifies DICOM tags in a file using the dcmodify binary.\n *\n * Uses spawn (not exec) for safety with user-supplied values.\n *\n * @param inputPath - Path to the DICOM file to modify (modified in-place)\n * @param options - Modification options\n * @returns A Result containing the file path or an error\n *\n * @example\n * ```ts\n * const result = await dcmodify('/path/to/study.dcm', {\n * modifications: [\n * { tag: '(0010,0010)', value: 'Anonymous' },\n * { tag: '(0010,0020)', value: 'ANON001' },\n * ],\n * });\n * ```\n */\nasync function dcmodify(inputPath: string, options: DcmodifyOptions): Promise<Result<DcmodifyResult>> {\n const validation = DcmodifyOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmodify', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmodify');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(inputPath, options);\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n const result = await spawnCommand(binaryResult.value, args, {\n timeoutMs,\n signal: options.signal,\n });\n\n if (!result.ok) {\n return err(result.error);\n }\n\n if (result.value.exitCode !== 0) {\n return err(createToolError('dcmodify', args, result.value.exitCode, result.value.stderr));\n }\n\n return ok({ filePath: inputPath });\n}\n\nexport { dcmodify };\nexport type { DcmodifyOptions, DcmodifyResult, TagModification };\n","/**\n * File operation helpers for DicomInstance.\n *\n * Extracted to keep DicomInstance methods under line-count limits.\n *\n * @module dicom/_fileHelpers\n */\n\nimport { copyFile, stat, unlink } from 'node:fs/promises';\nimport { tryCatch } from 'stderr-lib';\nimport type { DicomFilePath } from '../brands';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport type { ChangeSet } from './ChangeSet';\nimport { dcmodify } from '../tools/dcmodify';\n\n/** Options for file I/O operations. */\ninterface FileIOOptions {\n /** Timeout in milliseconds. Defaults to DEFAULT_TIMEOUT_MS. */\n readonly timeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n/** Options for opening a DICOM file. Extends FileIOOptions with read-specific settings. */\ninterface DicomOpenOptions extends FileIOOptions {\n /** Assume the specified character set when SpecificCharacterSet (0008,0005) is absent. Maps to dcm2xml `+Ca`. */\n readonly charsetAssume?: string | undefined;\n /** Fallback charset to retry with when UTF-8 conversion fails due to illegal byte sequences. Maps to dcm2xml `+Ca`. When set, a charset conversion failure triggers an automatic retry with this charset assumed. `'Latin1'` is recommended — it maps every byte 0x00-0xFF to a valid character, so conversion never fails. */\n readonly charsetFallback?: string | undefined;\n}\n\n/** Bridges a ChangeSet to a dcmodify call on the given file. */\nasync function applyModifications(filePath: DicomFilePath, changeset: ChangeSet, options: FileIOOptions): Promise<Result<void>> {\n const modifications = changeset.toModifications();\n const erasures = changeset.toErasureArgs();\n\n const hasErasures = erasures.length > 0 || changeset.erasePrivate;\n\n const result = await dcmodify(filePath, {\n modifications: modifications.length > 0 ? modifications : undefined,\n erasures: erasures.length > 0 ? erasures : undefined,\n erasePrivateTags: changeset.erasePrivate || undefined,\n insertIfMissing: true,\n ignoreMissingTags: hasErasures || undefined,\n timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n signal: options.signal,\n });\n\n if (!result.ok) return err(result.error);\n return ok(undefined);\n}\n\n/** Wraps fs.copyFile in a Result. */\nasync function copyFileSafe(source: string, dest: string): Promise<Result<void>> {\n return tryCatch(\n () => copyFile(source, dest),\n e => new Error(`Failed to copy file: ${e.message}`)\n );\n}\n\n/** Wraps fs.stat in a Result, returning file size. */\nasync function statFileSize(path: string): Promise<Result<number>> {\n return tryCatch(\n async () => (await stat(path)).size,\n e => new Error(`Failed to stat file: ${e.message}`)\n );\n}\n\n/** Wraps fs.unlink in a Result. */\nasync function unlinkFile(path: string): Promise<Result<void>> {\n return tryCatch(\n () => unlink(path),\n e => new Error(`Failed to delete file: ${e.message}`)\n );\n}\n\nexport { applyModifications, copyFileSafe, statFileSize, unlinkFile };\nexport type { FileIOOptions, DicomOpenOptions };\n","/**\n * Unified DICOM object composing DicomDataset + ChangeSet + file I/O.\n *\n * Every setter returns a new DicomInstance — the original is never modified.\n * Designed for ergonomic DICOM workflows that combine reading, modifying,\n * and writing DICOM data in a single fluent API.\n *\n * @module dicom/DicomInstance\n */\n\nimport type { DicomFilePath, DicomTag, DicomTagPath, SOPClassUID } from '../brands';\nimport { createDicomFilePath } from '../brands';\nimport { DEFAULT_TIMEOUT_MS } from '../constants';\nimport type { Result } from '../types';\nimport { err, ok } from '../types';\nimport { ChangeSet } from './ChangeSet';\nimport { DicomDataset } from './DicomDataset';\nimport { dcm2json } from '../tools';\nimport type { DicomOpenOptions, FileIOOptions } from './_fileHelpers';\nimport { applyModifications, copyFileSafe, statFileSize, unlinkFile } from './_fileHelpers';\n\n// ---------------------------------------------------------------------------\n// DicomInstance class\n// ---------------------------------------------------------------------------\n\n/**\n * Unified DICOM object composing dataset, change tracking, file path, and metadata.\n *\n * Every setter returns a new immutable instance — the original is never modified.\n * Use the static factories {@link DicomInstance.open} or {@link DicomInstance.fromDataset}\n * to create instances.\n *\n * @example\n * ```ts\n * const result = await DicomInstance.open('/path/to/file.dcm');\n * if (!result.ok) { console.error(result.error.message); return; }\n * const modified = result.value\n * .setPatientName('DOE^JOHN')\n * .setPatientID('PAT001')\n * .erasePrivateTags();\n * await modified.writeAs('/path/to/output.dcm');\n * ```\n */\nclass DicomInstance {\n private readonly dicomDataset: DicomDataset;\n private readonly changeSet: ChangeSet;\n private readonly filepath: DicomFilePath | undefined;\n private readonly meta: ReadonlyMap<string, unknown>;\n\n private constructor(dataset: DicomDataset, changes: ChangeSet, filePath: DicomFilePath | undefined, metadata: ReadonlyMap<string, unknown>) {\n this.dicomDataset = dataset;\n this.changeSet = changes;\n this.filepath = filePath;\n this.meta = metadata;\n }\n\n // -----------------------------------------------------------------------\n // Factories\n // -----------------------------------------------------------------------\n\n /**\n * Opens a DICOM file and creates a DicomInstance.\n *\n * @param path - Filesystem path to the DICOM file\n * @param options - Timeout, abort, and charset options\n * @returns A Result containing the DicomInstance or an error\n */\n static async open(path: string, options?: DicomOpenOptions): Promise<Result<DicomInstance>> {\n const filePathResult = createDicomFilePath(path);\n if (!filePathResult.ok) return err(filePathResult.error);\n\n const jsonResult = await dcm2json(path, {\n timeoutMs: options?.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n signal: options?.signal,\n charsetAssume: options?.charsetAssume,\n charsetFallback: options?.charsetFallback,\n });\n if (!jsonResult.ok) return err(jsonResult.error);\n\n const datasetResult = DicomDataset.fromJson(jsonResult.value.data);\n if (!datasetResult.ok) return err(datasetResult.error);\n\n return ok(new DicomInstance(datasetResult.value, ChangeSet.empty(), filePathResult.value, new Map()));\n }\n\n /**\n * Creates a DicomInstance from an existing DicomDataset.\n *\n * @param dataset - The DicomDataset to wrap\n * @param filePath - Optional file path (e.g. if the dataset came from a file)\n * @returns A Result containing the DicomInstance\n */\n static fromDataset(dataset: DicomDataset, filePath?: string): Result<DicomInstance> {\n let fp: DicomFilePath | undefined;\n if (filePath !== undefined) {\n const fpResult = createDicomFilePath(filePath);\n if (!fpResult.ok) return err(fpResult.error);\n fp = fpResult.value;\n }\n return ok(new DicomInstance(dataset, ChangeSet.empty(), fp, new Map()));\n }\n\n // -----------------------------------------------------------------------\n // Read accessors (delegate to DicomDataset)\n // -----------------------------------------------------------------------\n\n /** The underlying immutable DICOM dataset. */\n get dataset(): DicomDataset {\n return this.dicomDataset;\n }\n\n /** The pending change set. */\n get changes(): ChangeSet {\n return this.changeSet;\n }\n\n /** Whether there are unsaved changes. */\n get hasUnsavedChanges(): boolean {\n return !this.changeSet.isEmpty;\n }\n\n /** The file path, or undefined if this instance has no associated file. */\n get filePath(): string | undefined {\n return this.filepath;\n }\n\n /** Patient's Name (0010,0010). */\n get patientName(): string {\n return this.dicomDataset.patientName;\n }\n\n /** Patient ID (0010,0020). */\n get patientID(): string {\n return this.dicomDataset.patientID;\n }\n\n /** Study Date (0008,0020). */\n get studyDate(): string {\n return this.dicomDataset.studyDate;\n }\n\n /** Modality (0008,0060). */\n get modality(): string {\n return this.dicomDataset.modality;\n }\n\n /** Accession Number (0008,0050). */\n get accession(): string {\n return this.dicomDataset.accession;\n }\n\n /** SOP Class UID (0008,0016). */\n get sopClassUID(): SOPClassUID | undefined {\n return this.dicomDataset.sopClassUID;\n }\n\n /** Study Instance UID (0020,000D). */\n get studyInstanceUID(): string {\n return this.dicomDataset.studyInstanceUID;\n }\n\n /** Series Instance UID (0020,000E). */\n get seriesInstanceUID(): string {\n return this.dicomDataset.seriesInstanceUID;\n }\n\n /** SOP Instance UID (0008,0018). */\n get sopInstanceUID(): string {\n return this.dicomDataset.sopInstanceUID;\n }\n\n /** Transfer Syntax UID (0002,0010). */\n get transferSyntaxUID(): string {\n return this.dicomDataset.transferSyntaxUID;\n }\n\n /**\n * Gets a tag value as a string with optional fallback.\n *\n * @param tag - A DICOM tag, e.g. `'(0010,0010)'` or `'00100010'`\n * @param fallback - Value to return if tag is missing (default: `''`)\n */\n getString(tag: DicomTag | string, fallback = ''): string {\n return this.dicomDataset.getString(tag, fallback);\n }\n\n /**\n * Gets a tag value as a number.\n *\n * @param tag - A DICOM tag, e.g. `'(0020,0013)'`\n */\n getNumber(tag: DicomTag | string): Result<number> {\n return this.dicomDataset.getNumber(tag);\n }\n\n /** Checks whether a tag exists in the dataset. */\n hasTag(tag: DicomTag | string): boolean {\n return this.dicomDataset.hasTag(tag);\n }\n\n /**\n * Finds all values matching a wildcard path.\n *\n * @param path - A DicomTagPath with optional wildcard indices\n */\n findValues(path: DicomTagPath): ReadonlyArray<unknown> {\n return this.dicomDataset.findValues(path);\n }\n\n // -----------------------------------------------------------------------\n // Write methods (return new instance)\n // -----------------------------------------------------------------------\n\n /**\n * Sets a tag value, returning a new DicomInstance.\n *\n * @param path - The DICOM tag path (e.g. `'(0010,0010)'`)\n * @param value - The new value\n */\n setTag(path: string, value: string): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.setTag(path, value), this.filepath, this.meta);\n }\n\n /**\n * Erases a tag, returning a new DicomInstance.\n *\n * @param path - The DICOM tag path to erase\n */\n eraseTag(path: string): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.eraseTag(path), this.filepath, this.meta);\n }\n\n /** Erases all private tags, returning a new DicomInstance. */\n erasePrivateTags(): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.erasePrivateTags(), this.filepath, this.meta);\n }\n\n /** Sets Patient's Name (0010,0010). */\n setPatientName(value: string): DicomInstance {\n return this.setTag('(0010,0010)', value);\n }\n\n /** Sets Patient ID (0010,0020). */\n setPatientID(value: string): DicomInstance {\n return this.setTag('(0010,0020)', value);\n }\n\n /** Sets Study Date (0008,0020). */\n setStudyDate(value: string): DicomInstance {\n return this.setTag('(0008,0020)', value);\n }\n\n /** Sets Modality (0008,0060). */\n setModality(value: string): DicomInstance {\n return this.setTag('(0008,0060)', value);\n }\n\n /** Sets Accession Number (0008,0050). */\n setAccessionNumber(value: string): DicomInstance {\n return this.setTag('(0008,0050)', value);\n }\n\n /** Sets Study Description (0008,1030). */\n setStudyDescription(value: string): DicomInstance {\n return this.setTag('(0008,1030)', value);\n }\n\n /** Sets Series Description (0008,103E). */\n setSeriesDescription(value: string): DicomInstance {\n return this.setTag('(0008,103E)', value);\n }\n\n /** Sets Institution Name (0008,0080). */\n setInstitutionName(value: string): DicomInstance {\n return this.setTag('(0008,0080)', value);\n }\n\n /**\n * Transforms a tag value using a function.\n *\n * The function receives the current string value (or undefined if tag is missing)\n * and returns the new value. Returns a new DicomInstance with the modification.\n *\n * @param path - The DICOM tag path\n * @param fn - Transform function receiving the current value\n */\n transformTag(path: string, fn: (current: string | undefined) => string): DicomInstance {\n const current = this.dicomDataset.getString(path);\n const newValue = fn(current.length > 0 ? current : undefined);\n return this.setTag(path, newValue);\n }\n\n /**\n * Sets multiple tags at once, returning a new DicomInstance.\n *\n * @param entries - A record of tag path → value pairs\n */\n setBatch(entries: Readonly<Record<string, string>>): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.setBatch(entries), this.filepath, this.meta);\n }\n\n /**\n * Returns a new DicomInstance with the given changes merged into pending changes.\n *\n * @param changes - A ChangeSet to merge with existing pending changes\n * @returns A new DicomInstance with accumulated changes\n */\n withChanges(changes: ChangeSet): DicomInstance {\n return new DicomInstance(this.dicomDataset, this.changeSet.merge(changes), this.filepath, this.meta);\n }\n\n /**\n * Returns a new DicomInstance pointing to a different file path.\n *\n * Preserves the dataset, pending changes, and metadata.\n *\n * @param newPath - The new filesystem path (validated via createDicomFilePath)\n * @returns A new DicomInstance with the updated path\n * @throws If the path is invalid\n */\n withFilePath(newPath: string): DicomInstance {\n const result = createDicomFilePath(newPath);\n if (!result.ok) throw result.error;\n return new DicomInstance(this.dicomDataset, this.changeSet, result.value, this.meta);\n }\n\n // -----------------------------------------------------------------------\n // File I/O\n // -----------------------------------------------------------------------\n\n /**\n * Applies pending changes to the file in-place.\n *\n * Requires that the instance has an associated file path.\n *\n * @param options - Timeout and abort options\n */\n async applyChanges(options?: FileIOOptions): Promise<Result<void>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n if (this.changeSet.isEmpty) return ok(undefined);\n return applyModifications(this.filepath, this.changeSet, options ?? {});\n }\n\n /**\n * Copies the file to a new path and applies pending changes to the copy.\n *\n * Returns a new DicomInstance pointing to the output path.\n *\n * @param outputPath - Destination filesystem path\n * @param options - Timeout and abort options\n */\n async writeAs(outputPath: string, options?: FileIOOptions): Promise<Result<DicomInstance>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n\n const outPathResult = createDicomFilePath(outputPath);\n if (!outPathResult.ok) return err(outPathResult.error);\n\n const copyResult = await copyFileSafe(this.filepath, outputPath);\n if (!copyResult.ok) return err(copyResult.error);\n\n if (!this.changeSet.isEmpty) {\n const applyResult = await applyModifications(outPathResult.value, this.changeSet, options ?? {});\n if (!applyResult.ok) {\n await unlinkFile(outputPath);\n return err(applyResult.error);\n }\n }\n\n return ok(new DicomInstance(this.dicomDataset, ChangeSet.empty(), outPathResult.value, this.meta));\n }\n\n /**\n * Gets the file size in bytes.\n *\n * @returns A Result containing the size or an error\n */\n async fileSize(): Promise<Result<number>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n return statFileSize(this.filepath);\n }\n\n /**\n * Deletes the associated file from the filesystem.\n *\n * @returns A Result indicating success or failure\n */\n async unlink(): Promise<Result<void>> {\n if (this.filepath === undefined) return err(new Error('No file path associated with this instance'));\n return unlinkFile(this.filepath);\n }\n\n // -----------------------------------------------------------------------\n // Metadata (non-DICOM app context)\n // -----------------------------------------------------------------------\n\n /**\n * Returns a new DicomInstance with application metadata attached.\n *\n * Metadata is not stored in the DICOM file — it's for application context\n * (e.g. tracking source association, processing status, etc.).\n *\n * @param key - Metadata key\n * @param value - Metadata value\n */\n withMetadata(key: string, value: unknown): DicomInstance {\n const newMeta = new Map(this.meta);\n newMeta.set(key, value);\n return new DicomInstance(this.dicomDataset, this.changeSet, this.filepath, newMeta);\n }\n\n /**\n * Gets application metadata by key.\n *\n * @param key - Metadata key\n * @returns The metadata value or undefined\n */\n getMetadata(key: string): unknown {\n return this.meta.get(key);\n }\n}\n\nexport { DicomInstance };\n","/**\n * Pooled DICOM receiver with auto-scaling.\n *\n * Manages a pool of long-lived `Dcmrecv` workers behind a TCP proxy,\n * routing incoming connections to idle workers. Workers are reused\n * across associations — they are only stopped during scale-down or\n * shutdown.\n *\n * @module servers/DicomReceiver\n */\n\nimport * as net from 'node:net';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { setTimeout as delay } from 'node:timers/promises';\nimport { EventEmitter } from 'node:events';\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { isSafePath, isValidAETitle } from '../patterns';\nimport { createValidationError } from '../tools/_toolError';\nimport { ensureDirectory, moveFile, statFileSafe, removeDirSafe } from '../utils';\nimport { Dcmrecv } from './Dcmrecv';\nimport type { FilenameModeValue, StorageModeValue } from './Dcmrecv';\nimport type { AssociationCompleteData } from '../events/dcmrecv';\nimport { DicomInstance } from '../dicom';\nimport type { DicomOpenOptions } from '../dicom/_fileHelpers';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_MIN_POOL_SIZE = 2;\nconst DEFAULT_MAX_POOL_SIZE = 10;\nconst DEFAULT_CONNECTION_TIMEOUT_MS = 10_000;\nconst CONNECTION_RETRY_INTERVAL_MS = 500;\nconst MAX_CONNECTION_RETRIES = 200;\nconst MAX_OUTPUT_LINES_PER_ASSOCIATION = 500;\n\n// ---------------------------------------------------------------------------\n// Public interfaces\n// ---------------------------------------------------------------------------\n\n/** Snapshot of the worker pool state. */\ninterface PoolStatus {\n /** Number of idle workers ready for connections. */\n readonly idle: number;\n /** Number of workers currently handling associations. */\n readonly busy: number;\n /** Total number of workers (idle + busy). */\n readonly total: number;\n}\n\n/** Data emitted with FILE_RECEIVED events (raw from dcmrecv, before processing). */\ninterface ReceiverFileReceivedData {\n readonly filePath: string;\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Data emitted with FILE_STORED events (file moved to association dir). */\ninterface ReceiverFileStoredData {\n readonly filePath: string;\n readonly fileSize: number;\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Data emitted with INSTANCE_RECEIVED events (parsed DicomInstance available). */\ninterface ReceiverInstanceData {\n readonly filePath: string;\n readonly fileSize: number;\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly instance: DicomInstance;\n}\n\n/** Data emitted with ASSOCIATION_COMPLETE events. */\ninterface ReceiverAssociationData {\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly durationMs: number;\n readonly endReason: 'release' | 'abort';\n readonly totalBytes: number;\n readonly bytesPerSecond: number;\n readonly startAt: number;\n readonly endAt: number;\n /** Captured stdout/stderr lines from the worker during this association. */\n readonly output: readonly string[];\n}\n\n/** Data emitted with ASSOCIATION_RECEIVED events (bubbled from worker). */\ninterface PoolAssociationReceivedData {\n readonly associationId: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Data emitted with C_STORE_REQUEST events (bubbled from worker). */\ninterface PoolCStoreRequestData {\n readonly associationId: string;\n readonly raw: string;\n}\n\n/** Data emitted with ECHO_REQUEST events (bubbled from worker). */\ninterface PoolEchoRequestData {\n readonly associationId: string;\n}\n\n/** Data emitted with REFUSING_ASSOCIATION events (bubbled from worker). */\ninterface PoolRefusingAssociationData {\n readonly reason: string;\n}\n\n/** Data emitted with INSTANCE_ERROR events when DicomInstance.open fails. */\ninterface ReceiverInstanceErrorData {\n readonly error: Error;\n /** Whether this was a thrown exception (true) or a Result error (false). */\n readonly thrown: boolean;\n readonly filePath: string;\n readonly fileSize: number;\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n}\n\n/** Data emitted with ASSOCIATION_FINALIZED — all work (including parsing) is done. */\ninterface ReceiverAssociationFinalizedData {\n readonly associationId: string;\n readonly associationDir: string;\n readonly callingAE: string;\n readonly calledAE: string;\n readonly source: string;\n readonly files: readonly string[];\n readonly instancesReceived: number;\n readonly instanceErrors: number;\n}\n\n/** Data emitted with error events. */\ninterface ReceiverErrorData {\n readonly error: Error;\n readonly filePath?: string;\n readonly associationId?: string;\n readonly associationDir?: string;\n readonly callingAE?: string;\n readonly calledAE?: string;\n readonly source?: string;\n}\n\n/** Typed event map for DicomReceiver. */\ninterface DicomReceiverEventMap {\n FILE_RECEIVED: [ReceiverFileReceivedData];\n FILE_STORED: [ReceiverFileStoredData];\n INSTANCE_RECEIVED: [ReceiverInstanceData];\n INSTANCE_ERROR: [ReceiverInstanceErrorData];\n ASSOCIATION_COMPLETE: [ReceiverAssociationData];\n ASSOCIATION_FINALIZED: [ReceiverAssociationFinalizedData];\n ASSOCIATION_RECEIVED: [PoolAssociationReceivedData];\n C_STORE_REQUEST: [PoolCStoreRequestData];\n ECHO_REQUEST: [PoolEchoRequestData];\n REFUSING_ASSOCIATION: [PoolRefusingAssociationData];\n error: [ReceiverErrorData];\n}\n\n/** Options for creating a DicomReceiver instance. */\ninterface DicomReceiverOptions {\n /** External port to listen on (required). */\n readonly port: number;\n /** Root directory for association subdirectories (required). */\n readonly storageDir: string;\n /** Application Entity Title for workers. */\n readonly aeTitle?: string | undefined;\n /** Minimum number of idle workers to maintain. */\n readonly minPoolSize?: number | undefined;\n /** Maximum total workers allowed. */\n readonly maxPoolSize?: number | undefined;\n /** Timeout for waiting for an idle worker (milliseconds). */\n readonly connectionTimeoutMs?: number | undefined;\n /** Path to a dcmrecv association negotiation configuration file. */\n readonly configFile?: string | undefined;\n /** Profile name within the configuration file. */\n readonly configProfile?: string | undefined;\n /** ACSE timeout in seconds (passed through to Dcmrecv workers). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed through to Dcmrecv workers). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum PDU receive size (passed through to Dcmrecv workers). */\n readonly maxPdu?: number | undefined;\n /** Filename generation mode for received files (passed through to Dcmrecv workers). */\n readonly filenameMode?: FilenameModeValue | undefined;\n /** Extension appended to received filenames, e.g. `'.dcm'` (passed through to Dcmrecv workers). */\n readonly filenameExtension?: string | undefined;\n /** Storage mode for received files (passed through to Dcmrecv workers). */\n readonly storageMode?: StorageModeValue | undefined;\n /** Options passed to DicomInstance.open() for each received file. Defaults charsetFallback to `'Latin1'`. */\n readonly instanceOpenOptions?: DicomOpenOptions | undefined;\n /** Whether to parse received files into DicomInstance. When false, INSTANCE_RECEIVED and INSTANCE_ERROR events are not emitted. Defaults to true. */\n readonly parseInstances?: boolean | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Zod validation schema\n// ---------------------------------------------------------------------------\n\nconst DicomReceiverOptionsSchema = z\n .object({\n port: z.number().int().min(0).max(65535),\n storageDir: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in storageDir' }),\n aeTitle: z.string().min(1).max(16).refine(isValidAETitle, { message: 'AE Title contains invalid characters' }).optional(),\n minPoolSize: z.number().int().min(1).max(100).optional(),\n maxPoolSize: z.number().int().min(1).max(100).optional(),\n connectionTimeoutMs: z.number().int().positive().optional(),\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }).optional(),\n configProfile: z.string().min(1).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n filenameMode: z.enum(['default', 'unique', 'short-unique', 'system-time']).optional(),\n filenameExtension: z.string().min(1).optional(),\n storageMode: z.enum(['normal', 'bit-preserving', 'ignore']).optional(),\n instanceOpenOptions: z\n .object({\n timeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n charsetAssume: z.string().min(1).optional(),\n charsetFallback: z.string().min(1).optional(),\n })\n .strict()\n .optional(),\n parseInstances: z.boolean().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict()\n .refine(data => (data.minPoolSize ?? DEFAULT_MIN_POOL_SIZE) <= (data.maxPoolSize ?? DEFAULT_MAX_POOL_SIZE), {\n message: 'minPoolSize must be <= maxPoolSize',\n });\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\n/** Frozen context for a single association, captured synchronously at connection time. */\ninterface AssociationContext {\n readonly associationId: string;\n readonly associationDir: string;\n readonly startAt: number;\n}\n\n// ---------------------------------------------------------------------------\n// Internal Worker class\n// ---------------------------------------------------------------------------\n\n/** Encapsulates a single Dcmrecv worker and its per-association state. */\nclass Worker {\n readonly dcmrecv: Dcmrecv;\n readonly port: number;\n readonly tempDir: string;\n private _state: 'idle' | 'busy' | 'finalizing' = 'idle';\n private _context: AssociationContext | undefined;\n private readonly _pending = new Set<Promise<void>>();\n private readonly _instancePending = new Set<Promise<void>>();\n private _instancesReceived = 0;\n private _instanceErrors = 0;\n private readonly _files: string[] = [];\n private readonly _fileSizes: number[] = [];\n private readonly _outputLines: string[] = [];\n private _remoteSocket: net.Socket | undefined;\n private _workerSocket: net.Socket | undefined;\n\n constructor(dcmrecv: Dcmrecv, port: number, tempDir: string) {\n this.dcmrecv = dcmrecv;\n this.port = port;\n this.tempDir = tempDir;\n }\n\n /** Current worker state: idle (ready), busy (handling association), finalizing (draining). */\n get state(): 'idle' | 'busy' | 'finalizing' {\n return this._state;\n }\n\n /** Active association context, or undefined when idle. */\n get context(): AssociationContext | undefined {\n return this._context;\n }\n\n /** Files moved to the association directory during the current association. */\n get files(): readonly string[] {\n return this._files;\n }\n\n /** Byte sizes parallel to files[], for transfer stats. */\n get fileSizes(): readonly number[] {\n return this._fileSizes;\n }\n\n /** Captured output lines during the current association. */\n get outputLines(): readonly string[] {\n return this._outputLines;\n }\n\n /** Marks the worker busy with a new association context. */\n beginAssociation(ctx: AssociationContext): void {\n this._state = 'busy';\n this._context = ctx;\n this._files.length = 0;\n this._fileSizes.length = 0;\n this._outputLines.length = 0;\n this._pending.clear();\n this._instancePending.clear();\n this._instancesReceived = 0;\n this._instanceErrors = 0;\n }\n\n /** Marks the worker as finalizing — still has valid context but cannot accept new connections. */\n markFinalizing(): void {\n this._state = 'finalizing';\n }\n\n /**\n * Returns the worker to idle. Context is intentionally preserved so that\n * late FILE_RECEIVED events (arriving in a subsequent pipe chunk after\n * ASSOCIATION_RELEASE) still have valid association info. Context is\n * cleared on the next {@link beginAssociation} call.\n */\n endAssociation(): void {\n this._state = 'idle';\n // NOTE: _context is NOT cleared here — see JSDoc above\n this._files.length = 0;\n this._fileSizes.length = 0;\n this._outputLines.length = 0;\n this._pending.clear();\n this._instancePending.clear();\n this._instancesReceived = 0;\n this._instanceErrors = 0;\n this._remoteSocket = undefined;\n this._workerSocket = undefined;\n }\n\n /** Tracks an in-flight file handling promise; auto-removes on completion. */\n trackFile(promise: Promise<void>): void {\n this._pending.add(promise);\n void promise.finally(() => {\n this._pending.delete(promise);\n });\n }\n\n /** Tracks an in-flight instance parsing promise; auto-removes on completion. */\n trackInstance(promise: Promise<void>): void {\n this._instancePending.add(promise);\n void promise.finally(() => {\n this._instancePending.delete(promise);\n });\n }\n\n /** Records a successful instance parse. */\n recordInstanceSuccess(): void {\n this._instancesReceived++;\n }\n\n /** Records a failed instance parse. */\n recordInstanceError(): void {\n this._instanceErrors++;\n }\n\n /** Awaits all in-flight instance parsing promises. */\n async drainInstancePending(): Promise<void> {\n if (this._instancePending.size > 0) {\n await Promise.all(this._instancePending);\n }\n }\n\n /** Number of successfully parsed instances in this association. */\n get instancesReceived(): number {\n return this._instancesReceived;\n }\n\n /** Number of failed instance parses in this association. */\n get instanceErrors(): number {\n return this._instanceErrors;\n }\n\n /** Records a successfully received file path and its size. */\n recordFile(filePath: string, size: number): void {\n this._files.push(filePath);\n this._fileSizes.push(size);\n }\n\n /** Awaits all in-flight file handling promises. */\n async drainPendingFiles(): Promise<void> {\n if (this._pending.size > 0) {\n await Promise.all(this._pending);\n }\n }\n\n /** Appends a line to the output buffer, respecting the cap. */\n captureOutput(text: string): void {\n if (this._outputLines.length < MAX_OUTPUT_LINES_PER_ASSOCIATION) {\n this._outputLines.push(text);\n }\n }\n\n /** Stores the remote and worker sockets for later cleanup. */\n setSockets(remote: net.Socket, worker: net.Socket): void {\n this._remoteSocket = remote;\n this._workerSocket = worker;\n }\n\n /** Destroys both sockets if they exist and are not already destroyed. */\n destroySockets(): void {\n if (this._remoteSocket !== undefined && !this._remoteSocket.destroyed) {\n this._remoteSocket.destroy();\n }\n if (this._workerSocket !== undefined && !this._workerSocket.destroyed) {\n this._workerSocket.destroy();\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Port allocation helper\n// ---------------------------------------------------------------------------\n\n/** Allocates a free ephemeral port by binding to port 0. */\nfunction allocatePort(): Promise<Result<number>> {\n return new Promise(resolve => {\n const server = net.createServer();\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address();\n if (addr === null || typeof addr === 'string') {\n server.close(() => resolve(err(new Error('Failed to allocate port'))));\n return;\n }\n const port = addr.port;\n server.close(() => resolve(ok(port)));\n });\n server.on('error', e => {\n resolve(err(new Error(`Port allocation failed: ${e.message}`)));\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Trivial helpers\n// ---------------------------------------------------------------------------\n\n/** Sums an array of numbers iteratively. */\nfunction sumArray(arr: readonly number[]): number {\n let total = 0;\n for (let i = 0; i < arr.length; i++) {\n total += arr[i] ?? 0;\n }\n return total;\n}\n\n// ---------------------------------------------------------------------------\n// DicomReceiver class\n// ---------------------------------------------------------------------------\n\n/**\n * Pooled DICOM receiver with auto-scaling.\n *\n * Manages a pool of long-lived `Dcmrecv` workers behind a TCP proxy.\n * Incoming connections are routed to idle workers. Workers are reused\n * across associations and only stopped during scale-down or shutdown.\n *\n * @example\n * ```ts\n * const result = DicomReceiver.create({\n * port: 4242,\n * storageDir: '/data/received',\n * minPoolSize: 2,\n * maxPoolSize: 8,\n * });\n * if (!result.ok) { console.error(result.error.message); return; }\n * const receiver = result.value;\n *\n * receiver.onFileReceived(data => console.log('File:', data.filePath));\n * receiver.onAssociationComplete(data => console.log('Done:', data.associationDir));\n *\n * await receiver.start();\n * ```\n */\nclass DicomReceiver extends EventEmitter<DicomReceiverEventMap> {\n private readonly options: DicomReceiverOptions;\n private readonly minPoolSize: number;\n private readonly maxPoolSize: number;\n private readonly connectionTimeoutMs: number;\n private readonly resolvedInstanceOpenOptions: DicomOpenOptions;\n private readonly parseInstances: boolean;\n private readonly workers: Map<number, Worker> = new Map();\n private tcpServer: net.Server | undefined;\n private associationCounter = 0;\n private started = false;\n private stopping = false;\n private abortHandler: (() => void) | undefined;\n\n private constructor(options: DicomReceiverOptions) {\n super();\n this.setMaxListeners(20);\n this.options = options;\n this.minPoolSize = options.minPoolSize ?? DEFAULT_MIN_POOL_SIZE;\n this.maxPoolSize = options.maxPoolSize ?? DEFAULT_MAX_POOL_SIZE;\n this.connectionTimeoutMs = options.connectionTimeoutMs ?? DEFAULT_CONNECTION_TIMEOUT_MS;\n this.resolvedInstanceOpenOptions = { charsetFallback: 'Latin1', ...options.instanceOpenOptions };\n this.parseInstances = options.parseInstances ?? true;\n }\n\n // -----------------------------------------------------------------------\n // Public API\n // -----------------------------------------------------------------------\n\n /**\n * Creates a new DicomReceiver instance.\n *\n * @param options - Configuration options\n * @returns A Result containing the instance or a validation error\n */\n static create(options: DicomReceiverOptions): Result<DicomReceiver> {\n const validation = DicomReceiverOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('DicomReceiver', validation.error));\n }\n return ok(new DicomReceiver(options));\n }\n\n /**\n * Starts the TCP proxy and spawns the initial worker pool.\n *\n * @returns A Result indicating success or failure\n */\n async start(): Promise<Result<void>> {\n if (this.started) {\n return err(new Error('DicomReceiver: already started'));\n }\n this.started = true;\n\n const storageDirResult = await ensureDirectory(this.options.storageDir);\n if (!storageDirResult.ok) return storageDirResult;\n\n const spawnResults = await this.spawnWorkers(this.minPoolSize);\n if (!spawnResults.ok) return spawnResults;\n\n const listenResult = await this.startTcpProxy();\n if (!listenResult.ok) return listenResult;\n\n if (this.options.signal !== undefined) {\n this.wireAbortSignal(this.options.signal);\n }\n\n return ok(undefined);\n }\n\n /**\n * Stops the TCP proxy and all workers.\n */\n async stop(): Promise<void> {\n if (!this.started || this.stopping) {\n return;\n }\n this.stopping = true;\n\n if (this.options.signal !== undefined && this.abortHandler !== undefined) {\n this.options.signal.removeEventListener('abort', this.abortHandler);\n }\n\n await this.closeTcpProxy();\n\n // Drain in-flight work on busy/finalizing workers before killing processes\n await this.drainAllWorkers();\n\n const stopPromises: Promise<void>[] = [];\n for (const worker of this.workers.values()) {\n stopPromises.push(this.stopWorker(worker));\n }\n await Promise.all(stopPromises);\n this.workers.clear();\n\n this.started = false;\n this.stopping = false;\n }\n\n /**\n * Registers a typed listener for a DicomReceiver-specific event.\n *\n * @param event - The event name from DicomReceiverEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof DicomReceiverEventMap>(event: K, listener: (...args: DicomReceiverEventMap[K]) => void): this {\n return this.on(event, listener as never);\n }\n\n /**\n * Registers a listener for files received by dcmrecv (before move/parse).\n *\n * @param listener - Callback receiving raw file data\n * @returns this for chaining\n */\n onFileReceived(listener: (data: ReceiverFileReceivedData) => void): this {\n return this.on('FILE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for files stored in the association directory.\n *\n * @param listener - Callback receiving stored file data with size\n * @returns this for chaining\n */\n onFileStored(listener: (data: ReceiverFileStoredData) => void): this {\n return this.on('FILE_STORED', listener);\n }\n\n /**\n * Registers a listener for parsed DicomInstance availability.\n *\n * @param listener - Callback receiving instance data\n * @returns this for chaining\n */\n onInstanceReceived(listener: (data: ReceiverInstanceData) => void): this {\n return this.on('INSTANCE_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for DicomInstance.open failures.\n *\n * @param listener - Callback receiving instance error data\n * @returns this for chaining\n */\n onInstanceError(listener: (data: ReceiverInstanceErrorData) => void): this {\n return this.on('INSTANCE_ERROR', listener);\n }\n\n /**\n * Registers a listener for completed associations (file moves done).\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationComplete(listener: (data: ReceiverAssociationData) => void): this {\n return this.on('ASSOCIATION_COMPLETE', listener);\n }\n\n /**\n * Registers a listener for fully finalized associations (all parsing done).\n *\n * @param listener - Callback receiving finalized data with instance counts\n * @returns this for chaining\n */\n onAssociationFinalized(listener: (data: ReceiverAssociationFinalizedData) => void): this {\n return this.on('ASSOCIATION_FINALIZED', listener);\n }\n\n /**\n * Registers a listener for new associations (bubbled from workers).\n *\n * @param listener - Callback receiving association received data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (data: PoolAssociationReceivedData) => void): this {\n return this.on('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Registers a listener for C-STORE requests (bubbled from workers).\n *\n * @param listener - Callback receiving C-STORE request data\n * @returns this for chaining\n */\n onCStoreRequest(listener: (data: PoolCStoreRequestData) => void): this {\n return this.on('C_STORE_REQUEST', listener);\n }\n\n /**\n * Registers a listener for C-ECHO requests (bubbled from workers).\n *\n * @param listener - Callback receiving echo request data\n * @returns this for chaining\n */\n onEchoRequest(listener: (data: PoolEchoRequestData) => void): this {\n return this.on('ECHO_REQUEST', listener);\n }\n\n /**\n * Registers a listener for refused associations (bubbled from workers).\n *\n * @param listener - Callback receiving refusing association data\n * @returns this for chaining\n */\n onRefusingAssociation(listener: (data: PoolRefusingAssociationData) => void): this {\n return this.on('REFUSING_ASSOCIATION', listener);\n }\n\n /**\n * Routes an external socket to an idle worker.\n *\n * The pool must be started via `start()` before calling this method.\n * Use this when managing your own TCP listener (e.g., protocol router).\n *\n * @param socket - An incoming net.Socket to route to a worker\n */\n handleSocket(socket: net.Socket): void {\n if (!this.started) {\n socket.destroy(new Error('DicomReceiver: not started'));\n return;\n }\n void this.handleConnection(socket);\n }\n\n /** Current pool status. */\n get poolStatus(): PoolStatus {\n let idle = 0;\n let busy = 0;\n for (const w of this.workers.values()) {\n if (w.state === 'idle') idle++;\n else busy++;\n }\n return { idle, busy, total: this.workers.size };\n }\n\n // -----------------------------------------------------------------------\n // TCP proxy\n // -----------------------------------------------------------------------\n\n /** Starts the TCP proxy on the configured port. Skips if port is 0. */\n private startTcpProxy(): Promise<Result<void>> {\n if (this.options.port === 0) {\n return Promise.resolve(ok(undefined));\n }\n return new Promise(resolve => {\n this.tcpServer = net.createServer(socket => {\n void this.handleConnection(socket);\n });\n this.tcpServer.on('error', e => {\n if (!this.started) {\n resolve(err(new Error(`DicomReceiver: TCP proxy failed: ${e.message}`)));\n } else {\n this.emit('error', { error: e instanceof Error ? e : new Error(String(e)) });\n }\n });\n this.tcpServer.listen(this.options.port, () => {\n resolve(ok(undefined));\n });\n });\n }\n\n /** Closes the TCP proxy server. */\n private closeTcpProxy(): Promise<void> {\n return new Promise(resolve => {\n if (this.tcpServer === undefined) {\n resolve();\n return;\n }\n this.tcpServer.close(() => resolve());\n });\n }\n\n /** Drains in-flight file and instance work on all non-idle workers, with a 5s safety timeout. */\n private async drainAllWorkers(): Promise<void> {\n const drainPromises: Promise<void>[] = [];\n for (const worker of this.workers.values()) {\n if (worker.state !== 'idle') {\n drainPromises.push(worker.drainPendingFiles());\n drainPromises.push(worker.drainInstancePending());\n }\n }\n if (drainPromises.length === 0) return;\n await Promise.race([Promise.all(drainPromises), delay(5000)]);\n }\n\n // -----------------------------------------------------------------------\n // Connection routing\n // -----------------------------------------------------------------------\n\n /** Routes an incoming connection to an idle worker. */\n private async handleConnection(remoteSocket: net.Socket): Promise<void> {\n remoteSocket.pause();\n\n const worker = await this.findIdleWorker();\n if (worker === undefined) {\n remoteSocket.destroy(new Error('DicomReceiver: no idle worker available'));\n this.emit('error', { error: new Error('DicomReceiver: connection rejected — pool exhausted') });\n return;\n }\n\n this.associationCounter++;\n const associationId = `assoc-${String(this.associationCounter)}`;\n const associationDir = path.join(this.options.storageDir, associationId);\n\n const mkdirResult = await ensureDirectory(associationDir);\n if (!mkdirResult.ok) {\n remoteSocket.destroy();\n this.emit('error', { error: mkdirResult.error });\n return;\n }\n\n const ctx: AssociationContext = {\n associationId,\n associationDir,\n startAt: Date.now(),\n };\n\n worker.beginAssociation(ctx);\n this.pipeConnection(worker, remoteSocket);\n void this.replenishPool().catch((e: unknown) => {\n this.emit('error', { error: e instanceof Error ? e : new Error(String(e)) });\n });\n }\n\n /** Finds an idle worker, retrying up to connectionTimeoutMs. */\n private async findIdleWorker(): Promise<Worker | undefined> {\n const idle = this.getIdleWorker();\n if (idle !== undefined) return idle;\n\n const maxRetries = Math.min(Math.ceil(this.connectionTimeoutMs / CONNECTION_RETRY_INTERVAL_MS), MAX_CONNECTION_RETRIES);\n\n for (let i = 0; i < maxRetries; i++) {\n await delay(CONNECTION_RETRY_INTERVAL_MS);\n const found = this.getIdleWorker();\n if (found !== undefined) return found;\n if (this.stopping) return undefined;\n }\n return undefined;\n }\n\n /** Returns the first idle worker, or undefined. */\n private getIdleWorker(): Worker | undefined {\n for (const w of this.workers.values()) {\n if (w.state === 'idle') return w;\n }\n return undefined;\n }\n\n /** Pipes remote socket bidirectionally to the worker's port. */\n private pipeConnection(worker: Worker, remoteSocket: net.Socket): void {\n const workerSocket = net.createConnection({ port: worker.port, host: '127.0.0.1' });\n\n worker.setSockets(remoteSocket, workerSocket);\n\n const cleanup = (): void => {\n remoteSocket.unpipe(workerSocket);\n workerSocket.unpipe(remoteSocket);\n if (!remoteSocket.destroyed) remoteSocket.destroy();\n if (!workerSocket.destroyed) workerSocket.destroy();\n };\n\n // Wait for the worker connection to be established before piping.\n // Writing to a socket before 'connect' buffers data in userland;\n // on Windows and some container runtimes this buffered data is\n // silently lost, causing the DICOM association handshake to hang.\n workerSocket.on('connect', () => {\n remoteSocket.pipe(workerSocket);\n workerSocket.pipe(remoteSocket);\n remoteSocket.resume();\n });\n\n remoteSocket.on('error', cleanup);\n workerSocket.on('error', cleanup);\n remoteSocket.on('close', cleanup);\n workerSocket.on('close', cleanup);\n }\n\n // -----------------------------------------------------------------------\n // Worker pool management\n // -----------------------------------------------------------------------\n\n /** Spawns `count` new workers and adds them to the pool. */\n private async spawnWorkers(count: number): Promise<Result<void>> {\n const promises: Promise<Result<Worker>>[] = [];\n for (let i = 0; i < count; i++) {\n promises.push(this.spawnWorker());\n }\n const results = await Promise.all(promises);\n for (const result of results) {\n if (!result.ok) return err(result.error);\n }\n return ok(undefined);\n }\n\n /** Creates a Dcmrecv instance with the pool's shared options. */\n private createDcmrecv(port: number, tempDir: string): Result<Dcmrecv> {\n return Dcmrecv.create({\n port,\n aeTitle: this.options.aeTitle,\n outputDirectory: tempDir,\n configFile: this.options.configFile,\n configProfile: this.options.configProfile,\n acseTimeout: this.options.acseTimeout,\n dimseTimeout: this.options.dimseTimeout,\n maxPdu: this.options.maxPdu,\n filenameMode: this.options.filenameMode ?? 'unique',\n filenameExtension: this.options.filenameExtension,\n storageMode: this.options.storageMode,\n });\n }\n\n /** Spawns a single Dcmrecv worker with an ephemeral port. */\n private async spawnWorker(): Promise<Result<Worker>> {\n const portResult = await allocatePort();\n if (!portResult.ok) return portResult;\n const port = portResult.value;\n\n const tempDir = path.join(os.tmpdir(), `dcmrecv-pool-${String(port)}-${String(Date.now())}`);\n const mkdirResult = await ensureDirectory(tempDir);\n if (!mkdirResult.ok) return mkdirResult;\n\n const createResult = this.createDcmrecv(port, tempDir);\n if (!createResult.ok) return createResult;\n\n const dcmrecv = createResult.value;\n const worker = new Worker(dcmrecv, port, tempDir);\n\n this.wireWorkerEvents(worker);\n const startResult = await dcmrecv.start();\n if (!startResult.ok) {\n return err(new Error(`DicomReceiver: worker start failed on port ${String(port)}: ${startResult.error.message}`));\n }\n\n this.workers.set(port, worker);\n return ok(worker);\n }\n\n /** Stops a single worker: destroy sockets, stop process, clean temp dir, remove from pool. */\n private async stopWorker(worker: Worker): Promise<void> {\n worker.destroySockets();\n await worker.dcmrecv.stop();\n worker.dcmrecv[Symbol.dispose]();\n await removeDirSafe(worker.tempDir);\n this.workers.delete(worker.port);\n }\n\n /** Pre-emptively spawns workers to keep idle count >= minPoolSize. */\n private async replenishPool(): Promise<void> {\n const status = this.poolStatus;\n const needed = this.minPoolSize - status.idle;\n const capacity = this.maxPoolSize - status.total;\n const toSpawn = Math.min(needed, capacity);\n\n if (toSpawn <= 0) return;\n\n const promises: Promise<Result<Worker>>[] = [];\n for (let i = 0; i < toSpawn; i++) {\n promises.push(this.spawnWorker());\n }\n const results = await Promise.all(promises);\n for (const result of results) {\n if (!result.ok) {\n this.emit('error', { error: result.error });\n }\n }\n }\n\n /** Stops excess idle workers when idle count > minPoolSize + 2. */\n private async scaleDown(): Promise<void> {\n const idleWorkers: Worker[] = [];\n for (const w of this.workers.values()) {\n if (w.state === 'idle') idleWorkers.push(w);\n }\n const excess = idleWorkers.length - (this.minPoolSize + 2);\n if (excess <= 0) return;\n\n const toStop = idleWorkers.slice(0, excess);\n const promises: Promise<void>[] = [];\n for (const w of toStop) {\n promises.push(this.stopWorker(w));\n }\n await Promise.all(promises);\n }\n\n // -----------------------------------------------------------------------\n // Worker event wiring\n // -----------------------------------------------------------------------\n\n /** Wires all events on a worker: file handling, association lifecycle, output capture. */\n private wireWorkerEvents(worker: Worker): void {\n this.wireFileReceived(worker);\n this.wireAssociationComplete(worker);\n this.wireAssociationReceived(worker);\n this.wireCStoreRequest(worker);\n this.wireEchoRequest(worker);\n this.wireRefusingAssociation(worker);\n this.wireOutputCapture(worker);\n }\n\n /** Wires FILE_RECEIVED from dcmrecv worker — captures context synchronously. */\n private wireFileReceived(worker: Worker): void {\n worker.dcmrecv.onFileReceived(data => {\n const ctx = worker.context;\n if (ctx === undefined) {\n this.emit('error', {\n error: new Error(`DicomReceiver: FILE_RECEIVED with no active association (worker state: ${worker.state})`),\n filePath: data.filePath,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n });\n return;\n }\n\n // FILE_RECEIVED: raw notification from dcmrecv, before any processing\n this.emit('FILE_RECEIVED', {\n filePath: data.filePath,\n associationId: ctx.associationId,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n });\n\n const promise = this.handleFileReceived(worker, data, ctx);\n worker.trackFile(promise);\n });\n }\n\n /** Moves file to association dir, emits FILE_STORED, then parses instance. */\n private async handleFileReceived(\n worker: Worker,\n data: { filePath: string; callingAE: string; calledAE: string; source: string },\n ctx: AssociationContext\n ): Promise<void> {\n try {\n await this.moveAndEmitFile(worker, data, ctx);\n } catch (thrown: unknown) {\n const error = thrown instanceof Error ? thrown : new Error(String(thrown));\n this.emit('error', {\n error,\n filePath: data.filePath,\n associationId: ctx.associationId,\n associationDir: ctx.associationDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n });\n }\n }\n\n /** Inner handler: move file, emit FILE_STORED, parse DICOM, emit INSTANCE_RECEIVED. */\n private async moveAndEmitFile(\n worker: Worker,\n data: { filePath: string; callingAE: string; calledAE: string; source: string },\n ctx: AssociationContext\n ): Promise<void> {\n const srcPath = data.filePath;\n const destPath = path.join(ctx.associationDir, path.basename(srcPath));\n\n const moveResult = await moveFile(srcPath, destPath);\n const finalPath = moveResult.ok ? destPath : srcPath;\n const fileSize = await statFileSafe(finalPath);\n worker.recordFile(finalPath, fileSize);\n\n // FILE_STORED: file is safely on disk in the association directory\n this.emit('FILE_STORED', {\n filePath: finalPath,\n fileSize,\n associationId: ctx.associationId,\n associationDir: ctx.associationDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n });\n\n if (this.parseInstances) {\n const instanceCtx = {\n filePath: finalPath,\n fileSize,\n associationId: ctx.associationId,\n associationDir: ctx.associationDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n };\n worker.trackInstance(this.parseAndEmitInstance(worker, instanceCtx));\n }\n }\n\n /** Parses a DICOM file and emits INSTANCE_RECEIVED or INSTANCE_ERROR. */\n private async parseAndEmitInstance(worker: Worker, ctx: ReceiverFileStoredData): Promise<void> {\n try {\n const openResult = await DicomInstance.open(ctx.filePath, this.resolvedInstanceOpenOptions);\n if (!openResult.ok) {\n worker.recordInstanceError();\n this.emit('INSTANCE_ERROR', { error: openResult.error, thrown: false, ...ctx });\n return;\n }\n worker.recordInstanceSuccess();\n this.emit('INSTANCE_RECEIVED', { ...ctx, instance: openResult.value });\n } catch (thrown: unknown) {\n const error = thrown instanceof Error ? thrown : new Error(String(thrown));\n worker.recordInstanceError();\n this.emit('INSTANCE_ERROR', { error, thrown: true, ...ctx });\n }\n }\n\n /** Returns worker to idle pool on association complete, emits summary. */\n private wireAssociationComplete(worker: Worker): void {\n worker.dcmrecv.onAssociationComplete((data: AssociationCompleteData) => {\n // Mark worker as finalizing SYNCHRONOUSLY — prevents findIdleWorker\n // from routing new connections to this worker during drain. (#25)\n worker.markFinalizing();\n\n // Defer the actual drain to the check phase (after I/O callbacks) so\n // any remaining FILE_RECEIVED events in pending pipe chunks are processed\n // before ASSOCIATION_FINALIZED fires. (#25)\n setImmediate(() => {\n void this.finalizeAssociation(worker, data);\n });\n });\n }\n\n /** Awaits file ops, emits ASSOCIATION_COMPLETE, awaits parsing, emits ASSOCIATION_FINALIZED. */\n private async finalizeAssociation(worker: Worker, data: AssociationCompleteData): Promise<void> {\n await worker.drainPendingFiles();\n this.emitAssociationComplete(worker, data);\n\n await worker.drainInstancePending();\n this.emitAssociationFinalized(worker, data);\n\n worker.endAssociation();\n void this.scaleDown();\n }\n\n /** Emits the ASSOCIATION_COMPLETE event with transfer stats. */\n private emitAssociationComplete(worker: Worker, data: AssociationCompleteData): void {\n const ctx = worker.context;\n const assocId = ctx?.associationId ?? data.associationId;\n const assocDir = ctx?.associationDir ?? '';\n const startAt = ctx?.startAt ?? Date.now();\n const files = [...worker.files];\n const output = [...worker.outputLines];\n\n const endAt = Date.now();\n const totalBytes = sumArray(worker.fileSizes);\n const elapsedMs = endAt - startAt;\n const bytesPerSecond = elapsedMs > 0 ? Math.round((totalBytes / elapsedMs) * 1000) : 0;\n\n this.emit('ASSOCIATION_COMPLETE', {\n associationId: assocId,\n associationDir: assocDir,\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n files,\n durationMs: data.durationMs,\n endReason: data.endReason,\n totalBytes,\n bytesPerSecond,\n startAt,\n endAt,\n output,\n });\n }\n\n /** Emits ASSOCIATION_FINALIZED after all instance parsing is done. */\n private emitAssociationFinalized(worker: Worker, data: AssociationCompleteData): void {\n const ctx = worker.context;\n this.emit('ASSOCIATION_FINALIZED', {\n associationId: ctx?.associationId ?? data.associationId,\n associationDir: ctx?.associationDir ?? '',\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n files: [...worker.files],\n instancesReceived: worker.instancesReceived,\n instanceErrors: worker.instanceErrors,\n });\n }\n\n /** Bubbles ASSOCIATION_RECEIVED from dcmrecv worker. */\n private wireAssociationReceived(worker: Worker): void {\n worker.dcmrecv.onEvent('ASSOCIATION_RECEIVED', (data: { callingAE: string; calledAE: string; source: string }) => {\n this.emit('ASSOCIATION_RECEIVED', {\n associationId: worker.context?.associationId ?? '',\n callingAE: data.callingAE,\n calledAE: data.calledAE,\n source: data.source,\n });\n });\n }\n\n /** Bubbles C_STORE_REQUEST from dcmrecv worker. */\n private wireCStoreRequest(worker: Worker): void {\n worker.dcmrecv.onEvent('C_STORE_REQUEST', (data: { raw: string }) => {\n this.emit('C_STORE_REQUEST', {\n associationId: worker.context?.associationId ?? '',\n raw: data.raw,\n });\n });\n }\n\n /** Bubbles ECHO_REQUEST from dcmrecv worker. */\n private wireEchoRequest(worker: Worker): void {\n worker.dcmrecv.onEvent('ECHO_REQUEST', () => {\n this.emit('ECHO_REQUEST', {\n associationId: worker.context?.associationId ?? '',\n });\n });\n }\n\n /** Bubbles REFUSING_ASSOCIATION from dcmrecv worker. */\n private wireRefusingAssociation(worker: Worker): void {\n worker.dcmrecv.onEvent('REFUSING_ASSOCIATION', (data: { reason: string }) => {\n this.emit('REFUSING_ASSOCIATION', {\n reason: data.reason,\n });\n });\n }\n\n /** Captures worker output lines during busy associations. */\n private wireOutputCapture(worker: Worker): void {\n worker.dcmrecv.on('line', ({ text }: { text: string }) => {\n if (worker.state === 'busy') {\n worker.captureOutput(text);\n }\n });\n }\n\n // -----------------------------------------------------------------------\n // Abort signal\n // -----------------------------------------------------------------------\n\n /** Wires an AbortSignal to stop the receiver. */\n private wireAbortSignal(signal: AbortSignal): void {\n /* v8 ignore next 4 */\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\n/** @deprecated Use ReceiverFileStoredData instead. */\ntype ReceiverFileData = ReceiverFileStoredData;\n\nexport { DicomReceiver };\nexport type {\n DicomReceiverOptions,\n DicomReceiverEventMap,\n ReceiverFileReceivedData,\n ReceiverFileStoredData,\n ReceiverInstanceData,\n ReceiverInstanceErrorData,\n ReceiverAssociationFinalizedData,\n ReceiverFileData,\n ReceiverAssociationData,\n ReceiverErrorData,\n PoolStatus,\n PoolAssociationReceivedData,\n PoolCStoreRequestData,\n PoolEchoRequestData,\n PoolRefusingAssociationData,\n};\n","/**\n * Event patterns and types for dcmprscp output parsing.\n *\n * Defines regex patterns that match DCMTK dcmprscp (print management SCP)\n * verbose output, along with typed event data interfaces for each event.\n *\n * @module events/dcmprscp\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmprscp process output. */\nconst DcmprscpEvent = {\n DATABASE_READY: 'DATABASE_READY',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n CONFIG_ERROR: 'CONFIG_ERROR',\n} as const;\n\ntype DcmprscpEventValue = (typeof DcmprscpEvent)[keyof typeof DcmprscpEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for DATABASE_READY event. */\ninterface DatabaseReadyData {\n readonly directory: string;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface PrintAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface PrintAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface PrintCannotStartListenerData {\n readonly message: string;\n}\n\n/** Data for CONFIG_ERROR event. */\ninterface ConfigErrorData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmprscp verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmprscp verbose output. */\nconst DCMPRSCP_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmprscpEvent.DATABASE_READY,\n pattern: /Using database in directory\\s+'([^']+)'/,\n processor: (match): DatabaseReadyData => ({\n directory: match[1] ?? '',\n }),\n },\n {\n event: DcmprscpEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{0,20}\\(([^)]+)\\)/,\n processor: (match): PrintAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmprscpEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): PrintAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmprscpEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmprscpEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmprscpEvent.CANNOT_START_LISTENER,\n pattern: /cannot initialise network|cannot listen/i,\n processor: (match): PrintCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmprscpEvent.CONFIG_ERROR,\n pattern: /can't open configuration file|no (?:default )?print scp/i,\n processor: (match): ConfigErrorData => ({\n message: match[0] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMPRSCP_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmprscpEvent.CANNOT_START_LISTENER, DcmprscpEvent.CONFIG_ERROR]);\n\nexport { DcmprscpEvent, DCMPRSCP_PATTERNS, DCMPRSCP_FATAL_EVENTS };\nexport type {\n DcmprscpEventValue,\n DatabaseReadyData,\n PrintAssociationReceivedData,\n PrintAssociationAcknowledgedData,\n PrintCannotStartListenerData,\n ConfigErrorData,\n};\n","/**\n * DICOM Print Management SCP server wrapping the dcmprscp binary.\n *\n * Provides a type-safe, event-driven API for the Basic Grayscale Print\n * Management SCP. Uses a static factory pattern because binary resolution\n * and validation must happen before the constructor call.\n *\n * @module servers/DcmprsCP\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { DCMPRSCP_PATTERNS, DCMPRSCP_FATAL_EVENTS } from '../events/dcmprscp';\nimport type {\n DatabaseReadyData,\n PrintAssociationReceivedData,\n PrintAssociationAcknowledgedData,\n PrintCannotStartListenerData,\n ConfigErrorData,\n} from '../events/dcmprscp';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the DcmprsCP server. */\ninterface DcmprsCPEventMap {\n DATABASE_READY: [DatabaseReadyData];\n ASSOCIATION_RECEIVED: [PrintAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [PrintAssociationAcknowledgedData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n CANNOT_START_LISTENER: [PrintCannotStartListenerData];\n CONFIG_ERROR: [ConfigErrorData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a DcmprsCP server instance. */\ninterface DcmprsCPOptions {\n /** Path to the dcmpstat configuration file (required). */\n readonly configFile: string;\n /** Printer identifier from the config file (optional, defaults to first printer). */\n readonly printer?: string | undefined;\n /** Enable DIMSE message dumping. */\n readonly dump?: boolean | undefined;\n /** Log level override. */\n readonly logLevel?: 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace' | undefined;\n /** Path to a log configuration file. */\n readonly logConfig?: string | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmprsCPOptionsSchema = z\n .object({\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }),\n printer: z.string().min(1).optional(),\n dump: z.boolean().optional(),\n logLevel: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).optional(),\n logConfig: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in logConfig' }).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmprsCPOptions): string[] {\n const args: string[] = ['--verbose', '--config', options.configFile];\n\n if (options.printer !== undefined) {\n args.push('--printer', options.printer);\n }\n if (options.dump === true) {\n args.push('--dump');\n }\n if (options.logLevel !== undefined) {\n args.push('--log-level', options.logLevel);\n }\n if (options.logConfig !== undefined) {\n args.push('--log-config', options.logConfig);\n }\n\n return args;\n}\n\n// ---------------------------------------------------------------------------\n// DcmprsCP class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Print Management SCP server wrapping the dcmprscp binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Note: dcmprscp does not print a \"listening\" message. The `start()` method\n * resolves either when the DATABASE_READY event is detected or on spawn.\n *\n * @example\n * ```ts\n * const result = DcmprsCP.create({ configFile: '/etc/dcmpstat.cfg' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('DATABASE_READY', (data) => console.log('DB:', data.directory));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass DcmprsCP extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /**\n * Registers a typed listener for a dcmprscp-specific event.\n *\n * @param event - The event name from DcmprsCPEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n onEvent<K extends keyof DcmprsCPEventMap>(event: K, listener: (...args: DcmprsCPEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for when the database is ready.\n *\n * @param listener - Callback receiving database ready data\n * @returns this for chaining\n */\n onDatabaseReady(listener: (...args: DcmprsCPEventMap['DATABASE_READY']) => void): this {\n return this.onEvent('DATABASE_READY', listener);\n }\n\n /**\n * Registers a listener for incoming associations.\n *\n * @param listener - Callback receiving association data\n * @returns this for chaining\n */\n onAssociationReceived(listener: (...args: DcmprsCPEventMap['ASSOCIATION_RECEIVED']) => void): this {\n return this.onEvent('ASSOCIATION_RECEIVED', listener);\n }\n\n /**\n * Creates a new DcmprsCP server instance.\n *\n * @param options - Configuration options for the dcmprscp server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmprsCPOptions): Result<DcmprsCP> {\n const validation = DcmprsCPOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmprscp', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmprscp');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMPRSCP_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n isStartedPredicate: line => /Using database in directory/i.test(line),\n };\n\n return ok(new DcmprsCP(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMPRSCP_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { DcmprsCP };\nexport type { DcmprsCPOptions, DcmprsCPEventMap };\n","/**\n * Event patterns and types for dcmpsrcv output parsing.\n *\n * Defines regex patterns that match DCMTK dcmpsrcv (viewer network receiver)\n * verbose output. Shares several patterns with dcmrecv/storescp since\n * dcmpsrcv handles incoming DICOM associations and C-STORE operations.\n *\n * @module events/dcmpsrcv\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmpsrcv process output. */\nconst DcmpsrcvEvent = {\n LISTENING: 'LISTENING',\n DATABASE_READY: 'DATABASE_READY',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n ECHO_REQUEST: 'ECHO_REQUEST',\n C_STORE_REQUEST: 'C_STORE_REQUEST',\n FILE_DELETED: 'FILE_DELETED',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n CONFIG_ERROR: 'CONFIG_ERROR',\n TERMINATING: 'TERMINATING',\n} as const;\n\ntype DcmpsrcvEventValue = (typeof DcmpsrcvEvent)[keyof typeof DcmpsrcvEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for LISTENING event. */\ninterface ReceiverListeningData {\n readonly receiverId: string;\n readonly port: number;\n}\n\n/** Data for DATABASE_READY event. */\ninterface ReceiverDatabaseReadyData {\n readonly directory: string;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface ReceiverAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface ReceiverAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for ECHO_REQUEST event. */\ninterface ReceiverEchoRequestData {\n readonly messageId: number;\n}\n\n/** Data for C_STORE_REQUEST event. */\ninterface ReceiverCStoreRequestData {\n readonly raw: string;\n}\n\n/** Data for FILE_DELETED event. */\ninterface FileDeletedData {\n readonly filePath: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface ReceiverCannotStartListenerData {\n readonly message: string;\n}\n\n/** Data for CONFIG_ERROR event. */\ninterface ReceiverConfigErrorData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmpsrcv verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmpsrcv verbose output. */\nconst DCMPSRCV_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmpsrcvEvent.LISTENING,\n pattern: /Receiver\\s{1,20}(\\S+)\\s{1,20}on port\\s{1,20}(\\d+)/,\n processor: (match): ReceiverListeningData => ({\n receiverId: match[1] ?? '',\n port: Number(match[2]),\n }),\n },\n {\n event: DcmpsrcvEvent.DATABASE_READY,\n pattern: /Using database in directory\\s+'([^']+)'/,\n processor: (match): ReceiverDatabaseReadyData => ({\n directory: match[1] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s*\\(([^)]+)\\)/,\n processor: (match): ReceiverAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): ReceiverAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmpsrcvEvent.ECHO_REQUEST,\n pattern: /Received Echo SCP RQ:\\s*MsgID\\s+(\\d+)/,\n processor: (match): ReceiverEchoRequestData => ({\n messageId: Number(match[1]),\n }),\n },\n {\n event: DcmpsrcvEvent.C_STORE_REQUEST,\n pattern: /Received Store SCP/i,\n processor: (match): ReceiverCStoreRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.FILE_DELETED,\n pattern: /Deleting Image File:\\s{0,20}(.{1,1024})/,\n processor: (match): FileDeletedData => ({\n filePath: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmpsrcvEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmpsrcvEvent.CANNOT_START_LISTENER,\n pattern: /cannot listen on port/i,\n processor: (match): ReceiverCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.CONFIG_ERROR,\n pattern: /can't open configuration file|missing configuration file|no application entity title|no or invalid port number/i,\n processor: (match): ReceiverConfigErrorData => ({\n message: match[0] ?? '',\n }),\n },\n {\n event: DcmpsrcvEvent.TERMINATING,\n pattern: /Terminating all receivers/i,\n processor: () => undefined,\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMPSRCV_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmpsrcvEvent.CANNOT_START_LISTENER, DcmpsrcvEvent.CONFIG_ERROR]);\n\nexport { DcmpsrcvEvent, DCMPSRCV_PATTERNS, DCMPSRCV_FATAL_EVENTS };\nexport type {\n DcmpsrcvEventValue,\n ReceiverListeningData,\n ReceiverDatabaseReadyData,\n ReceiverAssociationReceivedData,\n ReceiverAssociationAcknowledgedData,\n ReceiverEchoRequestData,\n ReceiverCStoreRequestData,\n FileDeletedData,\n ReceiverCannotStartListenerData,\n ReceiverConfigErrorData,\n};\n","/**\n * DICOM Viewer Network Receiver wrapping the dcmpsrcv binary.\n *\n * Provides a type-safe, event-driven API for the DICOMscope network\n * receiver component. Accepts incoming DICOM associations for storage\n * and C-ECHO verification.\n *\n * @module servers/Dcmpsrcv\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { DCMPSRCV_PATTERNS, DCMPSRCV_FATAL_EVENTS } from '../events/dcmpsrcv';\nimport type {\n ReceiverListeningData,\n ReceiverDatabaseReadyData,\n ReceiverAssociationReceivedData,\n ReceiverAssociationAcknowledgedData,\n ReceiverEchoRequestData,\n ReceiverCStoreRequestData,\n FileDeletedData,\n ReceiverCannotStartListenerData,\n ReceiverConfigErrorData,\n} from '../events/dcmpsrcv';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the Dcmpsrcv server. */\ninterface DcmpsrcvEventMap {\n LISTENING: [ReceiverListeningData];\n DATABASE_READY: [ReceiverDatabaseReadyData];\n ASSOCIATION_RECEIVED: [ReceiverAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [ReceiverAssociationAcknowledgedData];\n ECHO_REQUEST: [ReceiverEchoRequestData];\n C_STORE_REQUEST: [ReceiverCStoreRequestData];\n FILE_DELETED: [FileDeletedData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n CANNOT_START_LISTENER: [ReceiverCannotStartListenerData];\n CONFIG_ERROR: [ReceiverConfigErrorData];\n TERMINATING: [];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a Dcmpsrcv server instance. */\ninterface DcmpsrcvOptions {\n /** Path to the dcmpstat configuration file (required). */\n readonly configFile: string;\n /** Receiver identifier from the config file (optional, defaults to first receiver). */\n readonly receiverId?: string | undefined;\n /** Log level override. */\n readonly logLevel?: 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace' | undefined;\n /** Path to a log configuration file. */\n readonly logConfig?: string | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmpsrcvOptionsSchema = z\n .object({\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }),\n receiverId: z.string().min(1).optional(),\n logLevel: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).optional(),\n logConfig: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in logConfig' }).optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmpsrcvOptions): string[] {\n const args: string[] = ['--verbose'];\n\n if (options.logLevel !== undefined) {\n args.push('--log-level', options.logLevel);\n }\n if (options.logConfig !== undefined) {\n args.push('--log-config', options.logConfig);\n }\n\n args.push(options.configFile);\n\n if (options.receiverId !== undefined) {\n args.push(options.receiverId);\n }\n\n return args;\n}\n\n// ---------------------------------------------------------------------------\n// Dcmpsrcv class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Viewer Network Receiver wrapping the dcmpsrcv binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * The `start()` method resolves when the LISTENING event is detected\n * (i.e., \"Receiver <id> on port <port>\").\n *\n * @example\n * ```ts\n * const result = Dcmpsrcv.create({ configFile: '/etc/dcmpstat.cfg', receiverId: 'RECEIVE_1' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('LISTENING', (data) => console.log(`Listening on port ${data.port}`));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass Dcmpsrcv extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /**\n * Registers a typed listener for a dcmpsrcv-specific event.\n *\n * @param event - The event name from DcmpsrcvEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n onEvent<K extends keyof DcmpsrcvEventMap>(event: K, listener: (...args: DcmpsrcvEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for when the receiver starts listening.\n *\n * @param listener - Callback receiving listening data (receiver ID and port)\n * @returns this for chaining\n */\n onListening(listener: (...args: DcmpsrcvEventMap['LISTENING']) => void): this {\n return this.onEvent('LISTENING', listener);\n }\n\n /**\n * Registers a listener for incoming C-STORE requests.\n *\n * @param listener - Callback receiving C-STORE request data\n * @returns this for chaining\n */\n onCStoreRequest(listener: (...args: DcmpsrcvEventMap['C_STORE_REQUEST']) => void): this {\n return this.onEvent('C_STORE_REQUEST', listener);\n }\n\n /**\n * Creates a new Dcmpsrcv server instance.\n *\n * @param options - Configuration options for the dcmpsrcv server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmpsrcvOptions): Result<Dcmpsrcv> {\n const validation = DcmpsrcvOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmpsrcv', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmpsrcv');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMPSRCV_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n isStartedPredicate: line => /Receiver\\s+\\S+\\s+on port/i.test(line),\n };\n\n return ok(new Dcmpsrcv(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMPSRCV_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { Dcmpsrcv };\nexport type { DcmpsrcvOptions, DcmpsrcvEventMap };\n","/**\n * Event patterns and types for dcmqrscp output parsing.\n *\n * Defines regex patterns that match DCMTK dcmqrscp (Query/Retrieve SCP)\n * verbose output, along with typed event data interfaces for each event.\n *\n * @module events/dcmqrscp\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by dcmqrscp process output. */\nconst DcmqrscpEvent = {\n LISTENING: 'LISTENING',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n C_FIND_REQUEST: 'C_FIND_REQUEST',\n C_MOVE_REQUEST: 'C_MOVE_REQUEST',\n C_GET_REQUEST: 'C_GET_REQUEST',\n C_STORE_REQUEST: 'C_STORE_REQUEST',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n} as const;\n\ntype DcmqrscpEventValue = (typeof DcmqrscpEvent)[keyof typeof DcmqrscpEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for LISTENING event. */\ninterface QRListeningData {\n readonly port: number;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface QRAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface QRAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for C_FIND_REQUEST event. */\ninterface QRCFindRequestData {\n readonly raw: string;\n}\n\n/** Data for C_MOVE_REQUEST event. */\ninterface QRCMoveRequestData {\n readonly raw: string;\n}\n\n/** Data for C_GET_REQUEST event. */\ninterface QRCGetRequestData {\n readonly raw: string;\n}\n\n/** Data for C_STORE_REQUEST event. */\ninterface QRCStoreRequestData {\n readonly raw: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface QRCannotStartListenerData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for dcmqrscp verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing dcmqrscp verbose output. */\nconst DCMQRSCP_PATTERNS: readonly EventPattern[] = [\n {\n event: DcmqrscpEvent.LISTENING,\n pattern: /listening on port\\s{1,20}(\\d+)/i,\n processor: (match): QRListeningData => ({\n port: Number(match[1]),\n }),\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{0,20}([^\\r\\n]+)/,\n processor: (match): QRAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): QRAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: DcmqrscpEvent.C_FIND_REQUEST,\n pattern: /Received Find (?:SCP )?Request/i,\n processor: (match): QRCFindRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.C_MOVE_REQUEST,\n pattern: /Received Move (?:SCP )?Request/i,\n processor: (match): QRCMoveRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.C_GET_REQUEST,\n pattern: /Received Get (?:SCP )?Request/i,\n processor: (match): QRCGetRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.C_STORE_REQUEST,\n pattern: /Received Store (?:SCP )?Request/i,\n processor: (match): QRCStoreRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: DcmqrscpEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: DcmqrscpEvent.CANNOT_START_LISTENER,\n pattern: /cannot listen|cannot initialise network/i,\n processor: (match): QRCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst DCMQRSCP_FATAL_EVENTS: ReadonlySet<string> = new Set([DcmqrscpEvent.CANNOT_START_LISTENER]);\n\nexport { DcmqrscpEvent, DCMQRSCP_PATTERNS, DCMQRSCP_FATAL_EVENTS };\nexport type {\n DcmqrscpEventValue,\n QRListeningData,\n QRAssociationReceivedData,\n QRAssociationAcknowledgedData,\n QRCFindRequestData,\n QRCMoveRequestData,\n QRCGetRequestData,\n QRCStoreRequestData,\n QRCannotStartListenerData,\n};\n","/**\n * DICOM Query/Retrieve SCP server wrapping the dcmqrscp binary.\n *\n * Provides a type-safe, event-driven API for the Q/R SCP that supports\n * C-FIND, C-MOVE, C-GET, and C-STORE operations. Uses a static factory\n * pattern because binary resolution and validation must happen before\n * the constructor call.\n *\n * @module servers/DcmQRSCP\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { DCMQRSCP_PATTERNS, DCMQRSCP_FATAL_EVENTS } from '../events/dcmqrscp';\nimport type {\n QRListeningData,\n QRAssociationReceivedData,\n QRAssociationAcknowledgedData,\n QRCFindRequestData,\n QRCMoveRequestData,\n QRCGetRequestData,\n QRCStoreRequestData,\n QRCannotStartListenerData,\n} from '../events/dcmqrscp';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the DcmQRSCP server. */\ninterface DcmQRSCPEventMap {\n LISTENING: [QRListeningData];\n ASSOCIATION_RECEIVED: [QRAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [QRAssociationAcknowledgedData];\n C_FIND_REQUEST: [QRCFindRequestData];\n C_MOVE_REQUEST: [QRCMoveRequestData];\n C_GET_REQUEST: [QRCGetRequestData];\n C_STORE_REQUEST: [QRCStoreRequestData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n CANNOT_START_LISTENER: [QRCannotStartListenerData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a DcmQRSCP server instance. */\ninterface DcmQRSCPOptions {\n /** Path to the dcmqrscp configuration file (required). */\n readonly configFile: string;\n /** Override port from config (positional arg). */\n readonly port?: number | undefined;\n /** Single-process mode (-s flag, recommended on Windows). */\n readonly singleProcess?: boolean | undefined;\n /** Check Find responses (-XF). */\n readonly checkFind?: boolean | undefined;\n /** Check Move responses (-XM). */\n readonly checkMove?: boolean | undefined;\n /** Disable C-GET support (--disable-get). */\n readonly disableGet?: boolean | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Enable verbose mode (default true for event detection). */\n readonly verbose?: boolean | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst DcmQRSCPOptionsSchema = z\n .object({\n configFile: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in configFile' }),\n port: z.number().int().min(1).max(65535).optional(),\n singleProcess: z.boolean().optional(),\n checkFind: z.boolean().optional(),\n checkMove: z.boolean().optional(),\n disableGet: z.boolean().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n verbose: z.boolean().optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: DcmQRSCPOptions): string[] {\n const args: string[] = [];\n\n if (options.verbose !== false) {\n args.push('--verbose');\n }\n\n args.push('--config', options.configFile);\n\n if (options.singleProcess === true) {\n args.push('-s');\n }\n if (options.checkFind === true) {\n args.push('-XF');\n }\n if (options.checkMove === true) {\n args.push('-XM');\n }\n if (options.disableGet === true) {\n args.push('--disable-get');\n }\n\n buildNetworkArgs(args, options);\n\n if (options.port !== undefined) {\n args.push(String(options.port));\n }\n\n return args;\n}\n\n/** Appends network-related CLI flags. */\nfunction buildNetworkArgs(args: string[], options: DcmQRSCPOptions): void {\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n}\n\n// ---------------------------------------------------------------------------\n// DcmQRSCP class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Query/Retrieve SCP server wrapping the dcmqrscp binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * @example\n * ```ts\n * const result = DcmQRSCP.create({ configFile: '/etc/dcmqrscp.cfg', port: 11112 });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('C_FIND_REQUEST', (data) => console.log('Find:', data.raw));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass DcmQRSCP extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n /**\n * Registers a typed listener for a dcmqrscp-specific event.\n *\n * @param event - The event name from DcmQRSCPEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof DcmQRSCPEventMap>(event: K, listener: (...args: DcmQRSCPEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming C-FIND requests.\n *\n * @param listener - Callback receiving C-FIND request data\n * @returns this for chaining\n */\n onCFindRequest(listener: (...args: DcmQRSCPEventMap['C_FIND_REQUEST']) => void): this {\n return this.onEvent('C_FIND_REQUEST', listener);\n }\n\n /**\n * Registers a listener for incoming C-MOVE requests.\n *\n * @param listener - Callback receiving C-MOVE request data\n * @returns this for chaining\n */\n onCMoveRequest(listener: (...args: DcmQRSCPEventMap['C_MOVE_REQUEST']) => void): this {\n return this.onEvent('C_MOVE_REQUEST', listener);\n }\n\n /**\n * Creates a new DcmQRSCP server instance.\n *\n * @param options - Configuration options for the dcmqrscp server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: DcmQRSCPOptions): Result<DcmQRSCP> {\n const validation = DcmQRSCPOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('dcmqrscp', validation.error));\n }\n\n const binaryResult = resolveBinary('dcmqrscp');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of DCMQRSCP_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n // dcmqrscp v3.7.0+ does not print a \"listening on port\" message even\n // in verbose/debug mode, so we resolve on spawn (like StoreSCP) and\n // rely on a short warmup delay in callers that need the socket ready.\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n };\n\n return ok(new DcmQRSCP(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (DCMQRSCP_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { DcmQRSCP };\nexport type { DcmQRSCPOptions, DcmQRSCPEventMap };\n","/**\n * Event patterns and types for wlmscpfs output parsing.\n *\n * Defines regex patterns that match DCMTK wlmscpfs (Worklist Management SCP)\n * verbose output, along with typed event data interfaces for each event.\n *\n * @module events/wlmscpfs\n */\n\nimport type { EventPattern } from '../parsers/EventPattern';\n\n// ---------------------------------------------------------------------------\n// Event constants (as const, not enum — Rule 3.5)\n// ---------------------------------------------------------------------------\n\n/** Events emitted by wlmscpfs process output. */\nconst WlmscpfsEvent = {\n LISTENING: 'LISTENING',\n ASSOCIATION_RECEIVED: 'ASSOCIATION_RECEIVED',\n ASSOCIATION_ACKNOWLEDGED: 'ASSOCIATION_ACKNOWLEDGED',\n C_FIND_REQUEST: 'C_FIND_REQUEST',\n ASSOCIATION_RELEASE: 'ASSOCIATION_RELEASE',\n ASSOCIATION_ABORTED: 'ASSOCIATION_ABORTED',\n ECHO_REQUEST: 'ECHO_REQUEST',\n CANNOT_START_LISTENER: 'CANNOT_START_LISTENER',\n} as const;\n\ntype WlmscpfsEventValue = (typeof WlmscpfsEvent)[keyof typeof WlmscpfsEvent];\n\n// ---------------------------------------------------------------------------\n// Event data interfaces (all readonly)\n// ---------------------------------------------------------------------------\n\n/** Data for LISTENING event. */\ninterface WlmListeningData {\n readonly port: number;\n}\n\n/** Data for ASSOCIATION_RECEIVED event. */\ninterface WlmAssociationReceivedData {\n readonly peerInfo: string;\n}\n\n/** Data for ASSOCIATION_ACKNOWLEDGED event. */\ninterface WlmAssociationAcknowledgedData {\n readonly maxSendPDV: number;\n}\n\n/** Data for C_FIND_REQUEST event. */\ninterface WlmCFindRequestData {\n readonly raw: string;\n}\n\n/** Data for CANNOT_START_LISTENER event. */\ninterface WlmCannotStartListenerData {\n readonly message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Regex patterns for wlmscpfs verbose output\n// ---------------------------------------------------------------------------\n\n/** Event patterns for parsing wlmscpfs verbose output. */\nconst WLMSCPFS_PATTERNS: readonly EventPattern[] = [\n {\n event: WlmscpfsEvent.LISTENING,\n pattern: /listening on port\\s{1,20}(\\d+)/i,\n processor: (match): WlmListeningData => ({\n port: Number(match[1]),\n }),\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_RECEIVED,\n pattern: /Association Received\\s{0,20}([^\\r\\n]+)/,\n processor: (match): WlmAssociationReceivedData => ({\n peerInfo: (match[1] ?? '').trim(),\n }),\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_ACKNOWLEDGED,\n pattern: /Association Acknowledged \\(Max Send PDV:\\s*(\\d+)\\)/,\n processor: (match): WlmAssociationAcknowledgedData => ({\n maxSendPDV: Number(match[1]),\n }),\n },\n {\n event: WlmscpfsEvent.C_FIND_REQUEST,\n pattern: /Received (?:C-FIND|Find) Request/i,\n processor: (match): WlmCFindRequestData => ({\n raw: match[0] ?? '',\n }),\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_RELEASE,\n pattern: /Association Release/i,\n processor: () => undefined,\n },\n {\n event: WlmscpfsEvent.ASSOCIATION_ABORTED,\n pattern: /Association Abort/i,\n processor: () => undefined,\n },\n {\n event: WlmscpfsEvent.ECHO_REQUEST,\n pattern: /Received (?:C-ECHO|Echo) Request/i,\n processor: () => undefined,\n },\n {\n event: WlmscpfsEvent.CANNOT_START_LISTENER,\n pattern: /cannot listen|cannot initialise network/i,\n processor: (match): WlmCannotStartListenerData => ({\n message: match[0] ?? '',\n }),\n },\n];\n\n/** Events that indicate fatal errors (process should be stopped). */\nconst WLMSCPFS_FATAL_EVENTS: ReadonlySet<string> = new Set([WlmscpfsEvent.CANNOT_START_LISTENER]);\n\nexport { WlmscpfsEvent, WLMSCPFS_PATTERNS, WLMSCPFS_FATAL_EVENTS };\nexport type {\n WlmscpfsEventValue,\n WlmListeningData,\n WlmAssociationReceivedData,\n WlmAssociationAcknowledgedData,\n WlmCFindRequestData,\n WlmCannotStartListenerData,\n};\n","/**\n * DICOM Worklist Management SCP server wrapping the wlmscpfs binary.\n *\n * Provides a type-safe, event-driven API for serving worklist data\n * from a file-system based database. Uses a static factory pattern\n * because binary resolution and validation must happen before the\n * constructor call.\n *\n * @module servers/Wlmscpfs\n */\n\nimport { z } from 'zod';\nimport type { Result } from '../types';\nimport { ok, err } from '../types';\nimport { DcmtkProcess } from '../DcmtkProcess';\nimport type { DcmtkProcessConfig } from '../DcmtkProcess';\nimport { LineParser } from '../parsers/LineParser';\nimport { resolveBinary } from '../tools/_resolveBinary';\nimport { createValidationError } from '../tools/_toolError';\nimport { isSafePath } from '../patterns';\nimport { WLMSCPFS_PATTERNS, WLMSCPFS_FATAL_EVENTS } from '../events/wlmscpfs';\nimport type {\n WlmListeningData,\n WlmAssociationReceivedData,\n WlmAssociationAcknowledgedData,\n WlmCFindRequestData,\n WlmCannotStartListenerData,\n} from '../events/wlmscpfs';\n\n// ---------------------------------------------------------------------------\n// Event map type\n// ---------------------------------------------------------------------------\n\n/** Typed event map for the Wlmscpfs server. */\ninterface WlmscpfsEventMap {\n LISTENING: [WlmListeningData];\n ASSOCIATION_RECEIVED: [WlmAssociationReceivedData];\n ASSOCIATION_ACKNOWLEDGED: [WlmAssociationAcknowledgedData];\n C_FIND_REQUEST: [WlmCFindRequestData];\n ASSOCIATION_RELEASE: [];\n ASSOCIATION_ABORTED: [];\n ECHO_REQUEST: [];\n CANNOT_START_LISTENER: [WlmCannotStartListenerData];\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Options for creating a Wlmscpfs server instance. */\ninterface WlmscpfsOptions {\n /** Port to listen on (required, positional arg). */\n readonly port: number;\n /** Worklist data directory (required, -dfp flag). */\n readonly worklistDirectory: string;\n /** Enable file rejection (default true). Maps to -efr / -dfr. */\n readonly enableFileRejection?: boolean | undefined;\n /** Maximum PDU receive size. */\n readonly maxPdu?: number | undefined;\n /** ACSE timeout in seconds (passed to DCMTK as-is). */\n readonly acseTimeout?: number | undefined;\n /** DIMSE timeout in seconds (passed to DCMTK as-is). */\n readonly dimseTimeout?: number | undefined;\n /** Maximum simultaneous associations. */\n readonly maxAssociations?: number | undefined;\n /** Enable verbose mode (default true for event detection). */\n readonly verbose?: boolean | undefined;\n /** Timeout for start() to resolve (milliseconds). */\n readonly startTimeoutMs?: number | undefined;\n /** Timeout for graceful drain during stop() (milliseconds). */\n readonly drainTimeoutMs?: number | undefined;\n /** AbortSignal for external cancellation. */\n readonly signal?: AbortSignal | undefined;\n}\n\nconst WlmscpfsOptionsSchema = z\n .object({\n port: z.number().int().min(1).max(65535),\n worklistDirectory: z.string().min(1).refine(isSafePath, { message: 'path traversal detected in worklistDirectory' }),\n enableFileRejection: z.boolean().optional(),\n maxPdu: z.number().int().min(4096).max(131072).optional(),\n acseTimeout: z.number().int().positive().optional(),\n dimseTimeout: z.number().int().positive().optional(),\n maxAssociations: z.number().int().positive().optional(),\n verbose: z.boolean().optional(),\n startTimeoutMs: z.number().int().positive().optional(),\n drainTimeoutMs: z.number().int().positive().optional(),\n signal: z.instanceof(AbortSignal).optional(),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Argument builder\n// ---------------------------------------------------------------------------\n\n/** Builds the CLI arguments array from validated options. */\nfunction buildArgs(options: WlmscpfsOptions): string[] {\n const args: string[] = [];\n\n if (options.verbose !== false) {\n args.push('--verbose');\n }\n\n args.push('-dfp', options.worklistDirectory);\n\n if (options.enableFileRejection === false) {\n args.push('-dfr');\n } else {\n args.push('-efr');\n }\n\n buildNetworkArgs(args, options);\n\n args.push(String(options.port));\n\n return args;\n}\n\n/** Appends network-related CLI flags. */\nfunction buildNetworkArgs(args: string[], options: WlmscpfsOptions): void {\n if (options.maxPdu !== undefined) {\n args.push('--max-pdu', String(options.maxPdu));\n }\n if (options.acseTimeout !== undefined) {\n args.push('--acse-timeout', String(options.acseTimeout));\n }\n if (options.dimseTimeout !== undefined) {\n args.push('--dimse-timeout', String(options.dimseTimeout));\n }\n if (options.maxAssociations !== undefined) {\n args.push('--max-associations', String(options.maxAssociations));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Wlmscpfs class\n// ---------------------------------------------------------------------------\n\n/**\n * DICOM Worklist Management SCP server wrapping the wlmscpfs binary.\n *\n * Uses a static `create()` factory because binary resolution is fallible\n * and must complete before the constructor runs.\n *\n * Note: wlmscpfs does not print a reliable \"listening\" message in all\n * DCMTK versions, so `start()` resolves on spawn (like StoreSCP).\n *\n * @example\n * ```ts\n * const result = Wlmscpfs.create({ port: 2005, worklistDirectory: '/var/worklists' });\n * if (result.ok) {\n * const server = result.value;\n * server.onEvent('C_FIND_REQUEST', (data) => console.log('Find:', data.raw));\n * const startResult = await server.start();\n * }\n * ```\n */\nclass Wlmscpfs extends DcmtkProcess {\n private readonly parser: LineParser;\n private abortSignal: AbortSignal | undefined;\n private abortHandler: (() => void) | undefined;\n\n private constructor(config: DcmtkProcessConfig, parser: LineParser, signal?: AbortSignal) {\n super(config);\n this.parser = parser;\n this.wireParser();\n if (signal !== undefined) {\n this.wireAbortSignal(signal);\n }\n }\n\n /** Disposes the server and its parser, preventing listener leaks. */\n [Symbol.dispose](): void {\n if (this.abortSignal !== undefined && this.abortHandler !== undefined) {\n this.abortSignal.removeEventListener('abort', this.abortHandler);\n }\n this.parser[Symbol.dispose]();\n super[Symbol.dispose]();\n }\n\n /**\n * Registers a typed listener for a wlmscpfs-specific event.\n *\n * @param event - The event name from WlmscpfsEventMap\n * @param listener - Callback receiving typed event data\n * @returns this for chaining\n */\n onEvent<K extends keyof WlmscpfsEventMap>(event: K, listener: (...args: WlmscpfsEventMap[K]) => void): this {\n return this.on(event as string, listener as never);\n }\n\n /**\n * Registers a listener for incoming C-FIND requests.\n *\n * @param listener - Callback receiving C-FIND request data\n * @returns this for chaining\n */\n onCFindRequest(listener: (...args: WlmscpfsEventMap['C_FIND_REQUEST']) => void): this {\n return this.onEvent('C_FIND_REQUEST', listener);\n }\n\n /**\n * Registers a listener for when the server starts listening.\n *\n * @param listener - Callback receiving listening data (port)\n * @returns this for chaining\n */\n onListening(listener: (...args: WlmscpfsEventMap['LISTENING']) => void): this {\n return this.onEvent('LISTENING', listener);\n }\n\n /**\n * Creates a new Wlmscpfs server instance.\n *\n * @param options - Configuration options for the wlmscpfs server\n * @returns A Result containing the server instance or a validation/resolution error\n */\n static create(options: WlmscpfsOptions): Result<Wlmscpfs> {\n const validation = WlmscpfsOptionsSchema.safeParse(options);\n if (!validation.success) {\n return err(createValidationError('wlmscpfs', validation.error));\n }\n\n const binaryResult = resolveBinary('wlmscpfs');\n if (!binaryResult.ok) {\n return err(binaryResult.error);\n }\n\n const args = buildArgs(options);\n const parser = new LineParser();\n for (const pattern of WLMSCPFS_PATTERNS) {\n const addResult = parser.addPattern(pattern);\n if (!addResult.ok) {\n return err(addResult.error);\n }\n }\n\n const config: DcmtkProcessConfig = {\n binary: binaryResult.value,\n args,\n startTimeoutMs: options.startTimeoutMs,\n drainTimeoutMs: options.drainTimeoutMs,\n // wlmscpfs doesn't reliably print \"listening\" — resolve on spawn\n };\n\n return ok(new Wlmscpfs(config, parser, options.signal));\n }\n\n /** Wires the line parser to the process output. */\n private wireParser(): void {\n this.on('line', ({ text }) => {\n this.parser.feed(text);\n });\n\n this.parser.on('match', ({ event, data }) => {\n if (WLMSCPFS_FATAL_EVENTS.has(event)) {\n this.emit('error', { error: new Error(`Fatal: ${event}`), fatal: true });\n void this.stop();\n }\n this.emit(event, data);\n });\n }\n\n /** Wires an AbortSignal to stop the server. */\n private wireAbortSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n void this.stop();\n return;\n }\n this.abortSignal = signal;\n this.abortHandler = (): void => {\n void this.stop();\n };\n signal.addEventListener('abort', this.abortHandler, { once: true });\n }\n}\n\nexport { Wlmscpfs };\nexport type { WlmscpfsOptions, WlmscpfsEventMap };\n"]}
|