{"version":3,"sources":["../src/tasks/index.js","../src/utils/date-utils.js","../src/utils/fs-utils.js","../src/utils/os-utils.js","../src/utils/format-utils.js","../src/utils/core-utils.js","../src/tasks/servicesRegistry.js","../src/tasks/taskUtils.js","../src/db/ensure.js","../src/tasks/time-matcher.js","../src/tasks/taskLogs.js","../src/filedatabase/index.js","../src/filedatabase/serializers.js","../src/errors.js","../src/tasks/AbstractTask.js","../src/tasks/coreTasks/TaskPing.js","../src/tasks/coreTasks/TaskSampleProcess.js","../src/tasks/coreTasks/TaskShellCommand.js","../src/tasks/coreTasks/TaskSystemInfo.js","../src/tasks/coreTasks/TaskSumAB.js","../src/tasks/coreTasks/TaskStopRunner.js","../src/tasks/runtimeParams.js","../src/tasks/coreTasks/TaskPauseRunner.js","../src/tasks/coreTasks/TaskPauseTask.js","../src/tasks/coreTasks/TaskGetLogs.js","../src/tasks/coreTasks/TaskSetRuntimeParam.js","../src/tasks/taskRetentionNameRules.js","../src/tasks/taskRetention.js","../src/tasks/coreTasks/TaskPruneTaskRetention.js","../src/tasks/TasksRegistry.js","../src/tasks/serviceTaskAllowlist.js","../src/tasks/claimOrder.js","../src/tasks/taskScriptRunner.js"],"sourcesContent":["import os from \"node:os\";\nimport { sleepMs, toJsonColumn } from \"../utils/index.js\";\nimport {\n    registerInServicesRegistry,\n    touchServicesRegistry,\n    unregisterServicesRegistry,\n} from \"./servicesRegistry.js\";\nimport {\n    enqueueTask,\n    ensureTaskTables,\n    queueToTableNames,\n    taskHistoryInsertFromQueueRow,\n    createTaskProgressReporter,\n    loggerTaskLabel,\n} from \"./taskUtils.js\";\nimport { appendTaskIpcLog } from \"./taskLogs.js\";\nimport { nextTimeMatch, timeMatcher } from \"./time-matcher.js\";\nexport {\n    timeMatcher,\n    nextTimeMatch,\n    matchesParsedPattern,\n    convertPattern,\n    resolveAsterisks,\n    resolveRanges,\n    resolveSteps,\n} from \"./time-matcher.js\";\nimport { TasksRegistry } from \"./TasksRegistry.js\";\nimport { normalizeAllowedTasks } from \"./serviceTaskAllowlist.js\";\nimport {\n    controlLaneTaskNames,\n    ensureTasksRuntime,\n    readLoopRuntime,\n    mergeRuntimeParamSpecs,\n    runtimeValuesForSpecs,\n} from \"./runtimeParams.js\";\nimport { maybePruneTaskRetention, seedTaskRetentionRuntime } from \"./taskRetention.js\";\nimport { applyClaimOrder, compareClaimCandidates } from \"./claimOrder.js\";\n\n/** Sentinel value stored in the `progress` column when a task is paused due to error. */\nconst LOCKED_BY_ERROR_MESSAGE = \"locked by error\";\n\n/**\n * Next `params` to persist on the queue row. Long-running tasks return\n * `results.checkpointParams` so pause, hard stop, and the next scheduled\n * tick resume from the same cursor (offset / pending unit) instead of\n * starting the next window.\n *\n * @param {object|null|undefined} results\n * @returns {object|null}\n */\nexport function checkpointParamsFromResults(results) {\n    if (!results || typeof results !== \"object\") return null;\n    const next = results.checkpointParams;\n    return next && typeof next === \"object\" && !Array.isArray(next) ? next : null;\n}\n\nexport {\n    enqueueTask,\n    ensureTaskTables,\n    queueToTableNames,\n    taskHistoryInsertFromQueueRow,\n    updateTaskProgress,\n    createTaskProgressReporter,\n    loggerTaskLabel,\n    setLoggerTaskLabelResolver,\n} from \"./taskUtils.js\";\nexport {\n    listServicesRegistry,\n    registerInServicesRegistry,\n    touchServicesRegistry,\n    unregisterServicesRegistry,\n    updateServicesRegistryMetadata,\n    setGroupMaxInstancesDefaults,\n    resolveGroupMaxInstances,\n} from \"./servicesRegistry.js\";\n/** @deprecated Use registerInServicesRegistry */\nexport { registerInServicesRegistry as registerRunnerHeartbeat } from \"./servicesRegistry.js\";\n/** @deprecated Use touchServicesRegistry */\nexport { touchServicesRegistry as touchRunnerHeartbeat } from \"./servicesRegistry.js\";\n/** @deprecated Use unregisterServicesRegistry */\nexport { unregisterServicesRegistry as unregisterRunnerHeartbeat } from \"./servicesRegistry.js\";\n/** @deprecated Use listServicesRegistry */\nexport { listServicesRegistry as listAliveRunnerHeartbeats } from \"./servicesRegistry.js\";\nexport {\n    appendTaskIpcLog,\n    filterIpcLogRecords,\n    flushTaskIpcLogs,\n    ipcFileLogsTableNameForSourceResource,\n    readTaskIpcLogsSnapshot,\n    resolveIpcFileLogsDir,\n    pruneIpcLogsOlderThan,\n    planIpcLogPrune,\n    tasksLogsRoot,\n} from \"./taskLogs.js\";\nexport {\n    maybePruneTaskRetention,\n    pruneTaskRetention,\n    seedTaskRetentionRuntime,\n    readRetentionConfig,\n    effectiveRetentionDays,\n    retentionCutoffIso,\n    retentionCutoffFromHours,\n    deleteHistoryOlderThan,\n} from \"./taskRetention.js\";\nexport {\n    setTaskRetentionNameRulesDefaults,\n    resolveRetentionNameRules,\n    parseRetentionNameRulesRaw,\n} from \"./taskRetentionNameRules.js\";\nexport { TaskPruneTaskRetention } from \"./coreTasks/TaskPruneTaskRetention.js\";\nexport { runNodeTaskScript } from \"./taskScriptRunner.js\";\nexport { AbstractTask } from \"./AbstractTask.js\";\nexport { TasksRegistry } from \"./TasksRegistry.js\";\nexport { TaskPing } from \"./coreTasks/TaskPing.js\";\nexport { TaskSampleProcess } from \"./coreTasks/TaskSampleProcess.js\";\nexport { TaskShellCommand } from \"./coreTasks/TaskShellCommand.js\";\nexport { TaskSystemInfo } from \"./coreTasks/TaskSystemInfo.js\";\nexport { TaskSumAB } from \"./coreTasks/TaskSumAB.js\";\nexport { TaskStopRunner } from \"./coreTasks/TaskStopRunner.js\";\nexport {\n    TaskPauseRunner,\n    TaskUnpauseRunner,\n    applyRunnerPaused,\n} from \"./coreTasks/TaskPauseRunner.js\";\nexport {\n    TaskPauseTask,\n    TaskResumeTask,\n    applyPauseTask,\n    applyResumeTask,\n} from \"./coreTasks/TaskPauseTask.js\";\nexport { TaskGetLogs } from \"./coreTasks/TaskGetLogs.js\";\nexport { TaskSetRuntimeParam } from \"./coreTasks/TaskSetRuntimeParam.js\";\nexport {\n    normalizeAllowedTasks,\n    mergeAllowedTasksWithServiceTasks,\n    SERVICE_TASK_NAMES,\n} from \"./serviceTaskAllowlist.js\";\nexport {\n    applyClaimOrder,\n    claimDueInstantMs,\n    compareClaimCandidates,\n    isClaimDue,\n} from \"./claimOrder.js\";\nexport {\n    applyRuntimeParam,\n    applyRuntimePatch,\n    coerceRuntimeValue,\n    controlLaneTaskNames,\n    ensureTasksRuntime,\n    readLoopRuntime,\n    mergeRuntimeParamSpecs,\n    runtimeValuesForSpecs,\n    runtimeParamSpecsFromMetadata,\n    LOOP_RUNTIME_KEYS,\n    LOGGER_RUNTIME_KEYS,\n    DEFAULT_RUNTIME_PARAM_SPECS,\n} from \"./runtimeParams.js\";\n\n/** Shared default registry preloaded with every core task (including legacy aliases). */\nexport const defaultTasksRegistry = TasksRegistry.withCoreTasks();\n\n/**\n * Fail-fast accessor for `context.db` with a tasks-specific error message.\n *\n * @param {object} context\n * @returns {Function}\n */\nfunction getDb(context) {\n    const db = context.db;\n    if (!db) {\n        throw new Error(\"Tasks component requires context.db. Initialize DB first and attach to context.\");\n    }\n    return db;\n}\n\n/**\n * Coerce whatever the caller passed as `registry` into a `TasksRegistry` instance:\n *\n *   - `undefined` / missing → {@link defaultTasksRegistry} (every core task)\n *   - already a `TasksRegistry` → returned as-is\n *   - plain `{ name: Class }` map → wrapped in a fresh registry\n *\n * @param {TasksRegistry | Record<string, Function> | undefined} registry\n * @returns {TasksRegistry}\n */\nfunction normalizeRegistry(registry) {\n    if (!registry) return defaultTasksRegistry;\n    if (registry instanceof TasksRegistry) return registry;\n    return new TasksRegistry().addMany(registry);\n}\n\n/**\n * Convenience for enqueuing a targeted `stopRunner` task so a specific service\n * group exits cleanly on its next tick. Intended for operator tooling — the\n * runner itself also accepts in-process stop signals via `context.isStop()`.\n *\n * @param {object} context\n * @param {string} serviceGroup\n * @param {string} [queueName]\n * @param {number} [allowanceMs]\n * @returns {Promise<string>} UUID of the enqueued stop task.\n */\nexport async function enqueueStopTask(context, serviceGroup, queueName = \"tasks\", allowanceMs = 60_000) {\n    return enqueueTask(context, {\n        queueName,\n        name: \"stopRunner\",\n        params: { allowanceMs },\n        priority: 0,\n        serviceGroup,\n    });\n}\n\n/**\n * Broadcast a cooperative stop signal to every currently-running task instance.\n * Tasks decide per-call how much of `allowanceMs` to honor; we also emit on\n * `context.emitter` so other subscribers (e.g. fetchers) can wind down.\n *\n * @param {object} context\n * @param {Map<string, { requestStop?: Function }>} runningTaskInstances\n * @param {number} allowanceMs\n * @returns {Promise<void>}\n */\n/**\n * If an operator deleted a queue row while the task is still running, ask that\n * instance to stop. Delete is a different process (tasksmm) and cannot call\n * requestStop itself.\n *\n * @param {object} context\n * @param {string} tasksTable\n * @param {Map<string, { requestStop?: Function }>} runningTaskInstances\n */\nexport async function signalStopForDeletedQueueRows(context, tasksTable, runningTaskInstances) {\n    if (!runningTaskInstances?.size) return;\n    const db = context?.db;\n    if (!db) return;\n    const ids = [...runningTaskInstances.keys()];\n    let alive;\n    try {\n        const rows = await db(tasksTable).whereIn(\"id\", ids).select(\"id\");\n        alive = new Set((Array.isArray(rows) ? rows : []).map((r) => r.id));\n    } catch {\n        return;\n    }\n    for (const [id, inst] of runningTaskInstances) {\n        if (alive.has(id)) continue;\n        context.logger?.warn?.(`[tasks] queue row ${id} deleted — requesting stop`);\n        if (typeof inst.requestStop === \"function\") {\n            try {\n                await inst.requestStop(0);\n            } catch (error) {\n                context.logger?.warn?.(\"[tasks] task requestStop failed:\", error);\n            }\n        }\n    }\n}\n\nasync function signalRunningTasksStop(context, runningTaskInstances, allowanceMs) {\n    context.logger.warn?.(`[tasks] signaling ${runningTaskInstances.size} running task(s) to stop`);\n    for (const [, taskInstance] of runningTaskInstances) {\n        if (typeof taskInstance.requestStop === \"function\") {\n            try {\n                await taskInstance.requestStop(allowanceMs);\n            } catch (error) {\n                context.logger.warn?.(\"[tasks] task requestStop failed:\", error);\n            }\n        }\n    }\n    context.emitter.emit(\"stop\", allowanceMs);\n}\n\n/**\n * Run a single claimed task row end-to-end:\n *\n *   1. Resolve its class from the registry (unknown name → record failure + remove/pause).\n *   2. Construct an instance, stash it in `runningTaskInstances` so stop signals can reach it.\n *   3. `await instance.run(reportProgress)`; capture thrown errors into a structured `results` payload.\n *   4. Append a row to the history table, update/delete/pause the queue row depending on schedule/success.\n *   5. Return a summary telling the loop whether a `stopRunner` was requested.\n *\n * @param {object} context\n * @param {string} tasksTable\n * @param {string} historyTable\n * @param {object} row              The claimed queue row.\n * @param {TasksRegistry} registry\n * @param {Map<string, object>} runningTaskInstances\n * @returns {Promise<{ stopRunnerRequested: boolean, stopAllowanceMs: number }>}\n */\nasync function executeClaimedTask(context, tasksTable, historyTable, row, registry, runningTaskInstances) {\n    const db = getDb(context);\n    const taskName = row.name;\n    const TaskClass = registry.get(taskName);\n    if (!TaskClass) {\n        const err = { message: `Unknown task \"${taskName}\"` };\n        await db(historyTable).insert(\n            taskHistoryInsertFromQueueRow(row, {\n                completed_at: new Date(),\n                success: false,\n                status: \"failed\",\n                status_changed_at: db.fn.now(),\n                params: toJsonColumn(row.params),\n                results: toJsonColumn(err),\n            })\n        );\n        if (row.schedule) {\n            await db(tasksTable).where({ id: row.id }).update({\n                started_at: null,\n                completed_at: new Date(),\n                success: false,\n                results: toJsonColumn(err),\n                past_due: null,\n                status: \"paused\",\n                status_changed_at: db.fn.now(),\n                progress: LOCKED_BY_ERROR_MESSAGE,\n            });\n        } else {\n            await db(tasksTable).where({ id: row.id }).delete();\n        }\n        return { stopRunnerRequested: false, stopAllowanceMs: 0 };\n    }\n\n    let success = false;\n    let results = null;\n    let taskInstance = null;\n    try {\n        const taskLogger =\n            typeof context.logger?.child === \"function\"\n                ? context.logger.child(loggerTaskLabel(row))\n                : context.logger;\n        const taskContext =\n            taskLogger && taskLogger !== context.logger ? { ...context, logger: taskLogger } : context;\n        taskInstance = new TaskClass(taskContext, row);\n        runningTaskInstances.set(row.id, taskInstance);\n        const reportProgress = createTaskProgressReporter(taskContext, tasksTable, row.id);\n        const runResult = await taskInstance.run(reportProgress);\n        success = !!runResult?.success;\n        results = runResult?.results ?? null;\n    } catch (error) {\n        success = false;\n        results = {\n            message: error?.message ?? String(error),\n            name: error?.name ?? \"Error\",\n            stack: error?.stack ?? null,\n        };\n    } finally {\n        runningTaskInstances.delete(row.id);\n    }\n\n    const taskPaused =\n        success && results && typeof results === \"object\" && results.taskPaused === true;\n\n    await db(historyTable).insert(\n        taskHistoryInsertFromQueueRow(row, {\n            completed_at: new Date(),\n            success,\n            status: taskPaused ? \"paused\" : success ? \"completed\" : \"failed\",\n            status_changed_at: db.fn.now(),\n            params: toJsonColumn(row.params),\n            results: toJsonColumn(results),\n        })\n    );\n    if (!success) {\n        const dbName = String(context?.params?.get?.(\"dbName\") || \"local\");\n        const tableName = String(context?.params?.get?.(\"table\") || \"tasks\");\n        const fallbackRecoverCommand = [\n            \"node\",\n            \"examples/tasks/recover-task.js\",\n            `--dbName='${dbName.replace(/'/g, `'\\\\''`)}'`,\n            `--table='${tableName.replace(/'/g, `'\\\\''`)}'`,\n            `--id='${String(row.id).replace(/'/g, `'\\\\''`)}'`,\n        ].join(\" \");\n        const rerunCommand = results && typeof results === \"object\" && results.rerunCommand\n            ? results.rerunCommand\n            : fallbackRecoverCommand;\n        appendTaskIpcLog(context, row, {\n            level: \"error\",\n            message: `[tasks] task failed: ${row.name} id=${row.id}. Once problem is fixed, re-run: ${rerunCommand}`,\n            details: results,\n        });\n    }\n\n    // Cooperative pause: keep the queue row as paused with optional checkpoint params.\n    // Survives runner restart — resumeTask (or manual status→idle) continues later.\n    if (taskPaused) {\n        const checkpointParams = checkpointParamsFromResults(results) ?? row.params;\n        const progressPayload =\n            results.progress != null\n                ? results.progress\n                : { paused: true, pausedAt: new Date().toISOString(), message: \"paused\" };\n        await db(tasksTable).where({ id: row.id }).update({\n            started_at: null,\n            completed_at: new Date(),\n            success: true,\n            results: toJsonColumn(results),\n            params: toJsonColumn(checkpointParams),\n            progress: toJsonColumn(progressPayload),\n            status: \"paused\",\n            status_changed_at: db.fn.now(),\n            past_due: null,\n            service_name: null,\n            server_name: null,\n            instance_number: null,\n        });\n    } else if (row.schedule) {\n        if (success) {\n            let nextRunAt = null;\n            try {\n                nextRunAt = nextTimeMatch(row.schedule, new Date());\n            } catch (e) {\n                context.logger?.warn?.(`[tasks] nextTimeMatch after success for task ${row.id}: ${e?.message ?? String(e)}`);\n            }\n            const checkpointParams = checkpointParamsFromResults(results);\n            await db(tasksTable).where({ id: row.id }).update({\n                started_at: null,\n                completed_at: new Date(),\n                success,\n                results: toJsonColumn(results),\n                progress: null,\n                past_due: null,\n                status: \"idle\",\n                status_changed_at: db.fn.now(),\n                next_run_at: nextRunAt,\n                ...(checkpointParams ? { params: toJsonColumn(checkpointParams) } : {}),\n                // Claim overwrites these; clear so idle rows stay “any worker” (see claimNextRunnableTask).\n                service_name: null,\n                server_name: null,\n                instance_number: null,\n            });\n        } else {\n            await db(tasksTable).where({ id: row.id }).update({\n                started_at: null,\n                completed_at: new Date(),\n                success,\n                results: toJsonColumn(results),\n                status: \"paused\",\n                status_changed_at: db.fn.now(),\n                progress: LOCKED_BY_ERROR_MESSAGE,\n                past_due: null,\n            });\n        }\n    } else {\n        await db(tasksTable).where({ id: row.id }).delete();\n    }\n\n    const stopRunnerRequested = !!(results && typeof results === \"object\" && results.stopRunner === true);\n    const stopAllowanceMs = stopRunnerRequested ? Number(results.allowanceMs ?? 60_000) : 0;\n    scheduleTaskRetentionPass(context, historyTable);\n    return { stopRunnerRequested, stopAllowanceMs };\n}\n\nfunction scheduleTaskRetentionPass(context, historyTable) {\n    void maybePruneTaskRetention(context, {\n        historyTable,\n        queueName: context.tasksQueueName,\n    }).catch((err) => {\n        context.logger?.warn?.(`[tasks-retention] ${err?.message ?? String(err)}`);\n    });\n}\n\n/**\n * Atomically claim one runnable task row matching the caller's service group /\n * identity / allowlist, and return the (now-`running`) row — or `null` when none\n * are ready.\n *\n * Targeting rules for task columns (`service_group`, `service_name`, `server_name`,\n * `instance_number`): NULL on the task row means \"any\" for that field; a value\n * means \"this runner must match exactly\". This lets operators enqueue a task for\n * a specific host/instance while letting other rows fan out to whoever is free.\n *\n * @param {object} context\n * @param {string} tasksTable\n * @param {string} serviceGroup\n * @param {TasksRegistry} registry\n * @param {number} scanLimit How many candidate rows to pull before attempting claim.\n * @param {string[]|undefined} taskNames When set, only claim rows with `name IN taskNames`.\n * @param {{ service_name: string, server_name: string, instance_number: number }|null} runnerIdentity\n * @returns {Promise<object|null>} The claimed row, or `null` when nothing is ready.\n */\nasync function claimNextRunnableTask(\n    context,\n    tasksTable,\n    serviceGroup,\n    registry,\n    scanLimit,\n    taskNames,\n    runnerIdentity\n) {\n    const db = getDb(context);\n\n    // Targeting: NULL on the task row means \"any\" for that field. Rows must match the runner's\n    // service_group and identity (when provided) for each non-null task column.\n    let query = db(tasksTable)\n        .where({ status: \"idle\" })\n        .where(function () {\n            this.whereNull(\"service_group\").orWhere({ service_group: serviceGroup });\n        })\n        // Honor next_run_at as a \"not before\" gate. NULL = no delay (claim now).\n        // This makes delayed one-off retries (next_run_at set, no schedule) wait\n        // their turn; scheduled rows already set next_run_at to their next fire\n        // time on enqueue/completion, so this stays consistent with timeMatcher.\n        .where(function () {\n            this.whereNull(\"next_run_at\").orWhere(\"next_run_at\", \"<=\", db.fn.now());\n        });\n    query = applyClaimOrder(query).limit(scanLimit);\n    if (taskNames && taskNames.length > 0) {\n        query = query.whereIn(\"name\", taskNames);\n    }\n    if (runnerIdentity) {\n        query = query\n            .where(function () {\n                this.whereNull(\"service_name\").orWhere({ service_name: runnerIdentity.service_name });\n            })\n            .where(function () {\n                this.whereNull(\"instance_number\").orWhere({ instance_number: runnerIdentity.instance_number });\n            })\n            .where(function () {\n                this.whereNull(\"server_name\").orWhere({ server_name: runnerIdentity.server_name });\n            });\n    } else {\n        // Without registry identity we cannot match a specific instance; only rows with no per-instance targeting.\n        query = query\n            .whereNull(\"service_name\")\n            .whereNull(\"instance_number\")\n            .whereNull(\"server_name\");\n    }\n    const candidates = await query;\n    candidates.sort(compareClaimCandidates);\n\n    for (const row of candidates) {\n        if (!row.past_due && row.schedule && !timeMatcher(row.schedule)) {\n            continue;\n        }\n\n        const TaskClass = registry.get(row.name);\n        if (!TaskClass) {\n            // Not registered on this runner — skip without claiming so another worker can run it.\n            continue;\n        }\n\n        const taskInstance = new TaskClass(context, row);\n        const reason = taskInstance.cantRunReason ? await taskInstance.cantRunReason() : null;\n        if (reason) {\n            if (!row.past_due) {\n                await db(tasksTable).where({ id: row.id }).update({\n                    past_due: db.fn.now(),\n                    progress: String(reason),\n                });\n            }\n            continue;\n        }\n\n        const claimPatch = {\n            started_at: db.fn.now(),\n            status: \"running\",\n            status_changed_at: db.fn.now(),\n        };\n        if (runnerIdentity) {\n            claimPatch.service_name = runnerIdentity.service_name;\n            claimPatch.server_name = runnerIdentity.server_name;\n            claimPatch.instance_number = runnerIdentity.instance_number;\n        }\n\n        const updated = await db(tasksTable)\n            .where({ id: row.id, status: \"idle\" })\n            .update(claimPatch)\n            .returning(\"*\");\n\n        const claimed = Array.isArray(updated) ? updated[0] : null;\n        if (claimed) return claimed;\n    }\n\n    return null;\n}\n\n/**\n * Main runner loop. Registers in the services registry (optional), then polls\n * the queue, claiming up to `maxParallel` tasks at a time plus one extra\n * \"control lane\" for `stop` / `pause` / `unpause` / `setRuntimeParam` (and\n * optional `controlLaneTasks`) so those can run even when workers are saturated.\n * When `context.tasksRuntime.paused` is true, in-flight worker tasks finish but\n * no new worker-lane claims are made until unpause.\n *\n * Loop knobs (`maxParallel`, `pollMs`, `claimJitterMs`, `scanLimit`) live on\n * `context.tasksRuntime` and are re-read every tick — change them live with the\n * `setRuntimeParam` core task (no restart).\n *\n * Exits when any of the following become true:\n *   - `context.isStop()` flips to `true` (external shutdown signal).\n *   - A `stopRunner` task completes successfully.\n *   - `context.tasksRunnerStop === true` (manual flag, mostly for tests).\n *\n * @param {object} context\n * @param {{\n *   queueName?: string,\n *   target: string,\n *   pollMs?: number,\n *   claimJitterMs?: number,\n *   maxParallel?: number,\n *   scanLimit?: number,\n *   allowedTasks?: string | string[],\n *   controlLaneTasks?: string | string[],\n *   registry?: TasksRegistry | Record<string, Function>,\n *   runnerServiceGroup?: string,\n *   runnerServiceName?: string,\n *   runnerInstanceNumber?: number,\n *   runnerHeartbeatIntervalMs?: number,\n *   runnerHeartbeatStaleMs?: number,\n *   runnerGroupMaxInstances?: number,\n *   runnerEnforceMaxInstances?: boolean,\n *   runnerMetadata?: Record<string, unknown>,\n *   runnerRuntimeParams?: import(\"./runtimeParams.js\").RuntimeParamSpec[],\n *   onRuntimeParam?: (key: string, value: unknown, runtime: object, context: object) => unknown,\n * }} options\n * @returns {Promise<void>}\n */\nexport async function runTasksLoop(context, options) {\n    const queueName = options.queueName ?? \"tasks\";\n    const target = options.target;\n    const allowedTasks = normalizeAllowedTasks(options.allowedTasks);\n    const controlLaneNames = controlLaneTaskNames(options.controlLaneTasks);\n    const registry = normalizeRegistry(options.registry);\n    const { tasksTable, historyTable } = queueToTableNames(queueName);\n\n    if (!target) throw new Error(\"runTasksLoop: target is required\");\n\n    context.tasksQueueName = queueName;\n    ensureTasksRuntime(context, {\n        maxParallel: options.maxParallel ?? 32,\n        pollMs: options.pollMs ?? 1000,\n        claimJitterMs: options.claimJitterMs ?? 0,\n        scanLimit: options.scanLimit ?? 100,\n    });\n    seedTaskRetentionRuntime(context);\n    if (typeof options.onRuntimeParam === \"function\") {\n        context.tasksRuntimeOnParam = options.onRuntimeParam;\n    }\n\n    const runningPromises = new Set();\n    const runningTaskInstances = new Map();\n    // Expose so control-lane pauseTask can signal in-process workers.\n    context.runningTaskInstances = runningTaskInstances;\n    let runningControlPromise = null;\n    let stopRequested = false;\n    let stopAllowanceMs = Number(context.stopAllowanceMs) > 0 ? Number(context.stopAllowanceMs) : 60_000;\n    context.tasksRunnerStop = false;\n\n    let registryReg = null;\n    let registryInterval = null;\n    let runnerIdentity = null;\n    const hbGroup = options.runnerServiceGroup?.trim();\n    if (hbGroup) {\n        const hbIntervalMs = options.runnerHeartbeatIntervalMs ?? 10_000;\n        const staleMs = options.runnerHeartbeatStaleMs ?? 45_000;\n        const runtimeParamSpecs = mergeRuntimeParamSpecs(options.runnerRuntimeParams);\n        context.tasksRuntimeParamSpecs = runtimeParamSpecs;\n        const defaultMeta = {\n            component: \"tasks-runner\",\n            allowedTasks: allowedTasks?.length ? allowedTasks.join(\",\") : \"all\",\n            paused: false,\n            runtimeParams: runtimeParamSpecs,\n            runtime: runtimeValuesForSpecs(context, runtimeParamSpecs),\n        };\n        const metadata = {\n            ...defaultMeta,\n            ...(options.runnerMetadata && typeof options.runnerMetadata === \"object\"\n                ? options.runnerMetadata\n                : {}),\n        };\n        if (!Array.isArray(metadata.runtimeParams) || metadata.runtimeParams.length === 0) {\n            metadata.runtimeParams = defaultMeta.runtimeParams;\n        }\n        if (!metadata.runtime || typeof metadata.runtime !== \"object\") {\n            metadata.runtime = defaultMeta.runtime;\n        }\n        registryReg = await registerInServicesRegistry(context, {\n            queueName,\n            target,\n            serviceGroup: hbGroup,\n            serviceName: options.runnerServiceName,\n            instanceNumber: options.runnerInstanceNumber,\n            staleMs,\n            groupMaxInstances: options.runnerGroupMaxInstances,\n            enforceMaxInstances: options.runnerEnforceMaxInstances ?? true,\n            metadata,\n        });\n        // Expose registration so setRuntimeParam can patch metadata.\n        context.servicesRegistry = registryReg;\n        runnerIdentity = {\n            service_name: registryReg.serviceName,\n            server_name: os.hostname(),\n            instance_number: registryReg.instanceNumber,\n        };\n        registryInterval = setInterval(() => {\n            void touchServicesRegistry(context, registryReg).catch((err) => {\n                context.logger.warn?.(`[services-registry] touch failed: ${err?.message ?? String(err)}`);\n            });\n        }, hbIntervalMs);\n    }\n\n    try {\n        while (!context.isStop() && !stopRequested && context.tasksRunnerStop !== true) {\n            const { maxParallel, pollMs, claimJitterMs, scanLimit } = readLoopRuntime(context);\n            await signalStopForDeletedQueueRows(context, tasksTable, runningTaskInstances);\n\n            // Control lane: stop / setRuntimeParam / extras even when workers are saturated.\n            if (!runningControlPromise) {\n                const claimedControlTask = await claimNextRunnableTask(\n                    context,\n                    tasksTable,\n                    target,\n                    registry,\n                    10,\n                    controlLaneNames,\n                    runnerIdentity\n                );\n                if (claimedControlTask) {\n                    runningControlPromise = executeClaimedTask(\n                        context,\n                        tasksTable,\n                        historyTable,\n                        claimedControlTask,\n                        registry,\n                        runningTaskInstances\n                    )\n                        .then(async (outcome) => {\n                            if (outcome.stopRunnerRequested && !stopRequested) {\n                                stopRequested = true;\n                                stopAllowanceMs = outcome.stopAllowanceMs || stopAllowanceMs;\n                                context.tasksRunnerStop = true;\n                                await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);\n                            }\n                        })\n                        .finally(() => {\n                            runningControlPromise = null;\n                        });\n                }\n            }\n\n            if (claimJitterMs > 0) {\n                await sleepMs(Math.floor(Math.random() * (claimJitterMs + 1)));\n            }\n\n            // Worker lane: skip new claims while paused (in-flight work still drains).\n            const paused = context.tasksRuntime?.paused === true;\n            if (!paused) {\n                while (runningPromises.size < maxParallel) {\n                    const claimed = await claimNextRunnableTask(\n                        context,\n                        tasksTable,\n                        target,\n                        registry,\n                        scanLimit,\n                        allowedTasks,\n                        runnerIdentity\n                    );\n                    if (!claimed) break;\n\n                    const p = executeClaimedTask(\n                        context,\n                        tasksTable,\n                        historyTable,\n                        claimed,\n                        registry,\n                        runningTaskInstances\n                    )\n                        .then(async (outcome) => {\n                            if (outcome.stopRunnerRequested && !stopRequested) {\n                                stopRequested = true;\n                                stopAllowanceMs = outcome.stopAllowanceMs || stopAllowanceMs;\n                                context.tasksRunnerStop = true;\n                                await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);\n                            }\n                        })\n                        .finally(() => {\n                            runningPromises.delete(p);\n                        });\n                    runningPromises.add(p);\n                }\n            }\n\n            const wakePromises = [...runningPromises];\n            if (runningControlPromise) {\n                wakePromises.push(runningControlPromise);\n            }\n            if (wakePromises.length === 0) {\n                scheduleTaskRetentionPass(context, historyTable);\n                await sleepMs(pollMs);\n            } else {\n                const safe = wakePromises.map((p) => p.catch(() => undefined));\n                await Promise.race([sleepMs(pollMs), Promise.race(safe)]);\n            }\n        }\n\n        if (context.isStop() && !stopRequested) {\n            stopRequested = true;\n            stopAllowanceMs = Number(context.stopAllowanceMs) > 0\n                ? Number(context.stopAllowanceMs)\n                : stopAllowanceMs;\n            await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);\n        }\n\n        if (runningPromises.size > 0) {\n            if (stopRequested) {\n                await Promise.race([\n                    Promise.allSettled(Array.from(runningPromises)),\n                    sleepMs(stopAllowanceMs).then(() => {\n                        context.logger.warn?.(\n                            `[tasks] stop allowance (${stopAllowanceMs}ms) reached; ${runningPromises.size} task(s) still running`\n                        );\n                    }),\n                ]);\n            } else {\n                await Promise.allSettled(Array.from(runningPromises));\n            }\n        }\n    } finally {\n        if (registryInterval) {\n            clearInterval(registryInterval);\n            registryInterval = null;\n        }\n        if (registryReg) {\n            await unregisterServicesRegistry(context, registryReg).catch((err) => {\n                context.logger.warn?.(`[services-registry] unregister failed: ${err?.message ?? String(err)}`);\n            });\n            registryReg = null;\n            delete context.servicesRegistry;\n            delete context.runnerHeartbeat;\n        }\n    }\n}\n\n/**\n * Poll for the outcome of a task by id. Returns the matching `_history` row when\n * the task completes, or `null` when the wait times out.\n *\n * Resolves any of:\n *   - Legacy: history row whose `id` equals the queue task id.\n *   - `opid` equals the queue task id (stamped when enqueue had no opid — see\n *     {@link taskHistoryInsertFromQueueRow}).\n *   - Same `name`+`opid` with `completed_at` ≥ wait start (optional `name`/`opid`\n *     hints help when the queue row is already gone on the first poll).\n *\n * Fast one-shot tasks (e.g. hostInfo) often finish before the first poll sees the\n * queue row — we keep polling until `timeoutMs` rather than treating “row gone”\n * as failure.\n *\n * @param {object} context\n * @param {string} taskId\n * @param {{\n *   queueName?: string,\n *   timeoutMs?: number,\n *   pollMs?: number,\n *   name?: string,\n *   opid?: string|null,\n * }} [options]\n * @returns {Promise<object|null>}\n */\nexport async function waitForTaskResult(context, taskId, options = {}) {\n    const db = getDb(context);\n    const queueName = options.queueName ?? \"tasks\";\n    const timeoutMs = options.timeoutMs ?? 60000;\n    const pollMs = options.pollMs ?? 500;\n    const { tasksTable, historyTable } = queueToTableNames(queueName);\n    const deadline = Date.now() + timeoutMs;\n    // Small skew grace so a fast complete on a slightly-behind DB clock still matches.\n    const waitStartedAt = new Date(Date.now() - 5_000);\n    let cachedNameOpid =\n        options.name != null && String(options.name).trim() !== \"\"\n            ? {\n                  name: String(options.name).trim(),\n                  opid: options.opid !== undefined ? options.opid : null,\n              }\n            : null;\n\n    /**\n     * @param {string} name\n     * @param {string|null|undefined} opid\n     * @returns {Promise<object|undefined>}\n     */\n    async function findHistory(name, opid) {\n        const base = () =>\n            db(historyTable).where({ name }).where(\"completed_at\", \">=\", waitStartedAt);\n\n        if (opid != null && String(opid).trim() !== \"\") {\n            const byOpid = await base().where({ opid }).orderBy(\"completed_at\", \"desc\").first();\n            if (byOpid) return byOpid;\n        }\n\n        // Queue id stamped into history.opid when the task had no opid.\n        const byQueueId = await base().where({ opid: taskId }).orderBy(\"completed_at\", \"desc\").first();\n        if (byQueueId) return byQueueId;\n\n        // Also try without the time gate for the unique queue-id opid (clock skew).\n        const byQueueIdAny = await db(historyTable)\n            .where({ name, opid: taskId })\n            .orderBy(\"completed_at\", \"desc\")\n            .first();\n        if (byQueueIdAny) return byQueueIdAny;\n\n        if (opid == null || opid === \"\") {\n            const byNull = await base().whereNull(\"opid\").orderBy(\"completed_at\", \"desc\").first();\n            if (byNull) return byNull;\n        }\n\n        return undefined;\n    }\n\n    while (Date.now() <= deadline) {\n        const legacy = await db(historyTable).where({ id: taskId }).orderBy(\"created_at\", \"desc\").first();\n        if (legacy) {\n            return legacy;\n        }\n\n        const pending = await db(tasksTable).where({ id: taskId }).first();\n        if (pending) {\n            cachedNameOpid = { name: pending.name, opid: pending.opid };\n        }\n\n        if (cachedNameOpid) {\n            const done = await findHistory(cachedNameOpid.name, cachedNameOpid.opid);\n            if (done) {\n                return done;\n            }\n        } else {\n            // Name unknown yet — still try correlation by stamped opid=taskId across names.\n            const byQueueId = await db(historyTable)\n                .where({ opid: taskId })\n                .orderBy(\"completed_at\", \"desc\")\n                .first();\n            if (byQueueId) {\n                return byQueueId;\n            }\n        }\n\n        await sleepMs(pollMs);\n    }\n    return null;\n}\n\n/**\n * Higher-level wrapper over {@link runTasksLoop}: captures defaults / params-driven\n * config at construction, then exposes them as methods (`ensureTaskTables`,\n * `runTasksLoop`) so callers don't have to plumb the same options through twice.\n *\n * Prefer `TasksManager.init(context)` over the bare constructor — `init` pulls\n * sensible defaults from `context.params` using the `tasks` module namespace.\n */\nexport class TasksManager {\n    /**\n     * @param {object} context\n     * @param {{\n     *   queueName?: string,\n     *   target?: string,\n     *   recreateTaskTables?: boolean,\n     *   pollMs?: number,\n     *   claimJitterMs?: number,\n     *   maxParallel?: number,\n     *   scanLimit?: number,\n     *   allowedTasks?: string | string[],\n     *   registry?: TasksRegistry | Record<string, Function>,\n     *   runnerServiceGroup?: string,\n     *   runnerServiceName?: string,\n     *   runnerInstanceNumber?: number,\n     *   runnerHeartbeatIntervalMs?: number,\n     *   runnerHeartbeatStaleMs?: number,\n     *   runnerGroupMaxInstances?: number,\n     *   runnerEnforceMaxInstances?: boolean,\n     *   runnerMetadata?: Record<string, unknown>,\n     * }} [options]\n     */\n    constructor(context, options = {}) {\n        this.context = context;\n        this.queueName = options.queueName ?? \"tasks\";\n        this.target = options.target ?? \"localRunner\";\n        this.recreateTaskTables = options.recreateTaskTables ?? false;\n        this.pollMs = options.pollMs ?? 1000;\n        this.claimJitterMs = options.claimJitterMs ?? 0;\n        this.maxParallel = options.maxParallel ?? 1;\n        this.scanLimit = options.scanLimit ?? 100;\n        this.allowedTasks = normalizeAllowedTasks(options.allowedTasks);\n        this.registry = normalizeRegistry(options.registry);\n        this.runnerServiceGroup = options.runnerServiceGroup;\n        this.runnerServiceName = options.runnerServiceName;\n        this.runnerInstanceNumber = options.runnerInstanceNumber;\n        this.runnerHeartbeatIntervalMs = options.runnerHeartbeatIntervalMs;\n        this.runnerHeartbeatStaleMs = options.runnerHeartbeatStaleMs;\n        this.runnerGroupMaxInstances = options.runnerGroupMaxInstances;\n        this.runnerEnforceMaxInstances = options.runnerEnforceMaxInstances;\n        this.runnerMetadata = options.runnerMetadata;\n    }\n\n    /**\n     * Preferred factory: reads defaults from `context.params` (module namespace\n     * `\"tasks\"`), then overlays explicit `options`. Keeps CLI flags, env vars,\n     * and inline options in one consistent resolver.\n     *\n     * @param {object} context\n     * @param {ConstructorParameters<typeof TasksManager>[1]} [options]\n     * @returns {TasksManager}\n     */\n    static init(context, options = {}) {\n        const defs = {\n            table: \"string default tasks\",\n            target: \"string default localRunner\",\n            recreateTaskTables: \"boolean default false\",\n            pollMs: \"number default 1000\",\n            claimJitterMs: \"number default 0\",\n            maxParallel: \"number default 1\",\n            scanLimit: \"number default 100\",\n            allowedTasks: \"string\",\n            runnerServiceGroup: \"string\",\n            runnerServiceName: \"string\",\n            runnerInstanceNumber: \"number\",\n            runnerHeartbeatIntervalMs: \"number default 10000\",\n            runnerHeartbeatStaleMs: \"number default 45000\",\n            runnerGroupMaxInstances: \"number\",\n            runnerEnforceMaxInstances: \"boolean default true\",\n        };\n\n        const discovered = context.params.getAllForModule(\"tasks\", defs);\n        const resolved = {\n            queueName: discovered.table,\n            target: discovered.target,\n            recreateTaskTables: discovered.recreateTaskTables,\n            pollMs: discovered.pollMs,\n            claimJitterMs: discovered.claimJitterMs,\n            maxParallel: discovered.maxParallel,\n            scanLimit: discovered.scanLimit,\n            allowedTasks: discovered.allowedTasks,\n            runnerServiceGroup: discovered.runnerServiceGroup,\n            runnerServiceName: discovered.runnerServiceName,\n            runnerInstanceNumber: discovered.runnerInstanceNumber,\n            runnerHeartbeatIntervalMs: discovered.runnerHeartbeatIntervalMs,\n            runnerHeartbeatStaleMs: discovered.runnerHeartbeatStaleMs,\n            runnerGroupMaxInstances: discovered.runnerGroupMaxInstances,\n            runnerEnforceMaxInstances: discovered.runnerEnforceMaxInstances,\n            ...options,\n        };\n        return new TasksManager(context, resolved);\n    }\n\n    /**\n     * Idempotently ensure the three backing tables exist for this queue.\n     *\n     * @param {{ recreate?: boolean }} [options]\n     * @returns {Promise<void>}\n     */\n    async ensureTaskTables(options = {}) {\n        await ensureTaskTables(this.context, {\n            queueName: this.queueName,\n            recreate: options.recreate ?? this.recreateTaskTables,\n        });\n    }\n\n    /**\n     * Start the runner loop using this manager's resolved config. Per-call\n     * options override the stored defaults, but `runnerMetadata` still falls\n     * through when omitted.\n     *\n     * @param {Partial<ConstructorParameters<typeof TasksManager>[1]>} [options]\n     * @returns {Promise<void>}\n     */\n    async runTasksLoop(options = {}) {\n        await runTasksLoop(this.context, {\n            queueName: options.queueName ?? this.queueName,\n            target: options.target ?? this.target,\n            pollMs: options.pollMs ?? this.pollMs,\n            claimJitterMs: options.claimJitterMs ?? this.claimJitterMs,\n            maxParallel: options.maxParallel ?? this.maxParallel,\n            scanLimit: options.scanLimit ?? this.scanLimit,\n            allowedTasks: options.allowedTasks ?? this.allowedTasks,\n            registry: options.registry ?? this.registry,\n            runnerServiceGroup: options.runnerServiceGroup ?? this.runnerServiceGroup,\n            runnerServiceName: options.runnerServiceName ?? this.runnerServiceName,\n            runnerInstanceNumber: options.runnerInstanceNumber ?? this.runnerInstanceNumber,\n            runnerHeartbeatIntervalMs: options.runnerHeartbeatIntervalMs ?? this.runnerHeartbeatIntervalMs,\n            runnerHeartbeatStaleMs: options.runnerHeartbeatStaleMs ?? this.runnerHeartbeatStaleMs,\n            runnerGroupMaxInstances: options.runnerGroupMaxInstances ?? this.runnerGroupMaxInstances,\n            runnerEnforceMaxInstances: options.runnerEnforceMaxInstances ?? this.runnerEnforceMaxInstances,\n            runnerMetadata: options.runnerMetadata ?? this.runnerMetadata,\n        });\n    }\n}\n","/**\n * Date/time utility functions for timestamp formatting and timezone conversions\n */\n\n\n\n\n\n\n/**\n * Format a date string or Date object to ISO8601 format in specified timezone\n * Always returns UTC-based ISO strings (YYYY-MM-DDTHH:mm:ssZ) as internal representation\n * \n * @param value - Date object, ISO string, or timestamp\n * @param options - Formatting options\n * @returns ISO8601 formatted string\n */\nexport function formatDate(value, options = {}) {\n    if (value === undefined || value === null) {\n        return \"\";\n    }\n\n    const { timezone = \"UTC\", format = \"iso\" } = options;\n    \n    let date;\n    if (value instanceof Date) {\n        date = value;\n    } else if (typeof value === \"string\") {\n        date = new Date(value);\n    } else if (typeof value === \"number\") {\n        date = new Date(value);\n    } else {\n        return \"\";\n    }\n\n    if (isNaN(date.getTime())) {\n        return \"\";\n    }\n\n    // Format based on requested format\n    switch (format) {\n        case \"iso\":\n            // Full ISO8601: 2025-01-01T01:01:01Z\n            return date.toISOString();\n        \n        case \"iso-date\":\n            // Date only: 2025-01-01\n            return date.toISOString().split(\"T\")[0];\n        \n        case \"iso-time\":\n            // Time only: 01:01:01Z\n            return date.toISOString().split(\"T\")[1];\n        \n        case \"human\":\n            // Human-readable: Jan 1, 2025 01:01:01 UTC\n            if (timezone === \"user\") {\n                return date.toLocaleString();\n            }\n            return date.toUTCString();\n        \n        default:\n            return date.toISOString();\n    }\n}\n\n/**\n * Parse a date value and return ISO8601 string in UTC\n * This is the canonical format for internal storage\n * \n * @param value - Date object or string\n * @returns ISO8601 string in UTC timezone\n */\nexport function toISOString(value) {\n    return formatDate(value, { timezone: \"UTC\", format: \"iso\" });\n}\n\n/**\n * Get current timestamp as ISO8601 string in UTC\n * @returns Current time as ISO8601 string\n */\nexport function nowISO() {\n    return new Date().toISOString();\n}\n\n/**\n * Parse ISO8601 string to Date object\n * @param isoString - ISO8601 formatted string\n * @returns Date object\n */\nexport function fromISOString(isoString) {\n    return new Date(isoString);\n}\n\n/**\n * Calculate difference between two dates in various units\n * @param start - Start date (ISO string or Date)\n * @param end - End date (ISO string or Date)\n * @returns Object with duration in multiple units\n */\nexport function dateDiff(\n    start,\n    end\n)\n\n\n\n\n\n{\n    const startDate = start instanceof Date ? start : new Date(start);\n    const endDate = end instanceof Date ? end : new Date(end);\n    \n    const diffMs = endDate.getTime() - startDate.getTime();\n    \n    return {\n        milliseconds: diffMs,\n        seconds: Math.floor(diffMs / 1000),\n        minutes: Math.floor(diffMs / (1000 * 60)),\n        hours: Math.floor(diffMs / (1000 * 60 * 60)),\n        days: Math.floor(diffMs / (1000 * 60 * 60 * 24))\n    };\n}\n\n/**\n * Check if a folder name looks like an ISO8601 timestamp\n * Used to identify version folders vs regular folders\n * @param folderName - Folder name to check\n * @returns true if the folder name is a valid ISO8601 timestamp\n */\nexport function isTimestampFolder(folderName) {\n    // Match ISO8601 format: YYYY-MM-DDTHH:mm:ssZ\n    const isoRegex = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(Z|\\.\\d{3}Z)$/;\n    \n    if (!isoRegex.test(folderName)) {\n        return false;\n    }\n    \n    const date = new Date(folderName);\n    return !isNaN(date.getTime()) && date.getTime() > 0;\n}\n\n/**\n * Generate a new version name (ISO8601 timestamp)\n * If existingVersions provided, ensures the new version is later than all existing ones\n * @param existingVersions - Array of existing version timestamps\n * @returns New version timestamp that is unique and later than existing ones\n */\nexport function generateVersionName(existingVersions = []) {\n    if (existingVersions.length === 0) {\n        // No existing versions, use current timestamp\n        const now = new Date();\n        return now.toISOString().split(\".\")[0] + \"Z\";\n    }\n    \n    // Find the maximum timestamp among all existing versions\n    const maxTimestamp = existingVersions.reduce((max, version) => {\n        const versionDate = new Date(version);\n        const maxDate = new Date(max);\n        return versionDate > maxDate ? version : max;\n    });\n    \n    // Increment by 1 second to ensure uniqueness\n    const maxDate = new Date(maxTimestamp);\n    const nextDate = new Date(maxDate.getTime() + 1000);\n    \n    return nextDate.toISOString().split(\".\")[0] + \"Z\";\n}\n\n","/**\n * File System Utilities\n * \n * Helper functions for file system operations like path management,\n * directory creation, and file type detection\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\n\n/**\n * Ensure a directory path exists, creating it if necessary\n * Returns the absolute path\n */\nexport async function ensurePath(...pathParts) {\n    const fullPath = path.resolve(...pathParts);\n    \n    if (!fs.existsSync(fullPath)) {\n        await fs.promises.mkdir(fullPath, { recursive: true });\n    }\n    \n    return fullPath;\n}\n\n/**\n * Synchronous version of ensurePath\n */\nexport function ensurePathSync(...pathParts) {\n    const fullPath = path.resolve(...pathParts);\n    \n    if (!fs.existsSync(fullPath)) {\n        fs.mkdirSync(fullPath, { recursive: true });\n    }\n    \n    return fullPath;\n}\n\n/**\n * Get file extension for a given data type\n */\nexport function getFileExtension(dataType) {\n    switch (dataType) {\n        case \"json-array\":\n        case \"json-object\":\n            return \"json\";\n        case \"text\":\n            return \"txt\";\n        case \"xml\":\n            return \"xml\";\n        default:\n            return \"json\";\n    }\n}\n\n/**\n * Get __dirname equivalent for ES modules\n * \n * Returns the directory path of the module file\n * Useful for resolving relative paths in ES modules where __dirname is not available\n * \n * @param metaUrl - The import.meta.url from the calling module (must be passed from calling module)\n * @returns The directory path of the module\n * \n * @example\n * ```typescript\n * import { getDirname } from \"@nmakarov/cli-toolkit/utils\";\n * const __dirname = getDirname(import.meta.url);\n * ```\n */\nexport function getDirname(metaUrl) {\n    return path.dirname(fileURLToPath(metaUrl));\n}\n\n","/**\n * Operating System Utilities\n * \n * Helper functions for interacting with the operating system\n * to get system statistics and information\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\nimport { execSync } from \"child_process\";\n\n/**\n * Get free disk space for a given path (in bytes)\n * Returns null if unable to determine\n * Uses `df` command on Unix-like systems\n */\nexport function getFreeDiskSpace(targetPath) {\n    try {\n        // If the target path doesn't exist, use its parent directory\n        let pathToCheck = targetPath;\n        if (!fs.existsSync(targetPath)) {\n            const parentDir = path.dirname(targetPath);\n            if (fs.existsSync(parentDir)) {\n                pathToCheck = parentDir;\n            } else {\n                // If parent doesn't exist either, use the root directory\n                pathToCheck = process.platform === \"win32\" ? \"C:\\\\\" : \"/\";\n            }\n        }\n\n        if (process.platform === \"win32\") {\n            // Windows: use wmic command\n            // Note: This is a simplified implementation, may need adjustments\n            return null; // TODO: Implement robust Windows support\n        } else {\n            // Unix-like systems: use df command\n            const stdout = execSync(`df -k \"${pathToCheck}\"`, { encoding: \"utf8\" });\n            const lines = stdout.trim().split(\"\\n\");\n            const parts = lines[1].split(/\\s+/); // second line, split on whitespace\n            const freeKb = parseInt(parts[3], 10); // 4th column is \"Available\"\n            return freeKb * 1024; // Convert to bytes\n        }\n    } catch (error) {\n        // Silently fail and return null\n        return null;\n    }\n}\n\n/**\n * Free / total bytes for the volume that holds `targetPath` (Node `fs.statfs`).\n * Returns null when the call is unavailable or fails.\n *\n * @param {string} targetPath\n * @returns {Promise<{ free: number, total: number, freeRatio: number } | null>}\n */\nexport async function getDiskUsage(targetPath) {\n    const fsPromises = await import(\"node:fs/promises\");\n    try {\n        let pathToCheck = targetPath;\n        if (!fs.existsSync(pathToCheck)) {\n            const parentDir = path.dirname(pathToCheck);\n            pathToCheck = fs.existsSync(parentDir)\n                ? parentDir\n                : process.platform === \"win32\"\n                  ? \"C:\\\\\"\n                  : \"/\";\n        }\n        if (typeof fsPromises.statfs !== \"function\") return null;\n        const stats = await fsPromises.statfs(pathToCheck);\n        const total = Number(stats.bsize) * Number(stats.blocks);\n        const free = Number(stats.bsize) * Number(stats.bavail);\n        if (!Number.isFinite(total) || total <= 0) return null;\n        return { free, total, freeRatio: free / total };\n    } catch {\n        return null;\n    }\n}\n\n","/**\n * Formatting Utilities\n * \n * Helper functions for converting between different data formats\n * and human-readable representations\n */\n\n/**\n * Convert bytes to human-readable format (e.g., \"1.5 MB\")\n */\nexport function bytesToHumanReadable(bytes) {\n    if (bytes === 0) return \"0 B\";\n    \n    const k = 1024;\n    const sizes = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\"];\n    const i = Math.floor(Math.log(bytes) / Math.log(k));\n    \n    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + \" \" + sizes[i];\n}\n\n/**\n * Convert human-readable format to bytes (e.g., \"1.5 MB\" -> 1572864)\n */\nexport function humanReadableToBytes(humanString) {\n    const units = {\n        \"B\": 1,\n        \"KB\": 1024,\n        \"MB\": 1024 * 1024,\n        \"GB\": 1024 * 1024 * 1024,\n        \"TB\": 1024 * 1024 * 1024 * 1024,\n        \"PB\": 1024 * 1024 * 1024 * 1024 * 1024,\n    };\n    \n    const match = humanString.trim().match(/^([\\d.]+)\\s*([A-Z]+)$/i);\n    if (!match) {\n        throw new Error(`Invalid format: ${humanString}. Expected format like \"2MB\" or \"1.5 GB\"`);\n    }\n    \n    const value = parseFloat(match[1]);\n    const unit = match[2].toUpperCase();\n    \n    if (!units[unit]) {\n        throw new Error(`Unknown unit: ${unit}. Supported units: ${Object.keys(units).join(\", \")}`);\n    }\n    \n    return Math.round(value * units[unit]);\n}\n\n","/**\n * Core lightweight utilities\n */\n\nexport function sleepMs(ms) {\n    return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function toJsonColumn(value) {\n    if (value === undefined || value === null) return null;\n    return JSON.stringify(value);\n}\n","import os from \"node:os\";\nimport { toJsonColumn } from \"../utils/index.js\";\nimport { queueToTableNames } from \"./taskUtils.js\";\n\n/**\n * Fail-fast accessor for `context.db`. The services-registry never lazy-inits the DB;\n * if it's missing, that's a caller wiring mistake.\n *\n * @param {object} context\n * @returns {Function}\n */\nfunction getDb(context) {\n    const db = context.db;\n    if (!db) {\n        throw new Error(\"Services registry requires context.db\");\n    }\n    return db;\n}\n\n/**\n * Decode a JSON column value into a plain object. Returns `{}` for nulls,\n * arrays, parse errors — callers never get `null`/`undefined` back so they can\n * safely spread the result.\n *\n * @param {unknown} value\n * @returns {Record<string, unknown>}\n */\nfunction parseMetadataColumn(value) {\n    if (!value) return {};\n    if (typeof value === \"object\" && !Array.isArray(value)) return value;\n    if (typeof value === \"string\") {\n        try {\n            const p = JSON.parse(value);\n            return p && typeof p === \"object\" && !Array.isArray(value) ? p : {};\n        } catch {\n            return {};\n        }\n    }\n    return {};\n}\n\n/**\n * Per-group max alive instances (0 = unlimited). Empty by default — product\n * apps inject their map via {@link setGroupMaxInstancesDefaults}.\n * An explicit `runnerGroupMaxInstances` override still wins.\n *\n * @type {Record<string, number>}\n */\nlet groupMaxInstancesDefaults = Object.create(null);\n\n/**\n * Replace the per-group instance-cap map. Keys are lowercased group names.\n * Pass `null` / omit to clear (every group unlimited unless overridden).\n *\n * @param {Record<string, number>|null|undefined} map\n */\nexport function setGroupMaxInstancesDefaults(map) {\n    const next = Object.create(null);\n    if (map && typeof map === \"object\") {\n        for (const [key, value] of Object.entries(map)) {\n            const g = String(key).trim().toLowerCase();\n            if (!g || !Number.isFinite(Number(value))) continue;\n            next[g] = Math.max(0, Math.floor(Number(value)));\n        }\n    }\n    groupMaxInstancesDefaults = next;\n}\n\n/**\n * Produce a DB-safe, human-readable name part: letters / digits / `._-` only,\n * trimmed and capped at 80 chars. Empty inputs fall back to `\"runner\"`.\n *\n * @param {unknown} raw\n * @returns {string}\n */\nfunction sanitizeNamePart(raw) {\n    const s = String(raw || \"\")\n        .trim()\n        .replace(/[^a-zA-Z0-9._-]+/g, \"-\")\n        .replace(/^-+|-+$/g, \"\");\n    return s.slice(0, 80) || \"runner\";\n}\n\n/**\n * How many alive instances are allowed in this group? Explicit `override` wins;\n * otherwise use the per-group default (lowercased group name). `0` = unlimited.\n *\n * @param {string} serviceGroup\n * @param {number|undefined} override\n * @returns {number}\n */\nfunction resolveMaxInstances(serviceGroup, override) {\n    if (override !== undefined && Number.isFinite(override)) {\n        return Math.max(0, Math.floor(Number(override)));\n    }\n    const g = serviceGroup.trim().toLowerCase();\n    return groupMaxInstancesDefaults[g] ?? 0;\n}\n\n/** @internal exported for tests */\nexport function resolveGroupMaxInstances(serviceGroup, override) {\n    return resolveMaxInstances(serviceGroup, override);\n}\n\n/**\n * Count rows in a group that have heartbeat'd within `staleMs`. Used to gate\n * `groupMaxInstances` at registration time.\n *\n * @param {Function} db knex instance.\n * @param {string} registryTable\n * @param {string} queueName\n * @param {string} serviceGroup\n * @param {number} staleMs\n * @param {string|undefined} excludeRowId When retrying, skip the row we're about to reuse.\n * @returns {Promise<number>}\n */\nasync function countAliveInGroup(\n    db,\n    registryTable,\n    queueName,\n    serviceGroup,\n    staleMs,\n    excludeRowId\n) {\n    const cutoff = new Date(Date.now() - staleMs);\n    let q = db(registryTable)\n        .where({ queue_name: queueName, service_group: serviceGroup })\n        .where(\"last_seen_at\", \">\", cutoff);\n    if (excludeRowId) {\n        q = q.whereNot(\"id\", excludeRowId);\n    }\n    const row = await q.count(\"id as count\").first();\n    return Number(row?.count ?? 0);\n}\n\n/**\n * Instance numbers currently held by *alive* rows (fresh last_seen).\n *\n * @param {Function} db\n * @param {string} registryTable\n * @param {string} queueName\n * @param {string} serviceGroup\n * @param {number} staleMs\n * @returns {Promise<Set<number>>}\n */\nasync function getOccupiedInstanceSlots(\n    db,\n    registryTable,\n    queueName,\n    serviceGroup,\n    staleMs\n) {\n    const cutoff = new Date(Date.now() - staleMs);\n    const rows = await db(registryTable)\n        .where({ queue_name: queueName, service_group: serviceGroup })\n        .where(\"last_seen_at\", \">\", cutoff)\n        .select(\"instance_number\");\n    const set = new Set();\n    for (const r of rows) {\n        const n = Number(r.instance_number);\n        if (Number.isFinite(n) && n >= 1) set.add(Math.floor(n));\n    }\n    return set;\n}\n\n/**\n * Best-effort detection of Postgres unique-constraint violations. Covers both\n * pg's `23505` SQLSTATE and drivers that only surface the error message.\n *\n * @param {unknown} error\n * @returns {boolean}\n */\nfunction isUniqueViolation(error) {\n    const code = error?.code ?? error?.errno;\n    return code === \"23505\" || String(error?.message || \"\").includes(\"duplicate key\");\n}\n\n/**\n * Package the `metadata` JSON column payload for a new/updated registry row.\n * Always carries `runnerTarget` when provided so read-side filters can see it\n * without decoding the whole blob.\n *\n * @param {{ metadata?: Record<string, unknown>, target?: string }} options\n * @returns {string|null}\n */\nfunction buildMetadata(options) {\n    const base = options.metadata && typeof options.metadata === \"object\" ? { ...options.metadata } : {};\n    if (options.target) {\n        base.runnerTarget = options.target;\n    }\n    return toJsonColumn(Object.keys(base).length ? base : null);\n}\n\n/**\n * Pick first free instance number: smallest n >= 1 with n ∉ occupied.\n * If explicit is set, use it only if not in occupied and within maxSlots (when > 0).\n *\n * @param {Set<number>} occupied\n * @param {number|undefined|null} explicit\n * @param {number|undefined} maxSlots\n * @returns {number}\n */\nfunction allocateInstanceNumber(occupied, explicit, maxSlots) {\n    if (explicit !== undefined && explicit !== null && Number.isFinite(Number(explicit))) {\n        const e = Math.max(1, Math.floor(Number(explicit)));\n        if (occupied.has(e)) {\n            throw new Error(`[services-registry] instance slot ${e} is already occupied by an alive peer`);\n        }\n        if (maxSlots !== undefined && maxSlots > 0 && e > maxSlots) {\n            throw new Error(`[services-registry] instance ${e} exceeds configured max slots ${maxSlots} for this group`);\n        }\n        return e;\n    }\n    const cap = maxSlots !== undefined && maxSlots > 0 ? maxSlots : 10_000;\n    for (let n = 1; n <= cap; n++) {\n        if (!occupied.has(n)) return n;\n    }\n    throw new Error(`[services-registry] no free instance slot (searched 1..${cap})`);\n}\n\n/**\n * Build a conventional `service_name` when the caller didn't pick one:\n * `<group>-<host>-<instance>`.\n *\n * @param {string} groupBase\n * @param {string} hostBase\n * @param {number} instanceNumber\n * @returns {string}\n */\nfunction defaultServiceName(groupBase, hostBase, instanceNumber) {\n    return `${groupBase}-${hostBase}-${instanceNumber}`;\n}\n\n/**\n * Register this process in `{queue}_services_registry` (no local identity files).\n * Allocates the first free instance number among *alive* peers, then inserts or takes over a stale row\n * with the same `service_name` when restarting on the same host/name pattern.\n *\n * @param {object} context\n * @param {{\n *   queueName: string,\n *   target?: string,\n *   serviceGroup: string,\n *   serviceName?: string,\n *   instanceNumber?: number|null,\n *   staleMs: number,\n *   groupMaxInstances?: number,\n *   enforceMaxInstances?: boolean,\n *   metadata?: Record<string, unknown>,\n * }} options\n * @returns {Promise<{\n *   serviceName: string,\n *   serviceGroup: string,\n *   queueName: string,\n *   target?: string,\n *   rowId: string,\n *   registryTable: string,\n *   instanceNumber: number,\n * }>}\n */\nexport async function registerInServicesRegistry(context, options) {\n    const db = getDb(context);\n    const registryTable = queueToTableNames(options.queueName).registryTable;\n    const serviceGroup = options.serviceGroup.trim();\n    if (!serviceGroup) {\n        throw new Error(\"registerInServicesRegistry: serviceGroup is required\");\n    }\n\n    const serverName = os.hostname();\n    const pid = typeof process.pid === \"number\" ? process.pid : null;\n    const meta = buildMetadata(options);\n    const groupBase = sanitizeNamePart(serviceGroup);\n    const hostBase = sanitizeNamePart(serverName);\n\n    const maxAllowed = resolveMaxInstances(serviceGroup, options.groupMaxInstances);\n    const aliveCount = await countAliveInGroup(db, registryTable, options.queueName, serviceGroup, options.staleMs, undefined);\n\n    if (maxAllowed > 0 && aliveCount >= maxAllowed) {\n        const msg = `[services-registry] group limit reached for \"${serviceGroup}\": ${aliveCount} alive (max ${maxAllowed}, queue=${options.queueName}).`;\n        if (options.enforceMaxInstances) {\n            throw new Error(msg);\n        }\n        context.logger.warn?.(`${msg} Starting anyway (runnerEnforceMaxInstances=false).`);\n    }\n\n    const maxSlots = maxAllowed > 0 ? maxAllowed : undefined;\n    const cutoff = new Date(Date.now() - options.staleMs);\n\n    const MAX_ATTEMPTS = 8;\n    for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {\n        const occupied = await getOccupiedInstanceSlots(db, registryTable, options.queueName, serviceGroup, options.staleMs);\n        const instanceNumber = allocateInstanceNumber(occupied, options.instanceNumber, maxSlots);\n\n        const serviceNameRaw = options.serviceName?.trim()\n            ? sanitizeNamePart(options.serviceName.trim())\n            : defaultServiceName(groupBase, hostBase, instanceNumber);\n\n        const existing = await db(registryTable)\n            .where({ queue_name: options.queueName, service_name: serviceNameRaw })\n            .first();\n\n        if (existing) {\n            const lastSeen = new Date(existing.last_seen_at);\n            const isAlive = !Number.isNaN(lastSeen.getTime()) && lastSeen > cutoff;\n\n            if (isAlive) {\n                if (options.serviceName?.trim()) {\n                    throw new Error(\n                        `[services-registry] service_name \"${serviceNameRaw}\" is already registered by an alive peer`\n                    );\n                }\n                context.logger.warn?.(\n                    `[services-registry] service_name \"${serviceNameRaw}\" already alive; retrying allocation (attempt ${attempt + 1})`\n                );\n                if (options.instanceNumber !== undefined && options.instanceNumber !== null) {\n                    throw new Error(\n                        `[services-registry] instance slot ${instanceNumber} / name \"${serviceNameRaw}\" is already held by an alive peer`\n                    );\n                }\n                await new Promise((r) => setTimeout(r, 50 + attempt * 30));\n                continue;\n            }\n\n            await db(registryTable)\n                .where({ id: existing.id })\n                .update({\n                    server_name: serverName,\n                    pid,\n                    metadata: meta,\n                    service_group: serviceGroup,\n                    instance_number: instanceNumber,\n                    last_seen_at: db.fn.now(),\n                });\n\n            const reg = {\n                serviceName: serviceNameRaw,\n                serviceGroup,\n                queueName: options.queueName,\n                target: options.target,\n                rowId: String(existing.id),\n                registryTable,\n                instanceNumber,\n            };\n            context.servicesRegistry = reg;\n            context.runnerHeartbeat = reg;\n\n            context.logger.info?.(\n                `[services-registry] took over stale row name=${serviceNameRaw} instance=${instanceNumber} group=${serviceGroup} queue=${options.queueName}`\n            );\n            return reg;\n        }\n\n        try {\n            const rows = await db(registryTable)\n                .insert({\n                    queue_name: options.queueName,\n                    service_group: serviceGroup,\n                    instance_number: instanceNumber,\n                    service_name: serviceNameRaw,\n                    server_name: serverName,\n                    pid,\n                    metadata: meta,\n                    last_seen_at: db.fn.now(),\n                    created_at: db.fn.now(),\n                })\n                .returning([\"id\", \"service_name\"]);\n\n            const row = Array.isArray(rows) ? rows[0] : rows;\n            let rowId = row && typeof row === \"object\" ? String(row.id ?? \"\") : \"\";\n            if (!rowId) {\n                const again = await db(registryTable)\n                    .where({ queue_name: options.queueName, service_name: serviceNameRaw })\n                    .first();\n                rowId = again?.id != null ? String(again.id) : \"\";\n            }\n            if (!rowId) continue;\n\n            const regNew = {\n                serviceName: String(row?.service_name ?? serviceNameRaw),\n                serviceGroup,\n                queueName: options.queueName,\n                target: options.target,\n                rowId,\n                registryTable,\n                instanceNumber,\n            };\n            context.servicesRegistry = regNew;\n            context.runnerHeartbeat = regNew;\n\n            context.logger.info?.(\n                `[services-registry] registered name=${regNew.serviceName} instance=${instanceNumber} group=${serviceGroup} queue=${options.queueName}`\n            );\n            return regNew;\n        } catch (error) {\n            if (!isUniqueViolation(error)) {\n                throw error;\n            }\n            context.logger.warn?.(`[services-registry] insert race on \"${serviceNameRaw}\", retrying (attempt ${attempt + 1})`);\n        }\n    }\n\n    throw new Error(\n        `[services-registry] could not allocate a registry row for group=${serviceGroup} queue=${options.queueName} after ${MAX_ATTEMPTS} attempts`\n    );\n}\n\n/**\n * Heartbeat: bump `last_seen_at`, refresh `server_name` / `pid` in case the\n * hostname rotates or the process PID changes (container restart in place).\n *\n * @param {object} context\n * @param {{ registryTable: string, rowId: string }} registration\n * @returns {Promise<void>}\n */\nexport async function touchServicesRegistry(context, registration) {\n    const db = getDb(context);\n    const serverName = os.hostname();\n    const pid = typeof process.pid === \"number\" ? process.pid : null;\n    await db(registration.registryTable)\n        .where({ id: registration.rowId })\n        .update({\n            last_seen_at: db.fn.now(),\n            server_name: serverName,\n            pid,\n        });\n}\n\n/**\n * Merge metadata (e.g. new allowedTasks / role) for this service row. Bumps last_seen_at.\n * Use when a service changes what it handles without restarting the process.\n *\n * @param {object} context\n * @param {{ registryTable: string, rowId: string, serviceName: string }} registration\n * @param {Record<string, unknown>} patch\n * @returns {Promise<void>}\n */\nexport async function updateServicesRegistryMetadata(context, registration, patch) {\n    const db = getDb(context);\n    const row = await db(registration.registryTable).where({ id: registration.rowId }).first();\n    const prev = parseMetadataColumn(row?.metadata);\n    const merged = { ...prev, ...patch };\n    await db(registration.registryTable)\n        .where({ id: registration.rowId })\n        .update({\n            metadata: toJsonColumn(merged),\n            last_seen_at: db.fn.now(),\n        });\n    context.logger.info?.(`[services-registry] metadata updated for ${registration.serviceName}`);\n}\n\n/**\n * Drop this process's registry row. Call on graceful shutdown so peers don't\n * have to wait for `staleMs` to reclaim the slot.\n *\n * @param {object} context\n * @param {{ registryTable: string, rowId: string, serviceName: string }} registration\n * @returns {Promise<void>}\n */\nexport async function unregisterServicesRegistry(context, registration) {\n    const db = getDb(context);\n    await db(registration.registryTable).where({ id: registration.rowId }).delete();\n    context.logger.info?.(`[services-registry] unregistered name=${registration.serviceName} id=${registration.rowId}`);\n}\n\n/**\n * List registry rows (optionally filter by queue / group). Rows with last_seen older than staleMs are excluded.\n *\n * @param {object} context\n * @param {{ queueName: string, staleMs?: number, serviceGroup?: string }} [options]\n * @returns {Promise<object[]>}\n */\nexport async function listServicesRegistry(context, options = { queueName: \"tasks\" }) {\n    const db = getDb(context);\n    const staleMs = options.staleMs ?? 60_000;\n    const cutoff = new Date(Date.now() - staleMs);\n    const table = queueToTableNames(options.queueName).registryTable;\n    let q = db(table).where(\"last_seen_at\", \">\", cutoff).orderBy([{ column: \"service_group\", order: \"asc\" }, { column: \"service_name\", order: \"asc\" }]);\n    if (options.serviceGroup?.trim()) {\n        q = q.where({ service_group: options.serviceGroup.trim() });\n    }\n    return await q;\n}\n","import { randomUUID } from \"node:crypto\";\nimport { toJsonColumn } from \"../utils/index.js\";\nimport { ensureSchema } from \"../db/ensure.js\";\nimport { nextTimeMatch } from \"./time-matcher.js\";\n\n/**\n * Fail-fast accessor for the knex instance on `context.db`. The tasks component\n * assumes the DB is already initialized by the caller — we don't lazy-init here,\n * so a missing `db` is a programming error, not a runtime condition.\n *\n * @param {object} context\n * @returns {Function} knex instance\n */\nfunction getDb(context) {\n    const db = context.db;\n    if (!db) {\n        throw new Error(\"Tasks component requires context.db. Initialize DB first and attach to context.\");\n    }\n    return db;\n}\n\n/**\n * Given a queue name, derive the three related table names the runtime uses:\n *\n *   - `tasksTable`     — active queue (rows that may still run)\n *   - `historyTable`   — append-only audit of completed attempts\n *   - `registryTable`  — live service/runner heartbeats for the queue\n *\n * @param {string} queueName\n * @returns {{ tasksTable: string, historyTable: string, registryTable: string }}\n */\nexport function queueToTableNames(queueName) {\n    return {\n        tasksTable: queueName,\n        historyTable: `${queueName}_history`,\n        registryTable: `${queueName}_services_registry`,\n    };\n}\n\n/**\n * Column set shared by the active queue and its history mirror, expressed as a\n * declarative spec (see db/ensure.js): each entry is one column, so\n * `ensureSchema` can create the whole table OR add just the columns an older\n * installation is missing — adding a field here is all a migration takes.\n *\n * @param {string} tableNameForIndex Used to name indexes uniquely per table.\n * @returns {import(\"../db/ensure.js\").TableSpec}\n */\nfunction tasksTableSpec(tableNameForIndex) {\n    return {\n        columns: {\n            id: (t, db) => t.uuid(\"id\").primary().defaultTo(db.raw(\"uuid_generate_v4()\")),\n            created_at: (t, db) => t.timestamp(\"created_at\").notNullable().defaultTo(db.fn.now()),\n            started_at: (t) => t.timestamp(\"started_at\"),\n            completed_at: (t) => t.timestamp(\"completed_at\"),\n            /*\n             * Priority: lower number = more urgent (0 first, default 50). Used when no\n             * row is due (`next_run_at` / `past_due`); due rows claim by earliest due.\n             */\n            priority: (t) => t.integer(\"priority\").notNullable().defaultTo(50),\n\n            schedule: (t) => t.text(\"schedule\"),\n            next_run_at: (t) => t.timestamp(\"next_run_at\").defaultTo(null),\n            past_due: (t) => t.timestamp(\"past_due\").defaultTo(null),\n\n            name: (t) => t.text(\"name\").notNullable(),\n            opid: (t) => t.text(\"opid\"),\n            params: (t) => t.jsonb(\"params\"),\n\n            // those are target identifiers, kind of who is going to run a task.\n            service_group: (t) => t.text(\"service_group\"), // harvester, loader, photos, ...\n            instance_number: (t) => t.integer(\"instance_number\"),\n            service_name: (t) => t.text(\"service_name\"), // that's a \"<server_name>_<service_group>_<instance_number>\"\n            server_name: (t) => t.text(\"server_name\"), // filled by runner when registering, auto.\n\n            status: (t) => t.text(\"status\").notNullable().defaultTo(\"idle\"), // idle, running, completed, failed, paused\n            status_changed_at: (t) => t.timestamp(\"status_changed_at\").defaultTo(null),\n\n            progress: (t) => t.text(\"progress\"),\n            success: (t) => t.boolean(\"success\"),\n            results: (t) => t.jsonb(\"results\"),\n        },\n        indexes: [\n            {\n                columns: [\"service_group\", \"status\", \"priority\", \"created_at\"],\n                name: `${tableNameForIndex}_claim_idx`,\n            },\n            { columns: [\"service_group\", \"name\"], name: `${tableNameForIndex}_group_name_idx` },\n            { columns: [\"completed_at\"], name: `${tableNameForIndex}_completed_at_idx` },\n            { columns: [\"name\", \"completed_at\"], name: `${tableNameForIndex}_name_completed_at_idx` },\n        ],\n    };\n}\n\n/**\n * Spec for the services registry table of a queue.\n *\n * @param {string} registryTable\n * @returns {import(\"../db/ensure.js\").TableSpec}\n */\nfunction registryTableSpec(registryTable) {\n    return {\n        columns: {\n            id: (t, db) => t.uuid(\"id\").primary().defaultTo(db.raw(\"uuid_generate_v4()\")),\n\n            queue_name: (t) => t.text(\"queue_name\").notNullable(),\n            service_group: (t) => t.text(\"service_group\").notNullable(), // harvester, loader, photos, ...\n            instance_number: (t) => t.integer(\"instance_number\").notNullable().defaultTo(1),\n            service_name: (t) => t.text(\"service_name\").notNullable(), // that's a \"<server_name>_<service_group>_<instance_number>\"\n            server_name: (t) => t.text(\"server_name\").notNullable(), // filled by runner when registering, auto.\n            pid: (t) => t.integer(\"pid\"),\n\n            metadata: (t) => t.json(\"metadata\"),\n\n            created_at: (t, db) => t.timestamp(\"created_at\").notNullable().defaultTo(db.fn.now()),\n            last_seen_at: (t, db) => t.timestamp(\"last_seen_at\").notNullable().defaultTo(db.fn.now()),\n        },\n        indexes: [\n            {\n                columns: [\"queue_name\", \"service_name\"],\n                name: `${registryTable}_queue_name_service_name_uniq`,\n                unique: true,\n            },\n            {\n                columns: [\"queue_name\", \"service_group\", \"last_seen_at\"],\n                name: `${registryTable}_queue_group_seen_idx`,\n            },\n            { columns: [\"queue_name\", \"last_seen_at\"], name: `${registryTable}_queue_seen_idx` },\n        ],\n        // TODO: a reference is needed - task_history entry should reference the registry entry, so that we can easily find all executed tasks for a given service and calculate the average workload or identify if there's a bottleneck. Also may be used for the load balancing.\n    };\n}\n\n/**\n * Full schema spec for one queue: active table + history mirror + registry.\n * Exported so callers (and tests) can feed it to `ensureSchema` /\n * `ensureSchemaEverywhere` directly.\n *\n * @param {string} [queueName]\n * @returns {import(\"../db/ensure.js\").SchemaSpec}\n */\nexport function tasksSchemaSpec(queueName = \"tasks\") {\n    const { tasksTable, historyTable, registryTable } = queueToTableNames(queueName);\n    return {\n        extensions: [\"uuid-ossp\"],\n        tables: {\n            [tasksTable]: tasksTableSpec(tasksTable),\n            [historyTable]: tasksTableSpec(historyTable),\n            [registryTable]: registryTableSpec(registryTable),\n        },\n    };\n}\n\n/**\n * Build an insert payload for `*_history`: never copies the queue row `id` as the history PK — PostgreSQL default\n * generates a new `id`. The snapshot still carries `name`, `opid`, `params`, etc. for auditing and ad hoc queries.\n *\n * When the queue row has no `opid`, we stamp `opid` with the queue row id so\n * {@link waitForTaskResult} can correlate history after the queue row is deleted\n * (history PK ≠ queue id). Explicit `opid` on the row or in `overrides` wins.\n *\n * @param {object} row      Original queue row.\n * @param {object} overrides Fields to override on the snapshot (e.g. `completed_at`, `success`).\n * @returns {object}\n */\nexport function taskHistoryInsertFromQueueRow(row, overrides = {}) {\n    const { id, ...snapshot } = row;\n    const opid =\n        overrides.opid !== undefined\n            ? overrides.opid\n            : snapshot.opid != null && String(snapshot.opid).trim() !== \"\"\n              ? snapshot.opid\n              : id;\n    return {\n        ...snapshot,\n        ...overrides,\n        opid,\n    };\n}\n\n/**\n * Idempotently make the three tables backing a queue (tasks / history /\n * registry) match the current spec — on one database or on many.\n *\n * Spec-driven (see {@link tasksSchemaSpec} + db/ensure.js), so this covers\n * BOTH cases: a missing table is created whole, and a table created by an\n * older version gets its missing columns/indexes added (never dropped or\n * altered in place).\n *\n * Multi-database: pass `databases: [handle, handle, ...]` (e.g. from\n * `Db.initAllSiblings(context, { prefix: \"src_\", includeMain: true })`) to\n * apply the same ensure to every database currently in use. Default stays\n * `context.db` only.\n *\n * Other options:\n *   - `recreate: true` — drop-and-recreate (dev/test only).\n *   - `dryRun: true`   — report the DDL it *would* run, change nothing.\n *\n * Requires the `uuid-ossp` extension; created on the fly if missing.\n *\n * @param {object} context\n * @param {{ queueName?: string, recreate?: boolean, dryRun?: boolean, databases?: Function[] }} [options]\n * @returns {Promise<void>}\n */\nexport async function ensureTaskTables(context, options = {}) {\n    const queueName = options.queueName ?? \"tasks\";\n    const recreate = options.recreate ?? false;\n    const dryRun = options.dryRun ?? false;\n    const databases = options.databases ?? [getDb(context)];\n    const log = context.logger ?? console;\n    const { tasksTable, historyTable, registryTable } = queueToTableNames(queueName);\n    const spec = tasksSchemaSpec(queueName);\n\n    for (const db of databases) {\n        const label = db?.config?.name ?? \"db\";\n\n        if (recreate) {\n            if (dryRun) {\n                log.info?.(\n                    `[tasks-schema] dryRun — ${label}: DROP TABLE IF EXISTS ${historyTable}, ${tasksTable}, ${registryTable}`,\n                );\n            } else {\n                await db.schema.dropTableIfExists(historyTable);\n                await db.schema.dropTableIfExists(tasksTable);\n                await db.schema.dropTableIfExists(registryTable);\n            }\n        }\n\n        const { actions } = await ensureSchema(db, spec, { dryRun, logger: context.logger });\n\n        // Older schemas had NOT NULL \"task\" (renamed to \"name\"). ensureSchema only\n        // adds columns, so a hybrid table breaks enqueueTask inserts into \"name\".\n        const legacyDrops = await dropLegacyTaskNameColumn(db, [tasksTable, historyTable], {\n            dryRun,\n            log,\n            label,\n        });\n\n        const allActions = [...actions, ...legacyDrops];\n        if (dryRun) {\n            if (allActions.length === 0) {\n                log.info?.(`[tasks-schema] dryRun — ${label}: queue \"${queueName}\" already up to date; no DDL`);\n            } else {\n                log.info?.(\n                    `[tasks-schema] dryRun — ${label}: would run ${allActions.length} statement(s) for queue \"${queueName}\":`,\n                );\n                for (const s of allActions) log.info?.(`  - ${s}`);\n            }\n        } else if (allActions.length > 0) {\n            log.info?.(\n                `[tasks-schema] ${label}: applied ${allActions.length} DDL statement(s) for queue \"${queueName}\"`,\n            );\n        }\n    }\n}\n\n/**\n * Drop legacy `task` text column when modern `name` is already present.\n * @returns {Promise<string[]>}\n */\nasync function dropLegacyTaskNameColumn(db, tableNames, { dryRun, log, label }) {\n    const actions = [];\n    for (const table of tableNames) {\n        if (!(await db.tableExists(table).catch(() => false))) continue;\n        const hasTask = await db.schema.hasColumn(table, \"task\");\n        const hasName = await db.schema.hasColumn(table, \"name\");\n        if (!hasTask || !hasName) continue;\n        const sql = `ALTER TABLE \"${table}\" DROP COLUMN IF EXISTS \"task\"`;\n        actions.push(sql);\n        if (dryRun) {\n            log?.info?.(`[tasks-schema] dryRun — ${label}: ${sql}`);\n        } else {\n            await db.raw(sql);\n            log?.info?.(`[tasks-schema] ${label}: dropped legacy column ${table}.task`);\n        }\n    }\n    return actions;\n}\n\n/**\n * Insert one task row into the queue. Supports targeting (service_group + optional\n * instance/server), recurring schedules (cron-like 6-field string, see `time-matcher.js`),\n * and explicit `nextRunAt` overrides.\n *\n * @param {object} context\n * @param {{\n *   queueName?: string,\n *   name?: string,\n *   task?: string,\n *   params?: unknown,\n *   opid?: string|null,\n *   priority?: number,\n *   schedule?: string|null,\n *   nextRunAt?: Date|string|number|null,\n *   serviceGroup?: string|null,\n *   instanceNumber?: number|null,\n *   serviceName?: string|null,\n *   serverName?: string|null,\n * }} options\n * @returns {Promise<string>} The new task's UUID.\n */\nexport async function enqueueTask(context, options) {\n    const db = getDb(context);\n    const queueName = options.queueName ?? \"tasks\";\n    const { tasksTable } = queueToTableNames(queueName);\n    const id = randomUUID();\n\n    const name = options.name ?? options.task;\n    if (!name) {\n        throw new Error(\"enqueueTask: name (or task) is required\");\n    }\n\n    const schedule = options.schedule?.trim() ? options.schedule : null;\n    let nextRunAt = null;\n    if (options.nextRunAt !== undefined) {\n        nextRunAt = options.nextRunAt == null ? null : new Date(options.nextRunAt);\n    } else if (schedule) {\n        nextRunAt = nextTimeMatch(schedule, new Date());\n    }\n\n    const row = {\n        id,\n        name,\n        params: toJsonColumn(options.params ?? null),\n        opid: options.opid ?? null,\n        priority: options.priority ?? 50,\n        schedule,\n        next_run_at: nextRunAt,\n        service_group: options.serviceGroup ?? null,\n        instance_number: options.instanceNumber ?? null,\n        service_name: options.serviceName ?? null,\n        server_name: options.serverName ?? null,\n        status: \"idle\",\n        status_changed_at: db.fn.now(),\n    };\n\n    // Hybrid DBs may still have legacy NOT NULL \"task\" until ensureTaskTables drops it.\n    if (await tableHasLegacyTaskColumn(db, tasksTable)) {\n        row.task = name;\n    }\n\n    await db(tasksTable).insert(row);\n    return id;\n}\n\n/** @type {Map<string, boolean>} */\nconst legacyTaskColumnCache = new Map();\n\nasync function tableHasLegacyTaskColumn(db, tableName) {\n    const key = `${db?.config?.name ?? \"db\"}:${tableName}`;\n    if (!legacyTaskColumnCache.has(key)) {\n        legacyTaskColumnCache.set(key, await db.schema.hasColumn(tableName, \"task\"));\n    }\n    return legacyTaskColumnCache.get(key);\n}\n\n/**\n * Update the `progress` column for one task. Strings go in verbatim; anything\n * else gets JSON-stringified so the column stays text-friendly.\n *\n * @param {object} context\n * @param {string} tasksTable\n * @param {string} taskId\n * @param {unknown} progress\n * @returns {Promise<void>}\n */\nexport async function updateTaskProgress(context, tasksTable, taskId, progress) {\n    const db = getDb(context);\n    await db(tasksTable).where({ id: taskId }).update({\n        progress: typeof progress === \"string\" ? progress : JSON.stringify(progress),\n    });\n}\n\n/**\n * Progress reporter for one running task: at most one in-flight UPDATE, with\n * the latest value coalesced. Prevents fire-and-forget per-photo writes from\n * saturating the Knex pool under high `maxParallel`.\n *\n * @param {object} context\n * @param {string} tasksTable\n * @param {string} taskId\n * @returns {(progress: unknown) => Promise<void>}\n */\nexport function createTaskProgressReporter(context, tasksTable, taskId) {\n    let pump = null;\n    let pending = undefined;\n    let hasPending = false;\n\n    return (progress) => {\n        pending = progress;\n        hasPending = true;\n        if (pump) return pump;\n\n        pump = (async () => {\n            try {\n                while (hasPending) {\n                    hasPending = false;\n                    const value = pending;\n                    try {\n                        await updateTaskProgress(context, tasksTable, taskId, value);\n                    } catch (err) {\n                        context.logger?.warn?.(\n                            `[tasks] progress update failed for ${taskId}: ${err?.message ?? err}`\n                        );\n                    }\n                }\n            } finally {\n                pump = null;\n            }\n        })();\n\n        return pump;\n    };\n}\n\n/** Optional product hook: `(row, { name, params }) => string|null`. */\nlet loggerTaskLabelResolver = null;\n\n/**\n * Inject a product-specific log-tag resolver (MLS leaf names, opid shapes, …).\n * The toolkit default is `params.logTask`, then `name:source`, then `name`.\n * Pass `null` to clear.\n *\n * @param {((row: object, parsed: { name: string, params: object|null }) => string|null|undefined)|null} fn\n */\nexport function setLoggerTaskLabelResolver(fn) {\n    loggerTaskLabelResolver = typeof fn === \"function\" ? fn : null;\n}\n\nfunction parseTaskParams(raw) {\n    if (raw && typeof raw === \"object\" && !Array.isArray(raw)) return raw;\n    if (typeof raw === \"string\") {\n        try {\n            const parsed = JSON.parse(raw);\n            if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) return parsed;\n        } catch {\n            /* ignore */\n        }\n    }\n    return null;\n}\n\n/**\n * Top-level task tag for logger lines (`name:source`).\n * Prefer `params.logTask` when a parent stamped the child row.\n * Product-specific leaf/opid mapping is an injected resolver, not toolkit logic.\n *\n * @param {object} [row]\n * @returns {string}\n */\nexport function loggerTaskLabel(row) {\n    const name = String(row?.name || \"task\").trim() || \"task\";\n    const params = parseTaskParams(row?.params);\n    const explicit = params?.logTask != null ? String(params.logTask).trim() : \"\";\n    if (explicit) return explicit;\n    if (loggerTaskLabelResolver) {\n        const extra = loggerTaskLabelResolver(row, { name, params });\n        if (extra != null && String(extra).trim()) return String(extra).trim();\n    }\n    const source = params?.source != null ? String(params.source).trim() : \"\";\n    if (source) return `${name}:${source}`;\n    return name;\n}\n","/**\n * Declarative, idempotent DDL — \"make sure this schema exists\" helpers.\n *\n * Components describe the schema they need (tables, columns, indexes,\n * extensions) once, as data; `ensureSchema` diffs that spec against a live\n * database and applies only what's missing:\n *\n *   - table missing            → CREATE TABLE with all columns + indexes\n *   - table there, column not  → ALTER TABLE ADD COLUMN (never drops/changes)\n *   - index/unique missing     → CREATE [UNIQUE] INDEX IF NOT EXISTS\n *   - extension missing        → CREATE EXTENSION IF NOT EXISTS\n *\n * Because the input is a spec (not imperative code), the same call can be\n * repeated over any number of databases — the main one and every sibling —\n * and each gets exactly the DDL it lacks. See Db.initSibling /\n * Db.discoverSiblings for getting those handles.\n *\n * Spec shape:\n *\n *   {\n *       extensions: [\"uuid-ossp\"],\n *       tables: {\n *           my_table: {\n *               columns: {\n *                   id:   (t, db) => t.uuid(\"id\").primary().defaultTo(db.raw(\"uuid_generate_v4()\")),\n *                   name: (t) => t.text(\"name\").notNullable(),\n *               },\n *               indexes: [\n *                   { columns: [\"name\"], name: \"my_table_name_idx\" },\n *                   { columns: [\"a\", \"b\"], name: \"my_table_ab_uniq\", unique: true },\n *               ],\n *           },\n *       },\n *   }\n *\n * Every function accepts `{ dryRun: true }` and then only *reports* what it\n * would do (returned in the report, logged when a logger is given) without\n * touching the database.\n */\n\n/** @typedef {{ columns: Record<string, Function>, indexes?: Array<{ columns: string[], name: string, unique?: boolean }> }} TableSpec */\n/** @typedef {{ extensions?: string[], tables?: Record<string, TableSpec> }} SchemaSpec */\n\nconst dbLabel = (db) => db?.config?.name ?? \"db\";\n\n/**\n * CREATE EXTENSION IF NOT EXISTS (PostgreSQL). No-op report entry on dryRun.\n *\n * @param {Function} db - a connected Db/knex handle\n * @param {string} name - extension name, e.g. \"uuid-ossp\"\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<{ action: string }>}\n */\nexport async function ensureExtension(db, name, options = {}) {\n    const action = `CREATE EXTENSION IF NOT EXISTS \"${name}\"`;\n    if (!options.dryRun) {\n        await db.raw(action);\n    }\n    options.logger?.silly?.(`[ensure] ${dbLabel(db)}: ${action}${options.dryRun ? \" (dryRun)\" : \"\"}`);\n    return { action };\n}\n\n/**\n * Create a table when missing; when it exists, add any missing columns and\n * indexes from the spec. Never drops or alters existing columns.\n *\n * @param {Function} db\n * @param {string} tableName\n * @param {TableSpec} spec\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<string[]>} human-readable list of applied (or planned) DDL\n */\nexport async function ensureTable(db, tableName, spec, options = {}) {\n    const { dryRun = false, logger } = options;\n    const actions = [];\n    const exists = await db.tableExists(tableName);\n\n    if (!exists) {\n        actions.push(`CREATE TABLE ${tableName} (${Object.keys(spec.columns).length} columns)`);\n        if (!dryRun) {\n            await db.schema.createTable(tableName, (t) => {\n                for (const define of Object.values(spec.columns)) {\n                    define(t, db);\n                }\n            });\n        }\n    } else {\n        // Column-level ensure: add whatever the spec has that the table lacks.\n        const missing = [];\n        for (const column of Object.keys(spec.columns)) {\n            if (!(await db.schema.hasColumn(tableName, column))) {\n                missing.push(column);\n            }\n        }\n        if (missing.length > 0) {\n            actions.push(`ALTER TABLE ${tableName} ADD COLUMN ${missing.join(\", \")}`);\n            if (!dryRun) {\n                await db.schema.alterTable(tableName, (t) => {\n                    for (const column of missing) {\n                        spec.columns[column](t, db);\n                    }\n                });\n            }\n        }\n    }\n\n    for (const index of spec.indexes ?? []) {\n        const indexActions = await ensureIndex(db, tableName, index, options);\n        actions.push(...indexActions);\n    }\n\n    for (const action of actions) {\n        logger?.silly?.(`[ensure] ${dbLabel(db)}: ${action}${dryRun ? \" (dryRun)\" : \"\"}`);\n    }\n    return actions;\n}\n\n/**\n * Ensure a (unique) index exists. On PostgreSQL this is a real existence check\n * (`CREATE [UNIQUE] INDEX IF NOT EXISTS`); other dialects fall back to\n * attempt-and-tolerate-\"already exists\".\n *\n * @param {Function} db\n * @param {string} tableName\n * @param {{ columns: string[], name: string, unique?: boolean }} index\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<string[]>}\n */\nexport async function ensureIndex(db, tableName, index, options = {}) {\n    const { dryRun = false } = options;\n    const kind = index.unique ? \"UNIQUE INDEX\" : \"INDEX\";\n    const cols = index.columns.map((c) => `\"${c}\"`).join(\", \");\n    const isPg = String(db?.config?.connectionString ?? \"\").startsWith(\"postgresql\");\n\n    if (isPg) {\n        const sql = `CREATE ${kind} IF NOT EXISTS \"${index.name}\" ON \"${tableName}\" (${cols})`;\n        const { rows } = await db.raw(`SELECT 1 FROM pg_indexes WHERE indexname = ?`, [index.name]);\n        if (rows.length > 0) return [];\n        if (!dryRun) await db.raw(sql);\n        return [sql];\n    }\n\n    // Non-pg fallback: try, and treat \"already exists\" as success.\n    const sql = `CREATE ${kind} ${index.name} ON ${tableName} (${cols})`;\n    if (!dryRun) {\n        try {\n            await db.raw(sql);\n        } catch (error) {\n            if (!/already exists|duplicate/i.test(error?.message ?? \"\")) throw error;\n            return [];\n        }\n    }\n    return [sql];\n}\n\n/**\n * Apply a full schema spec to ONE database. Returns the list of applied\n * (or, with dryRun, planned) DDL statements — empty when everything is\n * already in place.\n *\n * @param {Function} db\n * @param {SchemaSpec} spec\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<{ database: string, actions: string[] }>}\n */\nexport async function ensureSchema(db, spec, options = {}) {\n    const actions = [];\n    for (const extension of spec.extensions ?? []) {\n        // Extensions are cheap no-ops when present; report only in dryRun.\n        const { action } = await ensureExtension(db, extension, options);\n        if (options.dryRun) actions.push(action);\n    }\n    for (const [tableName, tableSpec] of Object.entries(spec.tables ?? {})) {\n        actions.push(...(await ensureTable(db, tableName, tableSpec, options)));\n    }\n    return { database: dbLabel(db), actions };\n}\n\n/**\n * Apply a schema spec to MANY databases (e.g. the main DB plus every sibling).\n * Convenience loop over {@link ensureSchema} with a combined report and\n * per-database info logging.\n *\n * @param {Function[]} dbs - connected handles (see Db.initAllSiblings)\n * @param {SchemaSpec} spec\n * @param {{ dryRun?: boolean, logger?: object }} [options]\n * @returns {Promise<Array<{ database: string, actions: string[] }>>}\n */\nexport async function ensureSchemaEverywhere(dbs, spec, options = {}) {\n    const reports = [];\n    for (const db of dbs) {\n        const report = await ensureSchema(db, spec, options);\n        if (report.actions.length > 0) {\n            options.logger?.info?.(\n                `[ensure] ${report.database}: ${options.dryRun ? \"would apply\" : \"applied\"} ${report.actions.length} DDL statement(s)`,\n            );\n        }\n        reports.push(report);\n    }\n    return reports;\n}\n","/**\n * 6-field cron-like matcher: `sec min hour day month weekday`.\n * Fields support `*`, numeric literals, ranges (`1-5`), comma lists (`0,15,30,45`),\n * and step expressions (`*\\/10`, `0-30/5`). No named months/weekdays, no\n * `L`/`#`/`?` magic — keep patterns explicit.\n */\n\n/** Field index → `\"lo-hi\"` range that `*` expands into. Order: sec, min, hour, day, month, weekday. */\nconst RANGES = [\"0-59\", \"0-59\", \"0-23\", \"1-31\", \"1-12\", \"0-6\"];\n\n/**\n * Replace `*` with a concrete `lo-hi` range so the rest of the pipeline only\n * has to deal with numeric forms.\n *\n * @param {string} field\n * @param {string} range e.g. `\"0-59\"`\n * @returns {string}\n */\nexport function resolveAsterisks(field, range) {\n    return field.includes(\"*\") ? field.replace(\"*\", range) : field;\n}\n\n/**\n * Expand every `lo-hi` run in `field` to the comma-separated list of integers it\n * covers. Handles reversed bounds (`5-2` → `2,3,4,5`). Does not handle steps;\n * run {@link resolveSteps} after this.\n *\n * @param {string} field\n * @returns {string}\n */\nexport function resolveRanges(field) {\n    const regex = /(\\d+)-(\\d+)/;\n    let current = field;\n    while (true) {\n        const match = regex.exec(current);\n        if (!match) break;\n        const raw = match[0];\n        let first = Number(match[1]);\n        let last = Number(match[2]);\n        if (last < first) {\n            [first, last] = [last, first];\n        }\n        const values = [];\n        for (let i = first; i <= last; i += 1) {\n            values.push(i);\n        }\n        current = current.replace(raw, values.join(\",\"));\n    }\n    return current;\n}\n\n/**\n * Apply a `.../step` suffix, keeping only values divisible by `step`.\n * Expects ranges to already be expanded to comma-lists. No-op when the suffix is missing.\n *\n * @param {string} field e.g. `\"0,1,2,...,59/10\"` → `\"0,10,20,30,40,50\"`\n * @returns {string}\n */\nexport function resolveSteps(field) {\n    const match = /^(.+)\\/(\\d+)$/.exec(field);\n    if (!match) return field;\n    const base = match[1];\n    const step = Number(match[2]);\n    if (!Number.isFinite(step) || step <= 0) return field;\n    return base\n        .split(\",\")\n        .map((v) => Number(v))\n        .filter((v) => Number.isFinite(v) && v % step === 0)\n        .join(\",\");\n}\n\n/**\n * Normalize a raw 6-field schedule string into an array of comma-separated integer\n * lists — one per field, ready for {@link matchesParsedPattern}.\n *\n * @param {string} pattern\n * @returns {string[]}\n * @throws If `pattern` does not contain exactly six whitespace-separated fields.\n */\nexport function convertPattern(pattern) {\n    const parts = pattern.trim().split(/\\s+/);\n    if (parts.length !== 6) {\n        throw new Error(`Invalid schedule \"${pattern}\". Expected 6 fields: sec min hour day month weekday`);\n    }\n    return parts\n        .map((field, idx) => resolveAsterisks(field, RANGES[idx]))\n        .map((field) => resolveRanges(field))\n        .map((field) => resolveSteps(field));\n}\n\n/**\n * Does `value` appear in the comma-list `field`?\n *\n * @param {string} field\n * @param {number} value\n * @returns {boolean}\n */\nfunction fieldMatches(field, value) {\n    const allowed = field.split(\",\").map((v) => Number(v));\n    return allowed.includes(value);\n}\n\n/**\n * Check an already-parsed pattern against a `Date`. All six fields must match\n * (month is 1-indexed here; weekday follows `Date#getDay`, 0 = Sunday).\n *\n * @param {string[]} parsed Output of {@link convertPattern}.\n * @param {Date} date\n * @returns {boolean}\n */\nexport function matchesParsedPattern(parsed, date) {\n    return (\n        fieldMatches(parsed[0], date.getSeconds()) &&\n        fieldMatches(parsed[1], date.getMinutes()) &&\n        fieldMatches(parsed[2], date.getHours()) &&\n        fieldMatches(parsed[3], date.getDate()) &&\n        fieldMatches(parsed[4], date.getMonth() + 1) &&\n        fieldMatches(parsed[5], date.getDay())\n    );\n}\n\n/**\n * One-shot check: does `pattern` match `date`? Parses the pattern each call —\n * fine for the runner loop where we only test one date per tick; use\n * {@link convertPattern} + {@link matchesParsedPattern} if you need to test\n * many dates against the same schedule.\n *\n * @param {string} pattern\n * @param {Date} [date]\n * @returns {boolean}\n */\nexport function timeMatcher(pattern, date = new Date()) {\n    const parsed = convertPattern(pattern);\n    return matchesParsedPattern(parsed, date);\n}\n\nconst MS_PER_SECOND = 1000;\nconst DEFAULT_SEARCH_HORIZON_MS = 10 * 365 * 24 * 60 * 60 * MS_PER_SECOND;\n\n/**\n * Earliest calendar second strictly after `from` where the schedule matches.\n * Use this to sleep until the next run instead of polling `timeMatcher` and risking missed seconds.\n *\n * @param {string} pattern Same 6-field format as `timeMatcher`: `sec min hour day month weekday`\n * @param {Date} [from=new Date()] Reference instant. Matching is second-granularity; search starts at the next second after `from`.\n * @param {number} [maxSearchMs] Abort if no match within this window (default ~10 years).\n * @returns {Date}\n */\nexport function nextTimeMatch(\n    pattern,\n    from = new Date(),\n    maxSearchMs = DEFAULT_SEARCH_HORIZON_MS\n) {\n    const parsed = convertPattern(pattern);\n    let t = Math.ceil((from.getTime() + 1) / MS_PER_SECOND) * MS_PER_SECOND;\n    const end = t + maxSearchMs;\n    while (t <= end) {\n        const date = new Date(t);\n        if (matchesParsedPattern(parsed, date)) {\n            return date;\n        }\n        t += MS_PER_SECOND;\n    }\n    throw new Error(\n        `nextTimeMatch: no match for \"${pattern}\" within ${maxSearchMs}ms after ${from.toISOString()}`\n    );\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { FileDatabase } from \"../filedatabase/index.js\";\nimport { isTimestampFolder } from \"../utils/date-utils.js\";\n\n/**\n * Gets or lazily builds the default IPC-logs FileDatabase state, cached on\n * `context.__tasksLogsState`. Reads `tasksLogs*` params (basePath, namespace,\n * table, errorTable, enabled, maxVersions, pageSize). When `tasksLogsEnabled=false`\n * the main `db` is null but `errorDb` still captures error payloads.\n *\n * @param {object} context\n * @returns {object} `{ db, errorDb, queue, initialized, errorInitialized }`\n */\nfunction getLogsState(context) {\n    const holder = context;\n    if (holder.__tasksLogsState) return holder.__tasksLogsState;\n\n    const basePath = holder.params?.get?.(\"tasksLogsBasePath\") || \"./data\";\n    const namespace = holder.params?.get?.(\"tasksLogsNamespace\") || \"tasks-logs\";\n    const tableName = holder.params?.get?.(\"tasksLogsTable\") || \"runner\";\n    const errorTableName = holder.params?.get?.(\"tasksErrorLogsTable\") || `${tableName}-errors`;\n    const maxVersionsRaw = Number(holder.params?.get?.(\"tasksLogsMaxVersions\"));\n    const pageSizeRaw = Number(holder.params?.get?.(\"tasksLogsPageSize\"));\n\n    const errorDb = new FileDatabase({\n        basePath,\n        namespace,\n        tableName: errorTableName,\n        versioned: true,\n        useMetadata: true,\n        maxVersions: Number.isFinite(maxVersionsRaw) && maxVersionsRaw > 0 ? maxVersionsRaw : 20,\n        pageSize: Number.isFinite(pageSizeRaw) && pageSizeRaw > 0 ? pageSizeRaw : 2000,\n        logger: holder.logger,\n    });\n\n    const enabledRaw = holder.params?.get?.(\"tasksLogsEnabled\");\n    const enabled = enabledRaw === undefined ? true : !!enabledRaw;\n    if (!enabled) {\n        const disabledState = {\n            db: null,\n            errorDb,\n            queue: Promise.resolve(),\n            initialized: true,\n            errorInitialized: false,\n        };\n        holder.__tasksLogsState = disabledState;\n        return disabledState;\n    }\n\n    const db = new FileDatabase({\n        basePath,\n        namespace,\n        tableName,\n        versioned: true,\n        useMetadata: true,\n        maxVersions: Number.isFinite(maxVersionsRaw) && maxVersionsRaw > 0 ? maxVersionsRaw : 20,\n        pageSize: Number.isFinite(pageSizeRaw) && pageSizeRaw > 0 ? pageSizeRaw : 2000,\n        logger: holder.logger,\n    });\n    const state = {\n        db,\n        errorDb,\n        queue: Promise.resolve(),\n        initialized: false,\n        errorInitialized: false,\n    };\n    holder.__tasksLogsState = state;\n    return state;\n}\n\n/**\n * Cache key for a target so multiple writers sharing the same\n * `basePath`/`namespace`/`tableName` reuse one FileDatabase state\n * (see `getLogsStateForTarget`).\n *\n * @param {object} target `{ basePath?, namespace?, tableName }`\n * @returns {string}\n */\nfunction ipcLogTargetKey(target) {\n    const bp = target.basePath ?? \"\";\n    const ns = target.namespace ?? \"\";\n    return `${bp}::${ns}::${target.tableName}`;\n}\n\n/**\n * Produce a FileDatabase `tableName` of the form `source/resource`, sanitizing each\n * segment so only `[a-zA-Z0-9._-]` survive. Empty segments fall back to `\"x\"`.\n *\n * @param {string} source\n * @param {string} resource\n * @returns {string} e.g. `\"actris/properties\"`\n */\nexport function ipcFileLogsTableNameForSourceResource(source, resource) {\n    const seg = (s) => {\n        const t = String(s).trim().replace(/[^a-zA-Z0-9._-]+/g, \"_\").replace(/^_+|_+$/g, \"\");\n        return t.length ? t : \"x\";\n    };\n    return `${seg(source)}/${seg(resource)}`;\n}\n\n/**\n * Read IPC log records from the latest FileDatabase version for `source/resource`.\n * Intended for tailing / incremental polling — use the returned `latestTs` as the\n * next call's `afterTs`.\n *\n * @param {object} context\n * @param {object} options\n * @param {string} options.source\n * @param {string} options.resource\n * @param {number} [options.tail=100]     Max records returned after filtering (clamped 1..10000).\n * @param {string|null} [options.afterTs] ISO timestamp watermark; keeps rows with `ts > afterTs`.\n * @param {string|null} [options.fromTs]  Inclusive lower bound (`ts >= fromTs`).\n * @param {string|null} [options.toTs]    Inclusive upper bound (`ts <= toTs`).\n * @param {string|null} [options.taskId]  Keep only rows stamped with this task id.\n * @returns {Promise<{ records: object[], latestTs: string|null }>}\n */\nexport function filterIpcLogRecords(records, { afterTs, fromTs, toTs, taskId } = {}) {\n    const after = afterTs && String(afterTs).trim() ? String(afterTs).trim() : \"\";\n    const from = fromTs && String(fromTs).trim() ? String(fromTs).trim() : \"\";\n    const to = toTs && String(toTs).trim() ? String(toTs).trim() : \"\";\n    const id = taskId != null && String(taskId).trim() ? String(taskId).trim() : \"\";\n    return (Array.isArray(records) ? records : []).filter((r) => {\n        if (!r || typeof r.ts !== \"string\") return false;\n        const ts = String(r.ts);\n        if (after && !(ts > after)) return false;\n        if (from && ts < from) return false;\n        if (to && ts > to) return false;\n        if (id && String(r.taskId ?? \"\") !== id) return false;\n        return true;\n    });\n}\n\nfunction latestIpcRecordTs(records) {\n    let latestTs = null;\n    for (const r of records ?? []) {\n        const ts = typeof r?.ts === \"string\" ? String(r.ts) : null;\n        if (ts && (!latestTs || ts > latestTs)) latestTs = ts;\n    }\n    return latestTs;\n}\n\nexport async function readTaskIpcLogsSnapshot(context, options) {\n    const holder = context;\n    const basePath = holder.params?.get?.(\"tasksLogsBasePath\") ?? \"./data\";\n    const namespace = holder.params?.get?.(\"tasksLogsNamespace\") ?? \"tasks-logs\";\n    const tableName = ipcFileLogsTableNameForSourceResource(options.source, options.resource);\n    const tail = Math.max(1, Math.min(10_000, Number(options.tail) > 0 ? Number(options.tail) : 100));\n    const fromTs = options.fromTs && String(options.fromTs).trim() ? String(options.fromTs).trim() : \"\";\n    const toTs = options.toTs && String(options.toTs).trim() ? String(options.toTs).trim() : \"\";\n    const wantsWindow = !!(fromTs || toTs);\n\n    const fd = new FileDatabase({\n        basePath,\n        namespace,\n        tableName,\n        versioned: true,\n        useMetadata: true,\n        maxVersions: 30,\n        pageSize: 2000,\n        logger: holder.logger,\n    });\n\n    const versions = await fd.getVersions();\n    if (versions.length === 0) {\n        return { records: [], latestTs: null };\n    }\n\n    const versionsToRead = wantsWindow ? [...versions].reverse() : [versions[versions.length - 1]];\n    const collected = [];\n    for (const version of versionsToRead) {\n        const { records: arr } = await readIpcLogVersion(fd, version, holder.logger, tableName);\n        appendItems(collected, arr);\n        if (!wantsWindow) break;\n        if (fromTs) {\n            let minTs = null;\n            for (const r of arr) {\n                const ts = typeof r?.ts === \"string\" ? r.ts : null;\n                if (ts && (!minTs || ts < minTs)) minTs = ts;\n            }\n            if (minTs && minTs <= fromTs) break;\n        }\n    }\n\n    const filtered = filterIpcLogRecords(collected, {\n        afterTs: options.afterTs,\n        fromTs,\n        toTs,\n        taskId: options.taskId,\n    });\n    filtered.sort((a, b) => String(a?.ts ?? \"\").localeCompare(String(b?.ts ?? \"\")));\n\n    /** Watermark for incremental fetches: max `ts` among all matching rows, not only the returned tail. */\n    const latestTs = latestIpcRecordTs(filtered);\n\n    const incremental = !!(options.afterTs && String(options.afterTs).trim());\n    /** Incremental polls may return many lines between ticks — cap at 10k so we do not drop rows then advance `latestTs` past them. */\n    const maxReturn = incremental || wantsWindow ? 10_000 : tail;\n    const sliced = filtered.length > maxReturn ? filtered.slice(-maxReturn) : filtered;\n\n    return { records: sliced, latestTs };\n}\n\n/**\n * Absolute path to the FileDatabase table directory for a given target (matches the\n * FileDatabase on-disk layout). Versioned writes create timestamp subfolders inside.\n *\n * @param {object} context\n * @param {object} target `{ basePath?, namespace?, tableName }`\n * @returns {string}\n */\nexport function resolveIpcFileLogsDir(context, target) {\n    const holder = context;\n    const basePath = target.basePath ?? (holder.params?.get?.(\"tasksLogsBasePath\") || \"./data\");\n    const namespace = target.namespace ?? (holder.params?.get?.(\"tasksLogsNamespace\") || \"tasks-logs\");\n    const segments = target.tableName.split(\"/\").filter(Boolean);\n    return path.resolve(basePath, namespace, ...segments);\n}\n\n/**\n * Lazily build a FileDatabase state for the given target, memoized on\n * `context.__tasksLogsTargetStates` (Map keyed by `ipcLogTargetKey`).\n * Returns `null` when `tasksLogsEnabled=false`.\n *\n * @param {object} context\n * @param {object} target `{ basePath?, namespace?, tableName }`\n * @returns {object|null} same shape as `getLogsState`, but `errorDb` is always null.\n */\nfunction getLogsStateForTarget(context, target) {\n    const holder = context;\n    const enabledRaw = holder.params?.get?.(\"tasksLogsEnabled\");\n    const enabled = enabledRaw === undefined ? true : !!enabledRaw;\n    if (!enabled) return null;\n\n    if (!holder.__tasksLogsTargetStates) holder.__tasksLogsTargetStates = new Map();\n    const map = holder.__tasksLogsTargetStates;\n    const key = ipcLogTargetKey(target);\n    if (map.has(key)) return map.get(key);\n\n    const basePath = target.basePath ?? (holder.params?.get?.(\"tasksLogsBasePath\") || \"./data\");\n    const namespace = target.namespace ?? (holder.params?.get?.(\"tasksLogsNamespace\") || \"tasks-logs\");\n    const maxVersionsRaw = Number(holder.params?.get?.(\"tasksLogsMaxVersions\"));\n    const pageSizeRaw = Number(holder.params?.get?.(\"tasksLogsPageSize\"));\n\n    const db = new FileDatabase({\n        basePath,\n        namespace,\n        tableName: target.tableName,\n        versioned: true,\n        useMetadata: true,\n        maxVersions: Number.isFinite(maxVersionsRaw) && maxVersionsRaw > 0 ? maxVersionsRaw : 20,\n        pageSize: Number.isFinite(pageSizeRaw) && pageSizeRaw > 0 ? pageSizeRaw : 2000,\n        logger: holder.logger,\n    });\n    const state = {\n        db,\n        errorDb: null,\n        queue: Promise.resolve(),\n        initialized: false,\n        errorInitialized: false,\n    };\n    map.set(key, state);\n    return state;\n}\n\n/**\n * Heuristic: does this IPC payload represent an error?\n *   - object with `level` of `\"error\"`/`\"fatal\"`, OR\n *   - object with a `message` string containing the word \"error\", OR\n *   - plain string containing \"error\" (case-insensitive).\n *\n * @param {unknown} payload\n * @returns {boolean}\n */\nfunction isErrorPayload(payload) {\n    if (!payload) return false;\n    if (typeof payload === \"object\") {\n        const level = typeof payload.level === \"string\" ? payload.level.toLowerCase() : \"\";\n        if (level === \"error\" || level === \"fatal\") return true;\n        if (typeof payload.message === \"string\" && /\\berror\\b/i.test(payload.message)) return true;\n        return false;\n    }\n    if (typeof payload === \"string\") {\n        return /\\berror\\b/i.test(payload);\n    }\n    return false;\n}\n\n/**\n * Build the persisted log record for an IPC payload. Copies `source`/`resource` from\n * `task.params` when present so logs stay queryable by them later.\n *\n * @param {object} task\n * @param {unknown} payload\n * @returns {object} `{ ts, opid, taskId, taskName, target, source, resource, payload }`\n */\nfunction buildLogRecord(task, payload) {\n    const params = task.params && typeof task.params === \"object\" ? task.params : {};\n    return {\n        ts: new Date().toISOString(),\n        opid: task.opid ?? null,\n        taskId: task.id,\n        taskName: task.name,\n        target: task.service_group,\n        source: typeof params.source === \"string\" ? params.source : null,\n        resource: typeof params.resource === \"string\" ? params.resource : null,\n        payload,\n    };\n}\n\n/**\n * Append one IPC log line from a child worker. Never throws; writes are serialized\n * per-state on a promise queue (drain with `flushTaskIpcLogs`).\n *\n *   - Without `target`: writes to the default store (`tasksLogsTable`, usually `runner`)\n *     and, when the payload looks like an error, also to `tasksErrorLogsTable`.\n *   - With `target`: writes only to that target's store (e.g. per source/resource,\n *     later read by `readTaskIpcLogsSnapshot`).\n *\n * @param {object} context\n * @param {object} task\n * @param {unknown} payload\n * @param {object} [target] `{ basePath?, namespace?, tableName }`\n * @returns {void}\n */\nexport function appendTaskIpcLog(context, task, payload, target) {\n    if (target) {\n        const state = getLogsStateForTarget(context, target);\n        if (!state?.db) return;\n        const record = buildLogRecord(task, payload);\n        state.queue = state.queue\n            .then(async () => {\n                await state.db.write([record], { forceNewVersion: !state.initialized });\n                state.initialized = true;\n            })\n            .catch((error) => {\n                context.logger.warn?.(\"[tasks] failed to persist IPC log entry (targeted):\", error);\n            });\n        return;\n    }\n\n    const state = getLogsState(context);\n    if (!state.db && !state.errorDb) return;\n\n    const record = buildLogRecord(task, payload);\n    state.queue = state.queue\n        .then(async () => {\n            if (state.db) {\n                await state.db.write([record], { forceNewVersion: !state.initialized });\n                state.initialized = true;\n            }\n            if (state.errorDb && isErrorPayload(payload)) {\n                await state.errorDb.write([record], { forceNewVersion: !state.errorInitialized });\n                state.errorInitialized = true;\n            }\n        })\n        .catch((error) => {\n            context.logger.warn?.(\"[tasks] failed to persist IPC log entry:\", error);\n        });\n}\n\n/**\n * Await pending FileDatabase writes from task IPC logging (default store + every\n * per-target store). Does not close anything; subsequent appends continue to work.\n *\n * @param {object} context\n * @returns {Promise<void>}\n */\nexport async function flushTaskIpcLogs(context) {\n    const holder = context;\n    const promises = [];\n    if (holder.__tasksLogsState?.queue) promises.push(holder.__tasksLogsState.queue);\n    const map = holder.__tasksLogsTargetStates;\n    if (map) {\n        for (const s of map.values()) {\n            if (s.queue) promises.push(s.queue);\n        }\n    }\n    await Promise.all(promises);\n}\n\nexport function tasksLogsRoot(context) {\n    const holder = context ?? {};\n    const basePath = holder.params?.get?.(\"tasksLogsBasePath\") || \"./data\";\n    const namespace = holder.params?.get?.(\"tasksLogsNamespace\") || \"tasks-logs\";\n    return path.resolve(basePath, namespace);\n}\n\n/**\n * `arr.push(...items)` throws Maximum call stack size exceeded on large items.\n * @param {unknown[]} target\n * @param {unknown[]} items\n */\nexport function appendItems(target, items) {\n    if (!items?.length) return target;\n    for (let i = 0; i < items.length; i++) target.push(items[i]);\n    return target;\n}\n\n/**\n * Decide what to drop / rewrite for one IPC table.\n * @param {{ version: string, records: object[], missingChunks?: number }[]} versions\n * @param {string} cutoff ISO\n */\nexport function planIpcLogPrune(versions, cutoff) {\n    const cut = String(cutoff);\n    const kept = [];\n    const deleteVersions = [];\n    let dropped = 0;\n    let needsRewrite = false;\n    for (const { version, records, missingChunks } of versions ?? []) {\n        const arr = Array.isArray(records) ? records : [];\n        const live = arr.filter((r) => typeof r?.ts === \"string\" && r.ts >= cut);\n        dropped += arr.length - live.length;\n        appendItems(kept, live);\n        if (live.length === 0) deleteVersions.push(version);\n        else if (live.length < arr.length || Number(missingChunks) > 0) needsRewrite = true;\n    }\n    return {\n        kept,\n        dropped,\n        deleteVersions,\n        rewrite: needsRewrite,\n        deleteAll: kept.length === 0 && (versions?.length ?? 0) > 0,\n    };\n}\n\nasync function listIpcLogTableNames(root) {\n    const tables = [];\n    const walk = async (dir, prefix) => {\n        let entries;\n        try {\n            entries = await fs.readdir(dir, { withFileTypes: true });\n        } catch {\n            return;\n        }\n        const versionDirs = entries.filter((e) => e.isDirectory() && isTimestampFolder(e.name));\n        if (versionDirs.length && prefix) {\n            tables.push(prefix);\n            return;\n        }\n        for (const e of entries) {\n            if (!e.isDirectory() || isTimestampFolder(e.name)) continue;\n            const next = prefix ? `${prefix}/${e.name}` : e.name;\n            await walk(path.join(dir, e.name), next);\n        }\n    };\n    await walk(root, \"\");\n    return tables;\n}\n\nasync function removeVersionDir(tableDir, version) {\n    await fs.rm(path.join(tableDir, version), { recursive: true, force: true });\n}\n\n/** Live writes are in-place; do not delete a file that may still be flushing. */\nconst UNREADABLE_IPC_LOG_GRACE_MS = 10_000;\n\nfunction ipcLogBrokenFileName(message) {\n    const m = String(message ?? \"\").match(/Failed to read file ([^:]+):/i);\n    const name = m?.[1]?.trim() ?? \"\";\n    if (!name || name.includes(\"/\") || name.includes(\"\\\\\") || name.includes(\"..\")) return null;\n    return name;\n}\n\n/**\n * Drop a truncated / unparseable IPC chunk (or the whole version if we cannot\n * name the file). Returns what was removed, or null when the file is too new.\n */\nasync function removeUnreadableIpcLog(fd, version, message) {\n    const dest = fd.getDestinationPath(version);\n    const fileName = ipcLogBrokenFileName(message);\n    const target = fileName ? path.join(dest, fileName) : dest;\n    try {\n        const st = await fs.stat(target);\n        if (Date.now() - Number(st.mtimeMs) < UNREADABLE_IPC_LOG_GRACE_MS) return null;\n    } catch {\n        return null;\n    }\n    if (fileName) {\n        await fs.rm(target, { force: true });\n        let leftover = [];\n        try {\n            leftover = (await fs.readdir(dest)).filter((n) => n !== \"metadata.json\" && !n.startsWith(\".\"));\n        } catch {\n            leftover = [];\n        }\n        if (leftover.length === 0) {\n            await fs.rm(dest, { recursive: true, force: true });\n            return `${version}/${fileName}`;\n        }\n        return fileName;\n    }\n    await fs.rm(dest, { recursive: true, force: true });\n    return version;\n}\n\nasync function readIpcLogVersion(fd, version, logger, tableName) {\n    try {\n        fd.lastReadMissingFiles = [];\n        const raw = await fd.read({ version });\n        const missingChunks = Array.isArray(fd.lastReadMissingFiles) ? fd.lastReadMissingFiles.length : 0;\n        return { version, records: Array.isArray(raw) ? raw : [], missingChunks };\n    } catch (err) {\n        const msg = err?.message ?? String(err);\n        let removed = null;\n        try {\n            removed = await removeUnreadableIpcLog(fd, version, msg);\n        } catch {\n            /* still skip this poll */\n        }\n        logger?.warn?.(\n            `[tasks-logs] ${removed ? \"deleted\" : \"skipping\"} unreadable IPC log ${tableName}/${version}: ${msg}`,\n        );\n        return { version, records: [], missingChunks: 0 };\n    }\n}\n\nasync function compactIpcLogTable(context, tableName, cutoff) {\n    const holder = context;\n    const basePath = holder.params?.get?.(\"tasksLogsBasePath\") || \"./data\";\n    const namespace = holder.params?.get?.(\"tasksLogsNamespace\") || \"tasks-logs\";\n    const fd = new FileDatabase({\n        basePath,\n        namespace,\n        tableName,\n        versioned: true,\n        useMetadata: true,\n        maxVersions: 30,\n        pageSize: 2000,\n        logger: holder.logger,\n    });\n    const versions = await fd.getVersions();\n    if (versions.length === 0) return { table: tableName, dropped: 0, deletedVersions: 0 };\n\n    const loaded = [];\n    for (const version of versions) {\n        loaded.push(await readIpcLogVersion(fd, version, holder.logger, tableName));\n    }\n    const plan = planIpcLogPrune(loaded, cutoff);\n    const tableDir = resolveIpcFileLogsDir(context, { tableName, basePath, namespace });\n\n    if (plan.deleteAll) {\n        for (const version of versions) await removeVersionDir(tableDir, version);\n        return { table: tableName, dropped: plan.dropped, deletedVersions: versions.length };\n    }\n\n    if (plan.rewrite) {\n        await fd.write(plan.kept, { forceNewVersion: true });\n        const keep = fd.currentVersion;\n        for (const version of await fd.getVersions()) {\n            if (version !== keep) await removeVersionDir(tableDir, version);\n        }\n        return { table: tableName, dropped: plan.dropped, deletedVersions: versions.length, rewritten: true };\n    }\n\n    for (const version of plan.deleteVersions) await removeVersionDir(tableDir, version);\n    return { table: tableName, dropped: plan.dropped, deletedVersions: plan.deleteVersions.length };\n}\n\nfunction invalidateIpcLogWriter(context, tableName) {\n    const holder = context;\n    holder.__tasksLogsTargetStates?.delete(ipcLogTargetKey({ tableName }));\n    const defaultTable = holder.params?.get?.(\"tasksLogsTable\") || \"runner\";\n    if (tableName === defaultTable) holder.__tasksLogsState = undefined;\n}\n\nfunction enqueueOnLogQueue(context, tableName, work) {\n    const state = getLogsStateForTarget(context, { tableName });\n    if (!state) return work();\n    const done = state.queue.then(work, work);\n    state.queue = done.catch(() => {});\n    return done;\n}\n\n/**\n * Drop IPC FileDatabase records older than `cutoff` (all tables under the logs namespace).\n *\n * @param {object} context\n * @param {string} cutoff ISO\n * @param {{ isStop?: () => boolean }} [opts]\n * @returns {Promise<{ tables: number, dropped: number, details: object[] }>}\n */\nexport async function pruneIpcLogsOlderThan(context, cutoff, opts = {}) {\n    const isStop = typeof opts.isStop === \"function\" ? opts.isStop : () => false;\n    const root = tasksLogsRoot(context);\n    const tables = await listIpcLogTableNames(root);\n    const details = [];\n    let dropped = 0;\n    for (const tableName of tables) {\n        if (isStop()) break;\n        try {\n            const out = await enqueueOnLogQueue(context, tableName, () =>\n                compactIpcLogTable(context, tableName, cutoff),\n            );\n            invalidateIpcLogWriter(context, tableName);\n            details.push(out);\n            dropped += Number(out?.dropped) || 0;\n        } catch (err) {\n            context?.logger?.warn?.(\n                `[tasks-retention] prune table ${tableName} failed: ${err?.message ?? err}`,\n            );\n            details.push({ table: tableName, dropped: 0, error: err?.message ?? String(err) });\n        }\n    }\n    return { tables: details.length, dropped, details };\n}\n","/**\n * FileDatabase - Versioned, file-based data storage system\n * \n * Provides organized file storage with:\n * - Timestamp-based versioning\n * - Chunked/paginated file writes for large datasets\n * - Metadata tracking\n * - Backward compatibility with legacy structures\n * - Multiple storage modes (versioned, catalog, logs)\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { ensurePath, getFileExtension, getFreeDiskSpace, bytesToHumanReadable, isTimestampFolder } from \"./utils.js\";\nimport { detectDataType, serializeData, deserializeData } from \"./serializers.js\";\nimport { ParamError, FileDatabaseError } from \"../errors.js\";\n\nexport { FileDatabaseError };\n\nexport class FileDatabase {\n    basePath;\n    namespace;\n    tableName = null;\n    versioned;\n    maxVersions;\n    pageSize;\n    useMetadata;\n    freeSpaceThreshold;\n    logger;\n\n    // Current operation state\n    currentVersion = null;\n    currentVersionFolder = null;\n    currentFileNumber = 0;\n    currentRecord = 0;\n    hasReadFirstPage = false;\n    lastFileData = null;\n    /** Cache of the last JSON file parsed during paginated reads (avoid re-parse per page). */\n    readFileCache = null; // { filePath: string, data: any[] } | null\n    metadata;\n\n    // Synopsis calculation functions\n    fileSynopsisFunction = null;\n    versionSynopsisFunction = null;\n\n    /**\n     * Constructor - accepts context as first parameter (new pattern)\n     * or config object (legacy pattern for backward compatibility)\n     */\n    constructor(contextOrConfig, options) {\n        let config;\n        \n        // Check if first parameter is Context (has params property)\n        if (contextOrConfig && typeof contextOrConfig === \"object\" && \"params\" in contextOrConfig) {\n            // New pattern: context is first parameter\n            const context = contextOrConfig ;\n            const opts = options || {};\n            \n            // Get configuration from context.params (module \"filedatabase\" for --showUsedParams grouping)\n            const defs = {\n                basePath: \"string default ./data\",\n                namespace: \"string default default\",\n                tableName: \"string\",\n                maxVersions: \"number default 5\",\n                pageSize: \"number default 5000\",\n            };\n            const discovered = context.params.getAllForModule(defs);\n            config = { ...discovered, ...opts, logger: context.logger } ;\n        } else {\n            // Legacy pattern: config object\n            config = contextOrConfig ;\n        }\n        \n        // Validate required configuration\n        if (!config.basePath) {\n            throw new ParamError(\"[FileDatabase] basePath is required\");\n        }\n\n        this.basePath = config.basePath;\n        this.namespace = config.namespace || \"default\";\n        this.tableName = config.tableName || null;\n        this.versioned = config.versioned ?? true; // Default true for backward compatibility\n        this.maxVersions = config.maxVersions || 5;\n        this.pageSize = config.pageSize || 5000;\n        this.useMetadata = config.useMetadata !== false; // Default true\n        this.freeSpaceThreshold = config.freeSpaceThreshold || 100 * 1024 * 1024; // 100MB\n        this.logger = config.logger || console;\n        this.lastReadMissingFiles = [];\n\n        // Initialize metadata\n        this.metadata = this.getDefaultMetadata();\n    }\n\n    /**\n     * Initialize FileDatabase from context and options.\n     * Params are read via getAllForModule(\"filedatabase\", defs) for --showUsedParams grouping.\n     */\n    static init(context, options) {\n        return new FileDatabase(context, options ?? {});\n    }\n\n    /**\n     * Get default metadata structure\n     */\n    getDefaultMetadata() {\n        return {\n            version: this.currentVersion || null,\n            files: [],\n            createdAt: new Date().toISOString(),\n            modifiedAt: new Date().toISOString(),\n            totalRecords: 0,\n            synopsis: null,\n            dataType: null,\n        };\n    }\n\n    /**\n     * Get the destination path (basePath/namespace/tableName[/version])\n     */\n    getDestinationPath(version) {\n        const errors = [\"basePath\", \"namespace\", \"tableName\"]\n            .filter(prop => !this[prop ])\n            .map(prop => `${prop} is not set`);\n        if (errors.length) {\n            throw new FileDatabaseError(`[FileDatabase] ${errors.join(\"; \")}`);\n        }\n\n        const parts = [this.basePath, this.namespace];\n        if (this.tableName) {\n            parts.push(...this.tableName.split(\"/\"));\n        }\n\n        // Only add version folder if in versioned mode and version is specified\n        if (this.versioned && version) {\n            parts.push(version);\n        }\n\n        return path.resolve(...parts);\n    }\n\n    /**\n     * Set current version and version folder\n     */\n    async setCurrentVersion(version) {\n        this.currentVersion = version;\n        this.currentVersionFolder = await ensurePath(this.getDestinationPath(), version);\n    }\n\n    /**\n     * Create a new version folder named with the current UTC second.\n     * Only works in versioned mode.\n     *\n     * Clash protection: if that name already exists (two writers in the same\n     * second, or wall clock behind the latest version), advance +1s until free.\n     * Do NOT always derive from max(existing)+1s — that made successive harvests\n     * hours apart still land one second apart on disk.\n     */\n    async makeNewVersion() {\n        if (!this.versioned) {\n            throw new FileDatabaseError(\"makeNewVersion() only works in versioned mode\");\n        }\n\n        // Reset in-memory metadata when creating a new version\n        this.metadata = this.getDefaultMetadata();\n\n        const existingVersions = await this.getVersions();\n        const existingSet = new Set(existingVersions);\n\n        let candidateMs = Date.now();\n        if (existingVersions.length > 0) {\n            let maxMs = 0;\n            for (const version of existingVersions) {\n                const ms = new Date(version).getTime();\n                if (Number.isFinite(ms) && ms > maxMs) maxMs = ms;\n            }\n            // Same-second clash or clock behind latest folder — start just after it.\n            if (candidateMs <= maxMs) {\n                candidateMs = maxMs + 1000;\n            }\n        }\n\n        let versionName = new Date(candidateMs).toISOString().split(\".\")[0] + \"Z\";\n        while (existingSet.has(versionName)) {\n            candidateMs += 1000;\n            versionName = new Date(candidateMs).toISOString().split(\".\")[0] + \"Z\";\n        }\n\n        await this.setCurrentVersion(versionName);\n\n        // Reset file numbering for new version\n        this.currentFileNumber = 0;\n\n        // Delete old versions if we exceed maxVersions\n        const versions = await this.getVersions();\n        while (versions.length > this.maxVersions) {\n            const versionToDelete = path.resolve(this.getDestinationPath(), versions.shift());\n            this.logger.silly?.(`[FileDatabase] Deleting old version: ${versionToDelete}`);\n            await fs.promises.rm(versionToDelete, { recursive: true, force: true });\n        }\n\n        return versionName;\n    }\n\n    /**\n     * Get list of all versions (sorted chronologically)\n     * Only works in versioned mode\n     */\n    async getVersions() {\n        if (!this.versioned) {\n            return []; // No versions in non-versioned mode\n        }\n\n        const destPath = this.getDestinationPath();\n\n        try {\n            await ensurePath(destPath);\n            const items = await fs.promises.readdir(destPath);\n            const versions = items.filter(item => {\n                const itemPath = path.join(destPath, item);\n                const stat = fs.statSync(itemPath);\n                return stat.isDirectory() && isTimestampFolder(item);\n            });\n\n            return versions.sort();\n        } catch (error) {\n            return [];\n        }\n    }\n\n    /**\n     * Get the latest version (most recent timestamp)\n     * Only works in versioned mode\n     * @returns Latest version string or null if no versions\n     */\n    async getLatestVersion() {\n        if (!this.versioned) {\n            throw new FileDatabaseError(\"getLatestVersion() only works in versioned mode\");\n        }\n\n        const versions = await this.getVersions();\n        if (versions.length === 0) {\n            return null;\n        }\n\n        return versions[versions.length - 1];\n    }\n\n    /**\n     * Check if any data exists in this table\n     * Works for both versioned and non-versioned modes\n     * @returns true if data exists\n     */\n    async hasData() {\n        const tablePath = this.getDestinationPath();\n\n        if (!fs.existsSync(tablePath)) {\n            return false;\n        }\n\n        if (this.versioned) {\n            // Check for version folders\n            const versions = await this.getVersions();\n            return versions.length > 0;\n        } else {\n            // Check for any data files or metadata\n            const items = await fs.promises.readdir(tablePath);\n            return items.some(item =>\n                item === \"metadata.json\" ||\n                item.match(/^\\d{6}\\.(json|txt|xml)$/) ||\n                item.endsWith(\".json\")\n            );\n        }\n    }\n\n    /**\n     * Auto-detect the data format in this table\n     * Used when reading existing data\n     * @returns Format detection result\n     */\n    async detectDataFormat()\n\n\n\n    {\n        const tablePath = this.getDestinationPath();\n\n        if (!fs.existsSync(tablePath)) {\n            return { versioned: false, hasMetadata: false, dataType: null };\n        }\n\n        const items = await fs.promises.readdir(tablePath);\n\n        // Check for metadata.json in root (non-versioned with metadata)\n        if (items.includes(\"metadata.json\")) {\n            const metadata = JSON.parse(\n                await fs.promises.readFile(path.join(tablePath, \"metadata.json\"), \"utf8\")\n            );\n            return {\n                versioned: false,\n                hasMetadata: true,\n                dataType: metadata.dataType || null\n            };\n        }\n\n        // Check for version folders\n        const versionFolders = items.filter(item => {\n            const itemPath = path.join(tablePath, item);\n            const stat = fs.statSync(itemPath);\n            return stat.isDirectory() && isTimestampFolder(item);\n        });\n\n        if (versionFolders.length > 0) {\n            // Check if latest version has metadata\n            const latestVersion = versionFolders.sort().pop();\n            const versionMetadataPath = path.join(tablePath, latestVersion, \"metadata.json\");\n\n            return {\n                versioned: true,\n                hasMetadata: fs.existsSync(versionMetadataPath),\n                dataType: null\n            };\n        }\n\n        // Check for sequential files (legacy non-versioned)\n        const dataFiles = items.filter(f => f.match(/^\\d{6}\\.(json|txt|xml)$/));\n        if (dataFiles.length > 0) {\n            return {\n                versioned: false,\n                hasMetadata: false,\n                dataType: null\n            };\n        }\n\n        return { versioned: false, hasMetadata: false, dataType: null };\n    }\n\n    /**\n     * Load metadata from JSON file. Distinguishes missing vs unreadable so\n     * callers can rewrite a truncated file once instead of warning on every read.\n     */\n    async loadMetadataJson(version) {\n        const loaded = await this.readMetadataJsonFile(version);\n        return loaded.metadata;\n    }\n\n    async readMetadataJsonFile(version) {\n        const metadataFile = path.join(this.getDestinationPath(), version, \"metadata.json\");\n        if (!fs.existsSync(metadataFile)) {\n            return { metadata: null, unreadable: false };\n        }\n        try {\n            const rawData = await fs.promises.readFile(metadataFile, \"utf8\");\n            return { metadata: JSON.parse(rawData), unreadable: false };\n        } catch {\n            return { metadata: null, unreadable: true };\n        }\n    }\n\n    async persistMetadataJson(version, metadata) {\n        if (!this.useMetadata || !metadata) {\n            return;\n        }\n        const metadataFile = path.join(this.getDestinationPath(), version, \"metadata.json\");\n        try {\n            await fs.promises.writeFile(metadataFile, JSON.stringify(metadata, null, 4), \"utf8\");\n        } catch (e) {\n            this.logger.silly?.(`[FileDatabase] Could not rewrite metadata for \"${version}\": ${e.message}`);\n        }\n    }\n\n    /**\n     * Build metadata by scanning files in a version folder (backward compatibility)\n     * Reads all files to get accurate counts - used when synopsis calculation is needed\n     */\n    async figureMetadataFromVersionFiles(version) {\n        const versionPath = path.join(this.getDestinationPath(), version);\n\n        if (!fs.existsSync(versionPath)) {\n            return this.getDefaultMetadata();\n        }\n\n        const files = (await fs.promises.readdir(versionPath))\n            .filter(file => file !== \"metadata.json\" && !file.startsWith(\".\"))\n            .sort();\n\n        const metadata = this.getDefaultMetadata();\n        metadata.version = version;\n        metadata.files = [];\n\n        let totalRecords = 0;\n        let detectedDataType = null;\n\n        for (let i = 0; i < files.length; i++) {\n            const fileName = files[i];\n            const filePath = path.join(versionPath, fileName);\n\n            try {\n                const rawData = await fs.promises.readFile(filePath, \"utf8\");\n                const extension = path.extname(fileName).toLowerCase();\n                let dataType = \"text\";\n\n                if (extension === \".json\") {\n                    dataType = \"json-array\";\n                } else if (extension === \".xml\") {\n                    dataType = \"xml\";\n                }\n\n                const fileData = deserializeData(rawData, dataType);\n                const recordsCount = Array.isArray(fileData) ? fileData.length : 1;\n\n                if (detectedDataType === null) {\n                    detectedDataType = detectDataType(fileData);\n                }\n\n                const fileInfo = {\n                    number: i + 1,\n                    recordsCount,\n                    fileName,\n                };\n\n                metadata.files.push(fileInfo);\n                totalRecords += recordsCount;\n            } catch (error) {\n                this.logger.error?.(`[FileDatabase] Failed to read file ${fileName}: ${(error ).message}`);\n            }\n        }\n\n        metadata.totalRecords = totalRecords;\n        metadata.dataType = detectedDataType;\n\n        return metadata;\n    }\n\n    /**\n     * Build metadata optimized - only reads first and last files\n     * Assumes all middle files have the same record count as the first file\n     * Much faster for large datasets with many files\n     */\n    async buildMetadataOptimized(version) {\n        const versionPath = path.join(this.getDestinationPath(), version);\n\n        if (!fs.existsSync(versionPath)) {\n            return this.getDefaultMetadata();\n        }\n\n        const files = (await fs.promises.readdir(versionPath))\n            .filter(file => file !== \"metadata.json\" && !file.startsWith(\".\"))\n            .sort();\n\n        if (files.length === 0) {\n            return this.getDefaultMetadata();\n        }\n\n        const metadata = this.getDefaultMetadata();\n        metadata.version = version;\n        metadata.files = files.map((fileName, index) => ({\n            number: index + 1,\n            recordsCount: 0,\n            fileName,\n        }));\n\n        // Read first file to determine data type and standard record count\n        const firstFile = metadata.files[0];\n        const firstFilePath = path.join(versionPath, firstFile.fileName);\n        const firstFileRaw = await fs.promises.readFile(firstFilePath, \"utf8\");\n\n        let firstFileData;\n        try {\n            firstFileData = JSON.parse(firstFileRaw);\n        } catch (e) {\n            firstFileData = firstFileRaw;\n        }\n\n        metadata.dataType = detectDataType(firstFileData);\n\n        // Only proceed with optimization for json-array data\n        if (metadata.dataType === \"json-array\") {\n            const firstFileCount = Array.isArray(firstFileData) ? firstFileData.length : 1;\n            firstFile.recordsCount = firstFileCount;\n\n            // Assume all middle files have the same count as the first\n            for (let i = 1; i < metadata.files.length - 1; i++) {\n                metadata.files[i].recordsCount = firstFileCount;\n            }\n\n            // Read last file to get its actual count (might be partial)\n            if (files.length > 1) {\n                const lastFile = metadata.files[metadata.files.length - 1];\n                const lastFilePath = path.join(versionPath, lastFile.fileName);\n                const lastFileRaw = await fs.promises.readFile(lastFilePath, \"utf8\");\n                const lastFileData = deserializeData(lastFileRaw, metadata.dataType);\n                lastFile.recordsCount = Array.isArray(lastFileData) ? lastFileData.length : 1;\n            }\n\n            // Calculate total records\n            metadata.totalRecords = metadata.files.reduce((sum, file) => sum + file.recordsCount, 0);\n        } else {\n            // For non-array data, count each file as 1 record\n            metadata.files.forEach(file => {\n                file.recordsCount = 1;\n            });\n            metadata.totalRecords = files.length;\n        }\n\n        return metadata;\n    }\n\n    /**\n     * Figure out metadata - tries JSON first, then builds from files\n     * Uses optimized building when no synopsis calculation is needed\n     */\n    async figureMetadata(version, useOptimized = true) {\n        let unreadable = false;\n        if (this.useMetadata) {\n            const loaded = await this.readMetadataJsonFile(version);\n            if (loaded.metadata) {\n                return loaded.metadata;\n            }\n            unreadable = loaded.unreadable;\n        }\n\n        // Fallback: build from files\n        // Use optimized version (only reads first+last) when no synopsis needed\n        const rebuilt = (useOptimized && !this.fileSynopsisFunction && !this.versionSynopsisFunction)\n            ? await this.buildMetadataOptimized(version)\n            : await this.figureMetadataFromVersionFiles(version);\n\n        if (unreadable) {\n            await this.persistMetadataJson(version, rebuilt);\n        }\n        return rebuilt;\n    }\n\n    /**\n     * Load version metadata (main entry point for loading)\n     */\n    async loadVersionMetadata(version) {\n        const metadata = await this.figureMetadata(version);\n        this.metadata = metadata;\n        return metadata;\n    }\n\n    /**\n     * Save version metadata to file\n     */\n    async saveVersionMetadata(metadata) {\n        if (!this.useMetadata) {\n            return;\n        }\n\n        const metadataToSave = metadata || this.metadata;\n        let metadataFile;\n\n        if (this.versioned) {\n            // Versioned mode: metadata in version folder\n            if (!this.currentVersion) {\n                return;\n            }\n            metadataFile = path.join(this.getDestinationPath(), this.currentVersion, \"metadata.json\");\n        } else {\n            // Non-versioned mode: metadata in root table folder\n            metadataFile = path.join(this.getDestinationPath(), \"metadata.json\");\n        }\n\n        await fs.promises.writeFile(metadataFile, JSON.stringify(metadataToSave, null, 4), \"utf8\");\n    }\n\n    /**\n     * Create a new file entry in metadata\n     */\n    makeNewFile() {\n        this.currentFileNumber = (this.currentFileNumber || 0) + 1;\n\n        const dataType = this.metadata.dataType || \"json-array\";\n        const fileEntry = {\n            number: this.currentFileNumber,\n            recordsCount: 0,\n            fileName: `${this.currentFileNumber.toString().padStart(6, \"0\")}.${getFileExtension(dataType)}`,\n        };\n\n        this.metadata.files.push(fileEntry);\n        this.lastFileData = null;\n\n        this.logger.silly?.(`[FileDatabase] Created new file: ${fileEntry.fileName}, fileNumber: ${this.currentFileNumber}`);\n    }\n\n    /**\n     * Figure out what data to write and which file to use (for pagination)\n     * @param data - Data to write\n     * @param targetFileIndex - Optional index of existing file to overwrite (when customMetadata matches)\n     * @param forceNewFile - If true, always create a new file (when customMetadata provided but no match)\n     */\n    figureOutDataAndFileToWrite(data, targetFileIndex = null, forceNewFile = false) {\n        let dataToWrite;\n        let dataLeftOver;\n\n        // Detect data type from incoming data\n        // Always use the incoming data's type to ensure correct file extension\n        const incomingDataType = detectDataType(data);\n        if (this.metadata.dataType !== incomingDataType) {\n            this.metadata.dataType = incomingDataType;\n        }\n\n        // If targetFileIndex is provided, use that file (overwrite existing file with matching customMetadata)\n        if (targetFileIndex !== null && targetFileIndex < this.metadata.files.length) {\n            const targetFile = this.metadata.files[targetFileIndex];\n            // For non-array data, overwrite the file\n            if (!Array.isArray(data)) {\n                dataToWrite = data;\n                dataLeftOver = null;\n                return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };\n            } else {\n                // For arrays, start fresh in the target file (don't append)\n                dataToWrite = data.slice(0, this.pageSize);\n                dataLeftOver = data.slice(this.pageSize);\n                this.lastFileData = dataToWrite;\n                return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };\n            }\n        }\n\n        // If forceNewFile is true (customMetadata provided but no match), create a new file\n        // Skip the initial file creation if forceNewFile is true to avoid creating an extra empty file\n        let newlyCreatedFileIndex = null;\n        if (forceNewFile) {\n            const filesBeforeCreate = this.metadata.files.length;\n            this.makeNewFile();\n            newlyCreatedFileIndex = filesBeforeCreate; // Index of the newly created file\n            this.logger.silly?.(`[FileDatabase] Creating new file for unique custom metadata combination, fileNumber: ${this.currentFileNumber}`);\n        } else if (this.metadata.files.length === 0) {\n            // If no files exist yet and we're not forcing a new file, create the first file\n            this.makeNewFile();\n        }\n\n        // Get the last file (which might be the one we just created)\n        const lastFile = this.metadata.files[this.metadata.files.length - 1];\n        const lastFileRecordsCount = lastFile.recordsCount;\n        \n        // Verify that if we created a new file, we're using it\n        if (forceNewFile && newlyCreatedFileIndex !== null) {\n            const newlyCreatedFile = this.metadata.files[newlyCreatedFileIndex];\n            if (newlyCreatedFile && newlyCreatedFile.fileName !== lastFile.fileName) {\n                this.logger.warn?.(`[FileDatabase] Warning: Newly created file ${newlyCreatedFile.fileName} doesn't match last file ${lastFile.fileName}`);\n            }\n        }\n        \n        // For non-array data (text/xml/object), check if we need a new file with correct extension\n        // But skip this check if forceNewFile is true - we already created the file we need\n        if (!Array.isArray(data) && !forceNewFile) {\n            const lastFileExtension = path.extname(lastFile.fileName);\n            const expectedExtension = `.${getFileExtension(incomingDataType)}`;\n            // If the last file has wrong extension, create a new file with correct extension\n            // Check even if recordsCount is 0 (empty file) - we want correct extension for new writes\n            if (lastFileExtension !== expectedExtension) {\n                // Only create new file if the existing one has content, otherwise we'll use it\n                if (lastFileRecordsCount > 0) {\n                    this.makeNewFile();\n                } else {\n                    // File is empty, update its name to have correct extension\n                    lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, \"0\")}.${getFileExtension(incomingDataType)}`;\n                }\n            }\n        } else if (!Array.isArray(data) && forceNewFile) {\n            // If forceNewFile is true, ensure the newly created file has the correct extension\n            const lastFileExtension = path.extname(lastFile.fileName);\n            const expectedExtension = `.${getFileExtension(incomingDataType)}`;\n            if (lastFileExtension !== expectedExtension) {\n                lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, \"0\")}.${getFileExtension(incomingDataType)}`;\n            }\n        }\n\n        if (Array.isArray(data)) {\n            // For arrays, handle pagination\n            // If forceNewFile is true, write fresh data to the new file (don't append)\n            if (forceNewFile) {\n                // Write fresh data to the newly created file\n                dataToWrite = data.slice(0, this.pageSize);\n                dataLeftOver = data.slice(this.pageSize);\n                this.lastFileData = dataToWrite;\n            } else if (lastFileRecordsCount < this.pageSize) {\n                // Try to append to existing file if there's space\n                dataToWrite = [...(this.lastFileData || []), ...data.slice(0, this.pageSize - lastFileRecordsCount)];\n                dataLeftOver = data.slice(this.pageSize - lastFileRecordsCount);\n                this.lastFileData = dataToWrite;\n            } else {\n                // Last file is full, create a new file\n                this.makeNewFile();\n                dataToWrite = data.slice(0, this.pageSize);\n                dataLeftOver = data.slice(this.pageSize);\n                this.lastFileData = dataToWrite;\n            }\n        } else {\n            // For non-arrays, write as-is\n            dataToWrite = data;\n            dataLeftOver = null;\n        }\n\n        // Get the file name - if forceNewFile is true, we just created a new file, so use that one\n        // Otherwise, use the last file (which might have been created earlier or is being reused)\n        const fileName = this.metadata.files[this.metadata.files.length - 1].fileName;\n\n        this.logger.silly?.(\n            `[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, forceNewFile=${forceNewFile}, targetFileIndex=${targetFileIndex}, dataToWrite.length=${Array.isArray(dataToWrite) ? dataToWrite.length : \"N/A\"}, lastFileRecordsCount=${lastFileRecordsCount}`\n        );\n\n        return { dataToWrite, dataLeftOver, fileName };\n    }\n\n    /**\n     * Calculate file-level synopsis if function is set\n     */\n    calculateFileSynopsis(data, fileIndex = this.metadata.files.length - 1) {\n        if (!this.fileSynopsisFunction) {\n            return;\n        }\n        const fileInfo = this.metadata.files[fileIndex];\n        const enhancedFileInfo = this.fileSynopsisFunction(fileInfo, data);\n        this.metadata.files[fileIndex] = enhancedFileInfo;\n    }\n\n    /**\n     * Calculate version-level synopsis if function is set\n     */\n    calculateVersionSynopsis() {\n        if (!this.versionSynopsisFunction) {\n            return;\n        }\n        const enhancedMetadata = this.versionSynopsisFunction(this.metadata);\n        this.metadata = enhancedMetadata;\n    }\n\n    /**\n     * Update metadata after writing data\n     */\n    updateMetadata(dataToWrite, fileName, customMetadata) {\n        let currentFile;\n\n        if (fileName) {\n            // Find the specific file by filename\n            const foundFile = this.metadata.files.find(file => file.fileName === fileName);\n            if (!foundFile) {\n                this.logger.warn?.(`[FileDatabase] File ${fileName} not found in metadata, using last file`);\n                currentFile = this.metadata.files[this.metadata.files.length - 1];\n            } else {\n                currentFile = foundFile;\n            }\n        } else {\n            // Get the current file info from metadata (always the last file)\n            currentFile = this.metadata.files[this.metadata.files.length - 1];\n        }\n\n        // Calculate the actual records count for the data being written\n        const recordsCount = Array.isArray(dataToWrite) ? dataToWrite.length : 1;\n\n        // Update existing file entry with the correct records count\n        currentFile.recordsCount = recordsCount;\n\n        // Add custom metadata fields if provided\n        if (customMetadata) {\n            Object.assign(currentFile, customMetadata);\n        }\n\n        // Find the file index for synopsis calculation\n        const fileIndex = this.metadata.files.indexOf(currentFile);\n        if (fileIndex !== -1) {\n            this.calculateFileSynopsis(dataToWrite, fileIndex);\n        }\n\n        // Update version metadata\n        this.metadata.version = this.currentVersion;\n        this.metadata.modifiedAt = new Date().toISOString();\n        this.metadata.dataType = detectDataType(dataToWrite);\n\n        // Recalculate total records by summing all file records counts\n        this.metadata.totalRecords = this.metadata.files.reduce((sum, file) => sum + (file.recordsCount || 0), 0);\n\n        this.logger.silly?.(\n            `[FileDatabase] Updated metadata for file ${currentFile.fileName}: recordsCount=${recordsCount}, totalRecords=${this.metadata.totalRecords}`\n        );\n    }\n\n    /**\n     * Safe write with disk space check\n     */\n    async safeWrite(filePath, data) {\n        const serializedData = serializeData(data);\n        const dir = path.dirname(filePath);\n        const requiredBytes = Buffer.byteLength(serializedData, \"utf8\");\n\n        // Check disk space\n        const freeBytes = getFreeDiskSpace(dir);\n        if (freeBytes !== null) {\n            if (freeBytes < requiredBytes) {\n                throw new FileDatabaseError(\n                    `Not enough disk space. Required: ${bytesToHumanReadable(requiredBytes)}, Free: ${bytesToHumanReadable(freeBytes)}`\n                );\n            }\n\n            if (freeBytes < this.freeSpaceThreshold) {\n                this.logger.warn?.(`Low disk space warning: only ${bytesToHumanReadable(freeBytes)} left`);\n            }\n        }\n\n        try {\n            await fs.promises.writeFile(filePath, serializedData, \"utf8\");\n            this.logger.silly?.(`[FileDatabase] Wrote ${bytesToHumanReadable(requiredBytes)} to ${filePath}`);\n        } catch (error) {\n            throw new FileDatabaseError(`Failed to write file ${filePath}: ${(error ).message}`);\n        }\n    }\n\n    /**\n     * Prepare the instance for read or write operations\n     * This discovers state and sets up internal members based on mode and current data\n     */\n    async prepare(options\n\n\n\n\n\n\n\n\n\n    ) {\n        const { write, read, version, deferInitialVersion } = options;\n        if (write) {\n            if (this.versioned) {\n                // Versioned mode\n                if (this.currentVersion === null) {\n                    if (!deferInitialVersion) {\n                        await this.makeNewVersion();\n                        this.metadata = this.getDefaultMetadata();\n                        this.metadata.version = this.currentVersion;\n                        this.makeNewFile();\n                    }\n                } else {\n                    // For existing versions, load the metadata if not already loaded\n                    if (!this.metadata.files.length) {\n                        this.metadata = await this.figureMetadata(this.currentVersion);\n                        // Initialize currentFileNumber from existing files\n                        if (this.metadata.files && this.metadata.files.length > 0) {\n                            this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                        } else {\n                            this.currentFileNumber = 0;\n                        }\n                    }\n                }\n            } else {\n                // Non-versioned mode - ensure table directory exists\n                await ensurePath(this.getDestinationPath());\n\n                // Non-versioned mode - auto-detect useMetadata if not set\n                if (this.useMetadata === true) {\n                    // Try to load existing metadata, create new if doesn't exist\n                    const metadataPath = path.join(this.getDestinationPath(), \"metadata.json\");\n                    if (fs.existsSync(metadataPath)) {\n                        try {\n                            const rawData = await fs.promises.readFile(metadataPath, \"utf8\");\n                            this.metadata = JSON.parse(rawData);\n                            // Initialize currentFileNumber from existing files\n                            if (this.metadata.files && this.metadata.files.length > 0) {\n                                this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                            } else {\n                                this.currentFileNumber = 0;\n                            }\n                        } catch (e) {\n                            this.metadata = this.getDefaultMetadata();\n                            this.currentFileNumber = 0;\n                        }\n                    } else {\n                        // Don't create a file here - let the write logic handle it\n                        // This prevents creating an empty file when customMetadata is provided\n                        this.metadata = this.getDefaultMetadata();\n                        this.currentFileNumber = 0;\n                    }\n                } else {\n                    // No metadata mode - just create default metadata\n                    // Don't create a file here either - let the write logic handle it\n                    this.metadata = this.getDefaultMetadata();\n                    this.currentFileNumber = 0;\n                }\n            }\n        } else if (read) {\n            if (this.versioned) {\n                // Versioned mode\n                const versions = await this.getVersions();\n                if (versions.length === 0) {\n                    throw new FileDatabaseError(\"[FileDatabase] No versions found, cannot read\");\n                }\n\n                const targetVersion = version || versions[versions.length - 1];\n                if (version && !versions.includes(version)) {\n                    throw new FileDatabaseError(`[FileDatabase] Version \"${version}\" not found`);\n                }\n                if (this.metadata.version !== targetVersion) {\n                    this.metadata = this.getDefaultMetadata();\n                    this.currentRecord = 0;\n                    this.hasReadFirstPage = false;\n                }\n                await this.setCurrentVersion(targetVersion);\n\n                if (!this.metadata.files.length) {\n                    this.metadata = await this.figureMetadata(this.currentVersion);\n                    // Initialize currentFileNumber from existing files\n                    if (this.metadata.files && this.metadata.files.length > 0) {\n                        this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                    } else {\n                        this.currentFileNumber = 0;\n                    }\n                }\n            } else {\n                // Non-versioned mode\n                this.currentVersion = null; // No version concept\n\n                // Auto-detect useMetadata if not explicitly set\n                if (this.useMetadata === undefined) {\n                    const format = await this.detectDataFormat();\n                    this.useMetadata = format.hasMetadata;\n                }\n\n                if (this.useMetadata) {\n                    // Load metadata from root\n                    const destPath = this.getDestinationPath();\n                    const metadataPath = path.join(destPath, \"metadata.json\");\n                    if (fs.existsSync(metadataPath)) {\n                        try {\n                            const rawData = await fs.promises.readFile(metadataPath, \"utf8\");\n                            this.metadata = JSON.parse(rawData);\n                            // Initialize currentFileNumber from existing files\n                            if (this.metadata.files && this.metadata.files.length > 0) {\n                                this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                            } else {\n                                this.currentFileNumber = 0;\n                            }\n                        } catch (e) {\n                            throw new FileDatabaseError(`Failed to read metadata: ${(e ).message}`);\n                        }\n                    } else {\n                        throw new FileDatabaseError(\n                            `[FileDatabase] No metadata found in non-versioned mode. Looked for: ${metadataPath} (table path: ${destPath})`\n                        );\n                    }\n                } else {\n                    // Figure metadata from files\n                    this.metadata = await this.figureMetadataFromVersionFiles(\"\");\n                    // Initialize currentFileNumber from existing files\n                    if (this.metadata.files && this.metadata.files.length > 0) {\n                        this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                    } else {\n                        this.currentFileNumber = 0;\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Write data to the file database\n     */\n    async write(data, options = {}) {\n        // Catalog mode: write to specific filename in destination path\n        if (options.filename) {\n            const destPath = this.getDestinationPath();\n            await ensurePath(destPath);\n            const filePath = path.join(destPath, options.filename);\n            await this.safeWrite(filePath, data);\n            return;\n        }\n\n        // Check for forceNewVersion in non-versioned mode\n        if (options.forceNewVersion && !this.versioned) {\n            throw new FileDatabaseError(\"Cannot use forceNewVersion in non-versioned mode\");\n        }\n\n        // Prepare for writing (this may load existing metadata).\n        // If this write will force a new version on an empty store, defer the initial version in\n        // prepare so we only call makeNewVersion() once (in the forceNewVersion block below).\n        await this.prepare({ write: true, deferInitialVersion: !!(options.forceNewVersion && this.versioned) });\n\n        // Always detect data type from incoming data AFTER prepare()\n        // This ensures we use the correct type even if existing metadata has a different type\n        const incomingDataType = detectDataType(data);\n        this.metadata.dataType = incomingDataType;\n\n        // Force new version if requested (versioned mode only)\n        if (options.forceNewVersion) {\n            await this.makeNewVersion();\n            this.metadata = this.getDefaultMetadata();\n            this.metadata.version = this.currentVersion;\n            // Set data type from incoming data\n            this.metadata.dataType = incomingDataType;\n            this.makeNewFile();\n        }\n\n        // Check if customMetadata is provided and find existing file with matching metadata\n        let targetFileIndex = null;\n        const hasCustomMetadata = options.customMetadata && Object.keys(options.customMetadata).length > 0;\n        \n        if (hasCustomMetadata) {\n            // Search through existing files for matching custom metadata\n            for (let i = 0; i < this.metadata.files.length; i++) {\n                const fileEntry = this.metadata.files[i];\n                // Check if all customMetadata fields match\n                // A file matches if it has all the customMetadata keys and their values match\n                const matches = Object.keys(options.customMetadata).every(key => {\n                    // File must have the key and the value must match\n                    return key in fileEntry && fileEntry[key] === options.customMetadata[key];\n                });\n                if (matches) {\n                    targetFileIndex = i;\n                    this.logger.silly?.(`[FileDatabase] Found existing file with matching custom metadata: ${fileEntry.fileName}, metadata: ${JSON.stringify(options.customMetadata)}`);\n                    break;\n                } else {\n                    this.logger.silly?.(`[FileDatabase] File ${fileEntry.fileName} does not match custom metadata: ${JSON.stringify(options.customMetadata)}`);\n                }\n            }\n            if (targetFileIndex === null) {\n                this.logger.silly?.(`[FileDatabase] No existing file found with custom metadata: ${JSON.stringify(options.customMetadata)}, will create new file`);\n            }\n        } else {\n            this.logger.silly?.(`[FileDatabase] No custom metadata provided, will create new file`);\n        }\n\n        // If we found a matching file, prepare to overwrite it\n        if (targetFileIndex !== null) {\n            const targetFile = this.metadata.files[targetFileIndex];\n            // Set current file number to match the target file\n            this.currentFileNumber = targetFile.number;\n            // Reset pagination state since we're overwriting\n            this.lastFileData = null;\n            this.currentRecord = 0;\n            this.hasReadFirstPage = false;\n        }\n\n        // Pass flag indicating if we should force a new file (when customMetadata provided but no match)\n        const forceNewFile = hasCustomMetadata && targetFileIndex === null;\n        // eslint-disable-next-line prefer-const\n        let { dataToWrite, dataLeftOver, fileName } = this.figureOutDataAndFileToWrite(data, targetFileIndex, forceNewFile);\n\n        // Write first batch\n        const destPath = this.getDestinationPath(this.currentVersion || undefined);\n        await this.safeWrite(path.join(destPath, fileName), dataToWrite);\n        this.updateMetadata(dataToWrite, fileName, options.customMetadata);\n\n        // Handle pagination for remaining data (arrays only)\n        // Note: For customMetadata matches, we only write to the target file, so no pagination needed\n        while (dataLeftOver && dataLeftOver.length > 0 && targetFileIndex === null) {\n            const writeContext = this.figureOutDataAndFileToWrite(dataLeftOver);\n            await this.safeWrite(path.join(destPath, writeContext.fileName), writeContext.dataToWrite);\n            this.updateMetadata(writeContext.dataToWrite, writeContext.fileName, options.customMetadata);\n            dataLeftOver = writeContext.dataLeftOver;\n        }\n\n        // Calculate version synopsis\n        this.calculateVersionSynopsis();\n\n        // Save metadata to file\n        if (this.useMetadata) {\n            await this.saveVersionMetadata(this.metadata);\n        }\n    }\n\n    /**\n     * Read data from the file database\n     */\n    async read(options = {}) {\n        const { version, nextPage = false, pageSize, filename } = options;\n\n        // Catalog mode: read specific file by name\n        if (filename) {\n            const destPath = this.getDestinationPath(version);\n            const filePath = path.join(destPath, filename);\n            try {\n                const rawData = await fs.promises.readFile(filePath, \"utf8\");\n                return JSON.parse(rawData);\n            } catch (error) {\n                throw new FileDatabaseError(`Failed to read file ${filename}: ${(error ).message}`);\n            }\n        }\n\n        // Prepare for reading\n        await this.prepare({ read: true, version });\n\n        // Check for non-paginated data types\n        const isNonPaginatedData =\n            this.metadata.dataType === \"text\" || this.metadata.dataType === \"xml\" || this.metadata.dataType === \"json-object\";\n\n        if (isNonPaginatedData) {\n            // For text/xml/object data, return all content\n            const file = this.metadata.files[0];\n            const filePath = path.join(this.getDestinationPath(this.currentVersion || undefined), file.fileName);\n            try {\n                const rawData = await fs.promises.readFile(filePath, \"utf8\");\n                return deserializeData(rawData, this.metadata.dataType);\n            } catch (error) {\n                throw new FileDatabaseError(`Failed to read file ${file.fileName}: ${(error ).message}`);\n            }\n        }\n\n        // Handle paginated data (JSON arrays)\n        let effectivePageSize;\n\n        if (nextPage && this.hasReadFirstPage) {\n            // currentRecord was already advanced by records actually returned\n            // at the end of the previous read (not by requested pageSize — that\n            // skipped records when a read ended mid-file / short final page).\n            effectivePageSize = pageSize || this.pageSize;\n        } else if (!nextPage) {\n            // If not paginating, read all records (unless pageSize is explicitly provided)\n            effectivePageSize = pageSize !== undefined ? pageSize : this.metadata.totalRecords;\n            this.currentRecord = 0;\n        } else {\n            // First call with nextPage=true (no previous page read)\n            effectivePageSize = pageSize || this.pageSize;\n        }\n\n        // If beyond total records, return empty array\n        if (this.currentRecord >= this.metadata.totalRecords) {\n            return [];\n        }\n\n        const result = [];\n        this.lastReadMissingFiles = [];\n        let recordsRead = 0;\n        let currentFileIndex = 0;\n        let currentFileOffset = 0;\n\n        // Calculate which file and offset to start from\n        let totalRecords = 0;\n        for (let i = 0; i < this.metadata.files.length; i++) {\n            const file = this.metadata.files[i];\n            if (this.currentRecord < totalRecords + file.recordsCount) {\n                currentFileIndex = i;\n                currentFileOffset = totalRecords;\n                break;\n            }\n            totalRecords += file.recordsCount;\n        }\n\n        // Read from files (cache parsed JSON — harvest chunks are often 50–60MB;\n        // re-parsing on every nextPage with pageSize=200 is catastrophic).\n        let cumulativeRecords = currentFileOffset;\n        for (let i = currentFileIndex; i < this.metadata.files.length && recordsRead < effectivePageSize; i++) {\n            const file = this.metadata.files[i];\n            const filePath = path.join(this.getDestinationPath(this.currentVersion || undefined), file.fileName);\n\n            try {\n                let fileData;\n                if (this.readFileCache?.filePath === filePath && Array.isArray(this.readFileCache.data)) {\n                    fileData = this.readFileCache.data;\n                } else {\n                    const rawData = await fs.promises.readFile(filePath, \"utf8\");\n                    fileData = deserializeData(rawData, this.metadata.dataType);\n                    this.readFileCache = { filePath, data: fileData };\n                }\n\n                let startIndex = 0;\n                if (i === currentFileIndex) {\n                    startIndex = this.currentRecord - cumulativeRecords;\n                }\n\n                const endIndex = Math.min(startIndex + (effectivePageSize - recordsRead), fileData.length);\n                const recordsFromThisFile = fileData.slice(startIndex, endIndex);\n\n                for (let r = 0; r < recordsFromThisFile.length; r++) {\n                    result.push(recordsFromThisFile[r]);\n                }\n                recordsRead += recordsFromThisFile.length;\n\n                cumulativeRecords += file.recordsCount;\n            } catch (error) {\n                if (error?.code === \"ENOENT\") {\n                    if (!this.lastReadMissingFiles) this.lastReadMissingFiles = [];\n                    this.lastReadMissingFiles.push(file.fileName);\n                    cumulativeRecords += file.recordsCount;\n                    continue;\n                }\n                throw new FileDatabaseError(`Failed to read file ${file.fileName}: ${(error ).message}`);\n            }\n        }\n\n        // Advance by what we actually returned so mid-file seeks + short pages\n        // don't skip records on the next nextPage call.\n        this.currentRecord += recordsRead;\n\n        // Mark page as read for pagination tracking\n        // When nextPage=true, we're explicitly paginating\n        // When nextPage=false with explicit pageSize, we're also paginating (starting from beginning)\n        if (result.length > 0) {\n            if (nextPage || (pageSize !== undefined && pageSize < this.metadata.totalRecords)) {\n                this.hasReadFirstPage = true;\n            }\n        }\n\n        return result;\n    }\n\n    /**\n     * Set the starting record for pagination (1-based index)\n     */\n    setStartRecord(startRecord) {\n        this.currentRecord = startRecord - 1;\n        this.hasReadFirstPage = false;\n        this.readFileCache = null;\n    }\n\n    /**\n     * Reset read pagination state\n     */\n    resetPagination() {\n        this.currentRecord = 0;\n        this.hasReadFirstPage = false;\n        this.readFileCache = null;\n    }\n\n    /**\n     * List filenames in the table directory.\n     * For catalog/key-value usage (files written with { filename }).\n     * Returns data file names (.json, .txt, .xml) excluding metadata.json.\n     */\n    async listFilenames() {\n        const destPath = this.versioned && this.currentVersion\n            ? path.join(this.getDestinationPath(), this.currentVersion)\n            : this.getDestinationPath();\n        try {\n            const entries = await fs.promises.readdir(destPath, { withFileTypes: true });\n            return entries\n                .filter((e) => e.isFile() && e.name !== \"metadata.json\" && /\\.(json|txt|xml)$/i.test(e.name))\n                .map((e) => e.name);\n        } catch (err) {\n            if (err?.code === \"ENOENT\") return [];\n            throw new FileDatabaseError(`Failed to list files: ${(err ).message}`);\n        }\n    }\n\n    /**\n     * Remove a file from the table directory (catalog mode).\n     * Use with listFilenames() to manage individual files.\n     */\n    async removeFile(filename) {\n        const destPath = this.versioned && this.currentVersion\n            ? path.join(this.getDestinationPath(), this.currentVersion)\n            : this.getDestinationPath();\n        const filePath = path.join(destPath, filename);\n        try {\n            await fs.promises.unlink(filePath);\n        } catch (err) {\n            if (err?.code === \"ENOENT\") return;\n            throw new FileDatabaseError(`Failed to remove file ${filename}: ${(err ).message}`);\n        }\n    }\n\n    /**\n     * Remove a file and its metadata entry (non-versioned mode with useMetadata).\n     * Use with findData() to get fileName, then call removeFileEntry to delete.\n     */\n    async removeFileEntry(filename) {\n        if (this.versioned) {\n            throw new FileDatabaseError(\"removeFileEntry is only supported in non-versioned mode\");\n        }\n        await this.prepare({ read: true });\n        const idx = this.metadata.files.findIndex((f) => f.fileName === filename);\n        if (idx === -1) {\n            throw new FileDatabaseError(`File entry ${filename} not found in metadata`);\n        }\n        const entry = this.metadata.files[idx];\n        const recordsCount = entry.recordsCount || 0;\n        this.metadata.files.splice(idx, 1);\n        this.metadata.totalRecords = Math.max(0, (this.metadata.totalRecords || 0) - recordsCount);\n        const destPath = this.getDestinationPath();\n        const filePath = path.join(destPath, filename);\n        try {\n            await fs.promises.unlink(filePath);\n        } catch (err) {\n            if (err?.code === \"ENOENT\") {\n                this.logger.warn?.(`[FileDatabase] File ${filename} already missing on disk`);\n            } else {\n                throw new FileDatabaseError(`Failed to remove file ${filename}: ${(err ).message}`);\n            }\n        }\n        if (this.useMetadata) {\n            await this.saveVersionMetadata(this.metadata);\n        }\n    }\n\n    /**\n     * Set file-level synopsis calculation function\n     */\n    setFileSynopsisFunction(fn) {\n        this.fileSynopsisFunction = fn;\n    }\n\n    /**\n     * Set version-level synopsis calculation function\n     */\n    setVersionSynopsisFunction(fn) {\n        this.versionSynopsisFunction = fn;\n    }\n\n    /**\n     * Get current version name\n     */\n    getCurrentVersion() {\n        return this.currentVersion;\n    }\n\n    /**\n     * Max retained version folders (used by harvest_sync.loaded_versions cap, etc.).\n     */\n    getMaxVersions() {\n        return this.maxVersions;\n    }\n\n    /**\n     * Get current metadata\n     */\n    getMetadata() {\n        return { ...this.metadata };\n    }\n\n    /**\n     * Find data by custom metadata fields\n     * Searches through all versions and files to find entries matching the search criteria\n     * \n     * @param searchCriteria - Object with field names and values to search for (e.g., { ListingKey: \"123\", id: \"456\" })\n     * @returns Array of found entries with their file paths and metadata\n     */\n    async findData(searchCriteria)\n\n\n\n\n\n    {\n        const results\n\n\n\n\n\n = [];\n\n        // Handle non-versioned mode separately\n        if (!this.versioned) {\n            // Load metadata for non-versioned mode\n            await this.prepare({ read: true });\n            const metadata = this.getMetadata();\n            \n            // Search through files\n            for (const fileEntry of metadata.files) {\n                // Check if file entry matches search criteria\n                const matches = Object.keys(searchCriteria).every(key => {\n                    return fileEntry[key] === searchCriteria[key];\n                });\n\n                if (matches) {\n                    // Read the file data\n                    const destPath = this.getDestinationPath();\n                    const filePath = path.join(destPath, fileEntry.fileName);\n                    const fileData = await fs.promises.readFile(filePath, \"utf8\");\n                    const data = deserializeData(fileData, metadata.dataType || \"json-object\");\n\n                    results.push({\n                        filePath,\n                        fileName: fileEntry.fileName,\n                        version: null,\n                        metadata: fileEntry,\n                        data,\n                    });\n                }\n            }\n        } else {\n            // Versioned mode: search through all versions\n            const versions = await this.getVersions();\n            \n            for (const version of versions) {\n                // Load metadata for this version\n                await this.prepare({ read: true, version });\n                const metadata = this.getMetadata();\n\n                // Search through files in this version\n                for (const fileEntry of metadata.files) {\n                    // Check if file entry matches search criteria\n                    const matches = Object.keys(searchCriteria).every(key => {\n                        return fileEntry[key] === searchCriteria[key];\n                    });\n\n                    if (matches) {\n                        // Read the file data\n                        const destPath = this.getDestinationPath(version);\n                        const filePath = path.join(destPath, fileEntry.fileName);\n                        const fileData = await fs.promises.readFile(filePath, \"utf8\");\n                        const data = deserializeData(fileData, metadata.dataType || \"json-object\");\n\n                        results.push({\n                            filePath,\n                            fileName: fileEntry.fileName,\n                            version,\n                            metadata: fileEntry,\n                            data,\n                        });\n                    }\n                }\n            }\n        }\n\n        return results;\n    }\n}\n\n// Export types\n\n\n\n\n\n\n\n\n\n\n\n;\n\n// Export synopsis functions\nexport { defaultFileSynopsisFunction, defaultVersionSynopsisFunction } from \"./synopsis-functions.js\";\n\n/**\n * Initialize FileDatabase from context\n * Similar to MlsClient.init pattern\n * \n * @param context - Context from init()\n * @param options - Optional configuration (takes precedence over context.params)\n * @returns Initialized FileDatabase instance\n */\n/**\n * List all table names in a given namespace\n * Scans the filesystem to find all table directories\n *\n * @param basePath - Base path for file storage\n * @param namespace - Namespace to scan (e.g., \"harvested\", \"fromMLS\")\n * @returns Array of table names (directory names)\n */\nexport function listTables(basePath, namespace) {\n    const namespacePath = path.join(basePath, namespace);\n\n    if (!fs.existsSync(namespacePath)) {\n        return [];\n    }\n\n    try {\n        return fs.readdirSync(namespacePath, { withFileTypes: true })\n            .filter(dirent => dirent.isDirectory())\n            .map(dirent => dirent.name);\n    } catch (error) {\n        // Return empty array if can't read directory\n        return [];\n    }\n}\n\n/**\n * List all sources (namespaces) in a given base path\n * Scans the filesystem to find all namespace directories\n *\n * @param basePath - Base path for file storage\n * @returns Array of source names (directory names)\n */\nexport function listSources(basePath) {\n    if (!fs.existsSync(basePath)) {\n        return [];\n    }\n\n    try {\n        return fs.readdirSync(basePath, { withFileTypes: true })\n            .filter(dirent => dirent.isDirectory())\n            .map(dirent => dirent.name);\n    } catch (error) {\n        // Return empty array if can't read directory\n        return [];\n    }\n}\n","\n\n\n\n\n\n\n\n/**\n * Detect the data type of a given value\n */\nexport function detectDataType(data) {\n    if (Array.isArray(data)) {\n        return \"json-array\";\n    } else if (typeof data === \"object\" && data !== null) {\n        return \"json-object\";\n    } else if (typeof data === \"string\") {\n        // Try to detect if it's XML\n        const trimmed = data.trim();\n        if (trimmed.startsWith(\"<?xml\") || trimmed.startsWith(\"<\")) {\n            return \"xml\";\n        }\n        return \"text\";\n    } else {\n        return \"text\";\n    }\n}\n\n/**\n * Serialize data to a string for file storage\n */\nexport function serializeData(data) {\n    const dataType = detectDataType(data);\n    \n    if (dataType === \"json-array\" || dataType === \"json-object\") {\n        return JSON.stringify(data, null, 4);\n    } else {\n        // For text and XML, return as-is\n        return String(data);\n    }\n}\n\n/**\n * Deserialize data from a string based on data type\n */\nexport function deserializeData(rawData, dataType) {\n    if (dataType === \"json-array\" || dataType === \"json-object\") {\n        return JSON.parse(rawData);\n    } else {\n        // For text and XML, return as-is\n        return rawData;\n    }\n}\n\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n    constructor(message) {\n        super(message);\n        this.name = \"FrameworkError\";\n    }\n}\n\nexport class ParamError extends FrameworkError {\n    constructor(message) {\n        super(message);\n        this.name = \"ParamError\";\n    }\n}\n\nexport class InitError extends FrameworkError {\n    constructor(message) {\n        super(message);\n        this.name = \"InitError\";\n    }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n    constructor(message) {\n        super(message);\n        this.name = \"CriticalRequestError\";\n    }\n}\n\nexport class ControlFlowError extends Error {\n    constructor(message) {\n        super(message);\n        this.name = \"ControlFlowError\";\n    }\n}\n\nexport class HttpClientError extends FrameworkError {\n    constructor(message,   cause) {\n        super(message);this.cause = cause;;\n        this.name = \"HttpClientError\";\n    }\n}\n\nexport class FileDatabaseError extends FrameworkError {\n    constructor(message) {\n        super(message);\n        this.name = \"FileDatabaseError\";\n    }\n}\n\n","import { ParamError } from \"../errors.js\";\n\n/**\n * Base class every task handler extends. Holds the runner `context` and the\n * claimed task row, and defines the contract the runner calls into:\n *\n *   - {@link AbstractTask#cantRunReason}: synchronous / async precondition check.\n *     Returning a truthy string tells the runner \"skip for now, stash the reason\n *     into `progress`\" without burning a retry; returning `false` means \"go\".\n *   - {@link AbstractTask#run}: the actual work, handed a `reportProgress`\n *     callback that updates the DB `progress` column.\n *   - {@link AbstractTask#requestStop}: cooperative shutdown signal from the runner\n *     (noop by default; long-running tasks override to honor it).\n *\n * Static enqueue-time hooks (write-time validation):\n *\n *   - {@link AbstractTask.resolveParams}: build a full row payload (envelope +\n *     inner `params` blob) for {@link enqueueTask}. Subclasses normally do not\n *     override this — they override {@link AbstractTask.resolveCustomParams}\n *     instead. Override here only for envelope-level cross-field rules\n *     (e.g. \"stop tasks must target a specific service_name\").\n *   - {@link AbstractTask.resolveCustomParams}: validate / default the typed\n *     fields that go into the `params` JSON column. Default returns a\n *     `--paramsJson` passthrough; subclasses override.\n *\n * Both static methods are async and accept `(context, overrides)`. `overrides`\n * is a partial that wins over CLI/env values — the typical caller is the\n * {@link TasksRegistry#resolveTaskParams} dispatcher, which seeds it with\n * `{ name }`. Programmatic enqueuers can pass any envelope field plus\n * `overrides.params` to inject inner-blob values.\n */\nexport class AbstractTask {\n    /**\n     * Whether `send-task` should wait for completion (and print a result\n     * report) when no explicit `--wait` / `--noWait` flag is given. Defaults\n     * to false; short-lived probe tasks (e.g. `ping`) override to true.\n     *\n     * @type {boolean}\n     */\n    static defaultWaitForResult = false;\n\n    /**\n     * @param {object} context Runner context (db, logger, params, emitter...).\n     * @param {object} task    Task row as claimed from the queue.\n     */\n    constructor(context, task) {\n        this.context = context;\n        this.task = task;\n        /** @type {boolean} */\n        this._stopRequested = false;\n        /** @type {boolean} */\n        this._pauseRequested = false;\n    }\n\n    /**\n     * Return a short reason string when the task should be deferred (e.g. \"locked\n     * by source\"), or `false`/falsy when it is free to run. Default: always `false`.\n     *\n     * @returns {string | false | Promise<string | false>}\n     */\n    cantRunReason() {\n        return false;\n    }\n\n    /**\n     * Called by the runner when a stop has been requested. Subclasses running\n     * long loops should flip a flag here and check it between iterations.\n     *\n     * @param {number} [_allowanceMs] Grace period the runner promises before hard exit.\n     */\n    requestStop(_allowanceMs) {\n        this._stopRequested = true;\n    }\n\n    /**\n     * Cooperative pause signal (from `pauseTask` control-lane task). Long-running\n     * tasks must persist the resume cursor in `results.checkpointParams` and\n     * return `{ success: true, results: { taskPaused: true, checkpointParams } }`\n     * so the runner keeps the row as `status=paused` and the next claim continues\n     * from that point (not the next window). Hard stop of a scheduled task must\n     * do the same (`checkpointParams` is written on scheduled finalize).\n     *\n     * @param {number} [_allowanceMs]\n     */\n    requestPause(_allowanceMs) {\n        this._pauseRequested = true;\n    }\n\n    /** @returns {boolean} */\n    isStopRequested() {\n        return this._stopRequested === true;\n    }\n\n    /** @returns {boolean} */\n    isPauseRequested() {\n        return this._pauseRequested === true;\n    }\n\n    /**\n     * Perform the task. Must be implemented by subclasses.\n     *\n     * @param {(progress: unknown) => Promise<void>} _reportProgress\n     *        Updates the DB `progress` column. Accepts any serializable value;\n     *        strings are stored verbatim, objects are JSON-stringified.\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run(_reportProgress) {\n        throw new Error(\"AbstractTask.run must be implemented by subclass\");\n    }\n\n    /**\n     * Resolve a complete row payload for this task — envelope fields (queue,\n     * priority, targeting, schedule…) plus the inner `params` blob produced by\n     * {@link AbstractTask.resolveCustomParams}. Output shape matches\n     * {@link enqueueTask}'s `options` argument, so the typical call is:\n     *\n     *   const payload = await TaskClass.resolveParams(context, { name });\n     *   await enqueueTask(context, payload);\n     *\n     * Validation failures throw {@link ParamError} so the script aborts before\n     * a malformed row hits the DB.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides] Partial overrides; takes precedence over CLI/env.\n     *   Recognised keys: `name`, `queueName`, `priority`, `serviceGroup`,\n     *   `serviceName`, `instanceNumber`, `serverName`, `opid`, `schedule`,\n     *   `nextRunAt`, plus `params` (object — overlay onto inner blob).\n     * @returns {Promise<object>}\n     */\n    static async resolveParams(context, overrides = {}) {\n        const main = AbstractTask._resolveMainFields(context, overrides);\n        const params = await this.resolveCustomParams(context, overrides);\n        return { ...main, params };\n    }\n\n    /**\n     * Resolve the inner JSON blob stored in the `params` column. Default\n     * implementation passes through `--paramsJson` (parsed as a JSON object)\n     * overlaid with `overrides.params` when supplied; returns `null` when\n     * neither is provided.\n     *\n     * Subclasses with typed fields should override and call\n     * {@link AbstractTask._mergeTypedParams} for layered CLI/env/JSON/override\n     * resolution, then validate and throw {@link ParamError} on bad input.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<object|null>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        return AbstractTask._defaultParamsBlob(context, overrides);\n    }\n\n    /**\n     * Read main task envelope fields from `context.params` (CLI/env), with\n     * any matching key on `overrides` taking precedence. Internal; called by\n     * {@link AbstractTask.resolveParams}.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {object}\n     */\n    static _resolveMainFields(context, overrides = {}) {\n        const defs = {\n            queueName: \"string default tasks\",\n            priority: \"number default 50\",\n            serviceGroup: \"string\",\n            serviceName: \"string\",\n            instanceNumber: \"number\",\n            serverName: \"string\",\n            opid: \"string\",\n            schedule: \"string\",\n        };\n        const cli = context.params.getAllForModule(\"task-envelope\", defs);\n\n        const name = emptyToUndef(overrides.name) ?? emptyToUndef(context.params.get(\"name\", \"string\"));\n        if (!name) {\n            throw new ParamError(\"Task --name is required (e.g. ping, stop, dummyHarvest)\");\n        }\n\n        let instanceNumber;\n        const rawInstance = overrides.instanceNumber ?? cli.instanceNumber;\n        if (rawInstance !== undefined && rawInstance !== null && String(rawInstance).trim() !== \"\") {\n            const n = Number(rawInstance);\n            if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {\n                throw new ParamError(\"--instanceNumber must be a positive integer when set\");\n            }\n            instanceNumber = n;\n        } else {\n            instanceNumber = null;\n        }\n\n        const priorityRaw = overrides.priority ?? cli.priority ?? 50;\n        const priority = Number(priorityRaw);\n        if (!Number.isFinite(priority)) {\n            throw new ParamError(`--priority must be a number (got ${JSON.stringify(priorityRaw)})`);\n        }\n\n        return {\n            name,\n            queueName: overrides.queueName ?? emptyToUndef(cli.queueName) ?? \"tasks\",\n            priority,\n            serviceGroup: emptyToUndef(overrides.serviceGroup) ?? emptyToUndef(cli.serviceGroup) ?? null,\n            serviceName: emptyToUndef(overrides.serviceName) ?? emptyToUndef(cli.serviceName) ?? null,\n            instanceNumber,\n            serverName: emptyToUndef(overrides.serverName) ?? emptyToUndef(cli.serverName) ?? null,\n            opid: emptyToUndef(overrides.opid) ?? emptyToUndef(cli.opid) ?? null,\n            schedule: emptyToUndef(overrides.schedule) ?? emptyToUndef(cli.schedule) ?? null,\n            nextRunAt: overrides.nextRunAt ?? null,\n        };\n    }\n\n    /**\n     * Default inner-params resolver: parses `--paramsJson` (must be a JSON\n     * object), then overlays `overrides.params` on top. Returns `null` when\n     * neither is provided.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {object|null}\n     */\n    static _defaultParamsBlob(context, overrides = {}) {\n        const cli = context.params.getAllForModule(\"task-params\", { paramsJson: \"string\" });\n        const fromJson = parseParamsJson(cli.paramsJson);\n        const fromOverride = pickParamsObject(overrides);\n        if (!fromJson && !fromOverride) return null;\n        return { ...(fromJson ?? {}), ...(fromOverride ?? {}) };\n    }\n\n    /**\n     * Helper for subclass `resolveCustomParams` overrides. Reads typed CLI\n     * params (per `defs`) plus `--paramsJson` under a module namespace, then\n     * merges them with explicit `overrides.params` in increasing priority:\n     *\n     *   typed CLI flags → --paramsJson → overrides.params\n     *\n     * Undefined values are dropped so defaults declared in `defs` aren't\n     * overwritten by missing-flag noise. Returns the merged object; the\n     * caller is responsible for validation and throwing `ParamError`.\n     *\n     * @param {object} context\n     * @param {string} moduleName Namespace for `--showUsedParams` grouping.\n     * @param {Record<string, string>} defs Param defs in `getAllForModule` syntax.\n     * @param {Record<string, unknown>} [overrides] As passed to `resolveCustomParams`.\n     * @returns {Record<string, unknown>}\n     */\n    static _mergeTypedParams(context, moduleName, defs, overrides = {}) {\n        const fullDefs = { ...defs, paramsJson: \"string\" };\n        const cliRaw = context.params.getAllForModule(moduleName, fullDefs);\n        const fromJson = parseParamsJson(cliRaw.paramsJson) ?? {};\n        const fromCli = {};\n        for (const [k, v] of Object.entries(cliRaw)) {\n            if (k === \"paramsJson\") continue;\n            if (v !== undefined && v !== null) fromCli[k] = v;\n        }\n        const fromOverride = pickParamsObject(overrides) ?? {};\n        return { ...fromCli, ...fromJson, ...fromOverride };\n    }\n}\n\n/** Trim a string-ish to a non-empty string, or return undefined. Non-strings pass through. */\nfunction emptyToUndef(s) {\n    if (s === undefined || s === null) return undefined;\n    if (typeof s !== \"string\") return s;\n    const t = s.trim();\n    return t.length ? t : undefined;\n}\n\n/**\n * Parse a `--paramsJson` value. Returns `null` for empty/missing input.\n * Throws `ParamError` for non-JSON or non-object payloads.\n *\n * @param {unknown} raw\n * @returns {object|null}\n */\nfunction parseParamsJson(raw) {\n    if (raw == null) return null;\n    const t = String(raw).trim();\n    if (!t) return null;\n    let parsed;\n    try {\n        parsed = JSON.parse(t);\n    } catch (e) {\n        throw new ParamError(`--paramsJson: not valid JSON: ${e?.message ?? String(e)}`);\n    }\n    if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n        throw new ParamError(\"--paramsJson must be a JSON object\");\n    }\n    return parsed;\n}\n\n/** Extract `overrides.params` when it is a plain object, else undefined. */\nfunction pickParamsObject(overrides) {\n    const p = overrides?.params;\n    if (p && typeof p === \"object\" && !Array.isArray(p)) return p;\n    return undefined;\n}\n","import { AbstractTask } from \"../AbstractTask.js\";\n\n/**\n * Trivial health-check task: used by `registryMaintenance` to probe runners and\n * by operators to confirm a runner is picking up work. Emits a log line and\n * returns `{ success: true, results: \"pong\" }`.\n */\nexport class TaskPing extends AbstractTask {\n    /** Default-wait so `send-task --name=ping` prints a result without `--wait`. */\n    static defaultWaitForResult = true;\n\n    /** Ping takes no params. */\n    static async resolveCustomParams() {\n        return null;\n    }\n\n    /**\n     * @returns {Promise<{ success: true, results: \"pong\" }>}\n     */\n    async run() {\n        this.context.logger.info?.(`[TaskPing] pong (${this.task.id})`);\n        return { success: true, results: \"pong\" };\n    }\n}\n","import { sleepMs } from \"../../utils/index.js\";\nimport { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\n\n/**\n * Long-running demo task used for exercising the runner's progress/stop paths.\n *\n * Ticks `total` times with `delay` ms between iterations, calling `reportProgress`\n * each tick. Honors cooperative stop (`requestStop`) by completing the current\n * iteration and deciding whether to finish the run or abort based on the\n * remaining work vs. the allowance window.\n */\nexport class TaskSampleProcess extends AbstractTask {\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ total: number, delay: number, name?: string }>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(context, \"task-sample-process\", {\n            total: \"number default 10\",\n            delay: \"number default 1000\",\n            name: \"string\",\n        }, overrides);\n        const total = Number(merged.total);\n        const delay = Number(merged.delay);\n        if (!Number.isInteger(total) || total <= 0) {\n            throw new ParamError(`sampleProcess: param \"total\" must be a positive integer (got ${JSON.stringify(merged.total)})`);\n        }\n        if (!Number.isInteger(delay) || delay < 0) {\n            throw new ParamError(`sampleProcess: param \"delay\" must be an integer >= 0 (got ${JSON.stringify(merged.delay)})`);\n        }\n        const out = { total, delay };\n        if (typeof merged.name === \"string\" && merged.name.trim()) {\n            out.name = merged.name.trim();\n        }\n        return out;\n    }\n\n    /**\n     * @param {object} context\n     * @param {object} task\n     */\n    constructor(context, task) {\n        super(context, task);\n        this.stopRequested = false;\n        this.stopAllowanceMs = 0;\n        this.stopDecisionLogged = false;\n    }\n\n    /**\n     * Runner-facing stop signal. Records the allowance window so the main loop\n     * can decide per-iteration whether to finish or abort early.\n     *\n     * @param {number} allowanceMs\n     */\n    requestStop(allowanceMs) {\n        this.stopRequested = true;\n        this.stopAllowanceMs = Number.isFinite(allowanceMs) && allowanceMs > 0 ? allowanceMs : 0;\n        this.context.logger.warn?.(\n            `[TaskSampleProcess] stop signal received (${this.task.id}), allowanceMs=${this.stopAllowanceMs}`\n        );\n    }\n\n    /**\n     * Iterate `total` times, sleeping `delay` ms between ticks and reporting\n     * progress every iteration. Validates params up front; invalid values short-\n     * circuit to a structured failure without starting the loop.\n     *\n     * @param {(progress: object) => Promise<void>} reportProgress\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run(reportProgress) {\n        const totalRaw = this.task?.params?.total ?? 10;\n        const delayRaw = this.task?.params?.delay ?? 1000;\n        const nameRaw = this.task?.params?.name;\n\n        const total = Number(totalRaw);\n        const delay = Number(delayRaw);\n        const name = typeof nameRaw === \"string\" && nameRaw.trim() ? nameRaw.trim() : \"sampleProcess\";\n\n        const errors = [];\n        if (!Number.isInteger(total) || total <= 0) {\n            errors.push('param \"total\" must be a positive integer');\n        }\n        if (!Number.isInteger(delay) || delay < 0) {\n            errors.push('param \"delay\" must be an integer >= 0');\n        }\n\n        if (errors.length > 0) {\n            return {\n                success: false,\n                results: {\n                    error: `Validation failed: ${errors.join(\", \")}`,\n                    received: { total: totalRaw, delay: delayRaw, name: nameRaw },\n                },\n            };\n        }\n\n        const startedAt = Date.now();\n        for (let i = 1; i <= total; i += 1) {\n            if (this.stopRequested) {\n                const remainingMs = Math.max(0, (total - i + 1) * delay);\n                if (remainingMs <= this.stopAllowanceMs) {\n                    if (!this.stopDecisionLogged) {\n                        this.stopDecisionLogged = true;\n                        this.context.logger.warn?.(\n                            `[TaskSampleProcess] continue to finish (${this.task.id}): remainingMs=${remainingMs} <= allowanceMs=${this.stopAllowanceMs}`\n                        );\n                    }\n                } else {\n                    this.context.logger.warn?.(\n                        `[TaskSampleProcess] stopping gracefully at iteration ${i}/${total} (${this.task.id}), remainingMs=${remainingMs} > allowanceMs=${this.stopAllowanceMs}`\n                    );\n                    return {\n                        success: false,\n                        results: {\n                            message: `Stopped before completion at iteration ${i}/${total}`,\n                            completed: i - 1,\n                            total,\n                            name,\n                            remainingMs,\n                            allowanceMs: this.stopAllowanceMs,\n                        },\n                    };\n                }\n            }\n\n            const elapsed = Date.now() - startedAt;\n            const remaining = Math.max(0, (total - i) * delay);\n            const progress = {\n                name,\n                count: i,\n                total,\n                elapsedMs: elapsed,\n                remainingMs: remaining,\n                status: `running ${name}: ${i}/${total}`,\n            };\n\n            this.context.logger.progress(\"running\", {\n                prefix: name,\n                count: i,\n                total,\n            });\n            await reportProgress(progress);\n            await sleepMs(delay);\n        }\n\n        return {\n            success: true,\n            results: {\n                message: `Completed ${total} iterations`,\n                total,\n                delay,\n                name,\n            },\n        };\n    }\n}\n","import { spawn } from \"node:child_process\";\nimport { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\n\n/**\n * Run a shell string, buffering stdout/stderr until exit. Use for short commands\n * only — everything accumulates in memory; long-running / high-throughput work\n * should spawn its own worker instead (see `taskScriptRunner.js`).\n *\n * @param {string} command\n * @param {string} [cwd]\n * @returns {Promise<{ exitCode: number|null, output: string, stderr: string, signal: NodeJS.Signals|null }>}\n */\nfunction runShellCommand(command, cwd) {\n    return new Promise((resolve, reject) => {\n        const child = spawn(command, {\n            shell: true,\n            cwd: cwd || process.cwd(),\n            stdio: [\"ignore\", \"pipe\", \"pipe\"],\n        });\n\n        let output = \"\";\n        let stderr = \"\";\n\n        child.stdout.on(\"data\", (chunk) => {\n            output += String(chunk);\n        });\n        child.stderr.on(\"data\", (chunk) => {\n            stderr += String(chunk);\n        });\n\n        child.on(\"error\", (error) => {\n            reject(error);\n        });\n\n        child.on(\"close\", (exitCode, signal) => {\n            resolve({\n                exitCode,\n                output: output.trim(),\n                stderr: stderr.trim(),\n                signal,\n            });\n        });\n    });\n}\n\n/**\n * Task wrapper for {@link runShellCommand}. Accepts either:\n *\n *   - `params: \"echo hi\"` (string shortcut), or\n *   - `params: { command: string, cwd?: string }`.\n *\n * Success is defined as `exitCode === 0`. Non-zero / spawn errors come back as\n * `{ success: false, results: { ... } }` — never a thrown exception.\n */\nexport class TaskShellCommand extends AbstractTask {\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ command: string, cwd?: string }>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(context, \"task-shell\", {\n            command: \"string\",\n            cwd: \"string\",\n        }, overrides);\n        const command = typeof merged.command === \"string\" ? merged.command.trim() : \"\";\n        if (!command) {\n            throw new ParamError('shellCommand: param \"command\" must be a non-empty string');\n        }\n        const cwd = typeof merged.cwd === \"string\" && merged.cwd.trim() ? merged.cwd.trim() : null;\n        return cwd ? { command, cwd } : { command };\n    }\n\n    /**\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run() {\n        const params = this.task?.params;\n        const commandRaw = typeof params === \"string\" ? params : params?.command;\n        const cwdRaw = typeof params === \"string\" ? undefined : params?.cwd;\n        const command = typeof commandRaw === \"string\" ? commandRaw.trim() : \"\";\n        const cwd = typeof cwdRaw === \"string\" && cwdRaw.trim() ? cwdRaw.trim() : undefined;\n\n        if (!command) {\n            return {\n                success: false,\n                results: {\n                    error: 'Validation failed: param \"command\" must be a non-empty string',\n                    received: this.task?.params ?? null,\n                },\n            };\n        }\n\n        try {\n            const result = await runShellCommand(command, cwd);\n            const success = result.exitCode === 0;\n\n            this.context.logger.info?.(\n                `[TaskShellCommand] command=\"${command}\" exitCode=${String(result.exitCode)} (${this.task.id})`\n            );\n\n            return {\n                success,\n                results: {\n                    command,\n                    cwd: cwd ?? process.cwd(),\n                    output: result.output,\n                    stderr: result.stderr,\n                    exitCode: result.exitCode,\n                    signal: result.signal,\n                },\n            };\n        } catch (error) {\n            return {\n                success: false,\n                results: {\n                    command,\n                    cwd: cwd ?? process.cwd(),\n                    output: \"\",\n                    stderr: \"\",\n                    exitCode: null,\n                    error: error?.message ?? String(error),\n                },\n            };\n        }\n    }\n}\n","import os from \"node:os\";\nimport fs from \"node:fs/promises\";\nimport { AbstractTask } from \"../AbstractTask.js\";\n\n/**\n * Format bytes as a human-readable gigabyte string, e.g. `\"3.25 GB\"`.\n *\n * @param {number} valueBytes\n * @returns {string}\n */\nfunction toGb(valueBytes) {\n    return `${(valueBytes / (1024 ** 3)).toFixed(2)} GB`;\n}\n\n/**\n * Format bytes as a human-readable megabyte string, e.g. `\"128.00 MB\"`.\n *\n * @param {number} valueBytes\n * @returns {string}\n */\nfunction toMb(valueBytes) {\n    return `${(valueBytes / (1024 ** 2)).toFixed(2)} MB`;\n}\n\n/**\n * Disk usage for `/` as `{ total, used, free }` strings. Uses `fs.statfs`\n * (Node 20+); for host-level signal we probe the root mount rather than the cwd.\n *\n * @returns {Promise<{ total: string, used: string, free: string }>}\n */\nasync function getDiskStats() {\n    // Node 20+ statfs; use root path for host-level signal.\n    const stats = await fs.statfs(\"/\");\n    const total = Number(stats.bsize) * Number(stats.blocks);\n    const free = Number(stats.bsize) * Number(stats.bavail);\n    const used = total - free;\n    return {\n        total: toGb(total),\n        used: toGb(used),\n        free: toGb(free),\n    };\n}\n\n/**\n * Snapshot of host + process stats (memory, CPU utilization, disk, runtime info).\n * Useful for ops dashboards and cluster-wide \"ping with telemetry\".\n */\nexport class TaskSystemInfo extends AbstractTask {\n    /** Same UX expectation as `ping` — short probe, print the result. */\n    static defaultWaitForResult = true;\n\n    /** systemInfo takes no params. */\n    static async resolveCustomParams() {\n        return null;\n    }\n\n    /**\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run() {\n        try {\n            const totalMemory = os.totalmem();\n            const freeMemory = os.freemem();\n            const usedMemory = totalMemory - freeMemory;\n\n            const cpus = os.cpus();\n            const cpuUtilization = cpus.map((cpu) => {\n                const total = Object.values(cpu.times).reduce((acc, time) => acc + time, 0);\n                const usage = ((total - cpu.times.idle) / total) * 100;\n                return Number(usage.toFixed(2));\n            });\n\n            const processMemory = process.memoryUsage();\n            const disk = await getDiskStats();\n\n            const results = {\n                memory: {\n                    total: toGb(totalMemory),\n                    used: toGb(usedMemory),\n                    free: toGb(freeMemory),\n                },\n                processMemory: {\n                    rss: toMb(processMemory.rss),\n                    heapTotal: toMb(processMemory.heapTotal),\n                    heapUsed: toMb(processMemory.heapUsed),\n                    external: toMb(processMemory.external),\n                },\n                disk,\n                cpu: {\n                    cores: cpuUtilization.length,\n                    utilization: cpuUtilization,\n                },\n                runtime: {\n                    platform: os.platform(),\n                    arch: os.arch(),\n                    uptimeSec: os.uptime(),\n                    hostname: os.hostname(),\n                },\n            };\n\n            this.context.logger.info?.(`[TaskSystemInfo] collected system metrics (${this.task.id})`);\n            return { success: true, results };\n        } catch (error) {\n            return {\n                success: false,\n                results: {\n                    error: \"Can't collect system stats\",\n                    message: error?.message ?? String(error),\n                },\n            };\n        }\n    }\n}\n","import { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\n\n/**\n * Sanity-check task for wiring: reads `params.a` and `params.b` (both numbers),\n * returns `{ a, b, sum }`. Any non-numeric input short-circuits to a structured\n * validation failure, not an exception.\n */\nexport class TaskSumAB extends AbstractTask {\n    /** Short, deterministic — wait by default so callers see the sum. */\n    static defaultWaitForResult = true;\n\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ a: number, b: number }>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(context, \"task-sumab\", {\n            a: \"number\",\n            b: \"number\",\n        }, overrides);\n        if (typeof merged.a !== \"number\" || Number.isNaN(merged.a)) {\n            throw new ParamError(`taskSumAB: param \"a\" must be a valid number (got ${JSON.stringify(merged.a)})`);\n        }\n        if (typeof merged.b !== \"number\" || Number.isNaN(merged.b)) {\n            throw new ParamError(`taskSumAB: param \"b\" must be a valid number (got ${JSON.stringify(merged.b)})`);\n        }\n        return { a: merged.a, b: merged.b };\n    }\n\n    /**\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run() {\n        const a = this.task?.params?.a;\n        const b = this.task?.params?.b;\n\n        if (typeof a !== \"number\" || Number.isNaN(a)) {\n            return {\n                success: false,\n                results: {\n                    error: 'Validation failed: param \"a\" must be a valid number',\n                    received: { a, b },\n                },\n            };\n        }\n\n        if (typeof b !== \"number\" || Number.isNaN(b)) {\n            return {\n                success: false,\n                results: {\n                    error: 'Validation failed: param \"b\" must be a valid number',\n                    received: { a, b },\n                },\n            };\n        }\n\n        const sum = a + b;\n        this.context.logger.info?.(`[TaskSumAB] ${a} + ${b} = ${sum} (${this.task.id})`);\n        return {\n            success: true,\n            results: { a, b, sum },\n        };\n    }\n}\n","import { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\n\n/**\n * Cooperative stop signal for the runner that claims it. Returns a result with\n * `stopRunner: true`; `runTasksLoop` sees that flag in `executeClaimedTask`'s\n * outcome and flips its own stop state, propagating `requestStop(allowanceMs)`\n * to every currently-running task.\n *\n * `params.allowanceMs` controls the grace window (default 60000 ms).\n */\nexport class TaskStopRunner extends AbstractTask {\n    /**\n     * Stop tasks must target a concrete instance — without `serviceName` the\n     * row would race against any worker on the queue. Layered on top of the\n     * envelope built by {@link AbstractTask.resolveParams}.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<object>}\n     */\n    static async resolveParams(context, overrides = {}) {\n        const main = await super.resolveParams(context, overrides);\n        if (!main.serviceName) {\n            throw new ParamError(\n                \"stop/stopRunner requires --serviceName (registry instance name; optional --serviceGroup, --instanceNumber, --serverName to narrow targeting)\"\n            );\n        }\n        return main;\n    }\n\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ allowanceMs: number }>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(context, \"task-stop\", {\n            allowanceMs: \"number default 60000\",\n        }, overrides);\n        const allowanceMs = Number(merged.allowanceMs);\n        if (!Number.isFinite(allowanceMs) || allowanceMs < 0) {\n            throw new ParamError(\n                `stopRunner: allowanceMs must be a non-negative number (got ${JSON.stringify(merged.allowanceMs)})`\n            );\n        }\n        return { allowanceMs };\n    }\n\n    /**\n     * @returns {Promise<{ success: true, results: { stopRunner: true, allowanceMs: number, message: string } }>}\n     */\n    async run() {\n        const allowanceMs = Number(this.task?.params?.allowanceMs ?? 60_000);\n        this.context.logger.warn?.(`[TaskStopRunner] stop requested (allowanceMs=${allowanceMs})`);\n        return {\n            success: true,\n            results: {\n                stopRunner: true,\n                allowanceMs,\n                message: \"Runner stop requested\",\n            },\n        };\n    }\n}\n","import { ParamError } from \"../errors.js\";\nimport { updateServicesRegistryMetadata } from \"./servicesRegistry.js\";\n\n/** Keys the tasks loop re-reads every tick from `context.tasksRuntime`. */\nexport const LOOP_RUNTIME_KEYS = [\"maxParallel\", \"pollMs\", \"claimJitterMs\", \"scanLimit\"];\n\n/** Keys applied via `context.logger.configure(...)`. */\nexport const LOGGER_RUNTIME_KEYS = [\n    \"levels\",\n    \"silent\",\n    \"showLevel\",\n    \"timestamp\",\n    \"mode\",\n    \"route\",\n    \"prefix\",\n    \"progressWithTimes\",\n    \"progressWithRate\",\n    \"progressThrottleMs\",\n];\n\n/**\n * Declared knobs operators may edit via setRuntimeParam / tasksmm \"Change param(s)\".\n * Written into services_registry `metadata.runtimeParams` at registration.\n *\n * @typedef {{\n *   key: string,\n *   type: \"number\" | \"boolean\" | \"string\",\n *   label: string,\n *   description?: string,\n * }} RuntimeParamSpec\n */\n\n/** @type {RuntimeParamSpec[]} */\nexport const DEFAULT_RUNTIME_PARAM_SPECS = [\n    {\n        key: \"maxParallel\",\n        type: \"number\",\n        label: \"Max parallel\",\n        description: \"Worker-lane concurrency (how many tasks claim at once)\",\n    },\n    {\n        key: \"pollMs\",\n        type: \"number\",\n        label: \"Poll ms\",\n        description: \"Idle poll interval between claim attempts\",\n    },\n    {\n        key: \"claimJitterMs\",\n        type: \"number\",\n        label: \"Claim jitter ms\",\n        description: \"Random delay before worker claims (0 = off)\",\n    },\n    {\n        key: \"scanLimit\",\n        type: \"number\",\n        label: \"Scan limit\",\n        description: \"Max idle rows scanned per claim attempt\",\n    },\n    {\n        key: \"tasksRetentionEnabled\",\n        type: \"boolean\",\n        label: \"Retention enabled\",\n        description: \"Prune tasks_history + IPC logs together\",\n    },\n    {\n        key: \"tasksRetentionDays\",\n        type: \"number\",\n        label: \"Retention days\",\n        description: \"Keep history and IPC logs this many days (0 = off)\",\n    },\n    {\n        key: \"tasksRetentionIntervalMs\",\n        type: \"number\",\n        label: \"Retention interval ms\",\n        description: \"How often the runner checks for stale history/logs\",\n    },\n    {\n        key: \"tasksRetentionMinFreeRatio\",\n        type: \"number\",\n        label: \"Min free disk ratio\",\n        description: \"If free/total on the logs volume is below this, prune earlier\",\n    },\n    {\n        key: \"tasksRetentionMinHours\",\n        type: \"number\",\n        label: \"Min retention hours\",\n        description: \"Floor when disk is low (never prune newer than this)\",\n    },\n    {\n        key: \"tasksRetentionNameRules\",\n        type: \"string\",\n        label: \"Per-task retention (JSON)\",\n        description: 'Shorter windows by task name, e.g. {\"processListingPhotos\":12} (hours)',\n    },\n];\n\n/**\n * Normalize / merge runner-supplied specs with defaults (by key; extras append).\n *\n * @param {RuntimeParamSpec[] | undefined | null} [extra]\n * @returns {RuntimeParamSpec[]}\n */\nexport function mergeRuntimeParamSpecs(extra) {\n    const byKey = new Map(DEFAULT_RUNTIME_PARAM_SPECS.map((s) => [s.key, { ...s }]));\n    if (Array.isArray(extra)) {\n        for (const raw of extra) {\n            if (!raw || typeof raw !== \"object\") continue;\n            const key = String(raw.key ?? \"\").trim();\n            if (!key) continue;\n            const prev = byKey.get(key) ?? {};\n            const type = [\"number\", \"boolean\", \"string\"].includes(raw.type) ? raw.type : prev.type ?? \"string\";\n            byKey.set(key, {\n                key,\n                type,\n                label: String(raw.label ?? prev.label ?? key),\n                description:\n                    raw.description != null\n                        ? String(raw.description)\n                        : prev.description != null\n                          ? String(prev.description)\n                          : undefined,\n            });\n        }\n    }\n    return Array.from(byKey.values());\n}\n\n/**\n * Snapshot current values for the given specs from `context.tasksRuntime`.\n *\n * @param {object} context\n * @param {RuntimeParamSpec[]} [specs]\n * @returns {Record<string, unknown>}\n */\nexport function runtimeValuesForSpecs(context, specs = DEFAULT_RUNTIME_PARAM_SPECS) {\n    const rt = ensureTasksRuntime(context);\n    const out = {};\n    for (const s of specs) {\n        if (rt[s.key] !== undefined) out[s.key] = rt[s.key];\n    }\n    return out;\n}\n\n/**\n * Parse specs from registry metadata (tolerant of older runners).\n *\n * @param {unknown} metadata\n * @returns {RuntimeParamSpec[]}\n */\nexport function runtimeParamSpecsFromMetadata(metadata) {\n    const meta = metadata && typeof metadata === \"object\" ? metadata : null;\n    const raw = meta?.runtimeParams;\n    if (!Array.isArray(raw) || raw.length === 0) {\n        return mergeRuntimeParamSpecs();\n    }\n    return mergeRuntimeParamSpecs(raw);\n}\n\nconst CONTROL_LANE_TASK_NAMES = [\n    \"stopRunner\",\n    \"stop\",\n    \"pauseRunner\",\n    \"pause\",\n    \"unpauseRunner\",\n    \"unpause\",\n    \"pauseTask\",\n    \"resumeTask\",\n    \"setRuntimeParam\",\n    \"setRunnerParam\",\n    \"pruneTaskRetention\",\n];\n\n/**\n * Task names claimed on the dedicated control lane (even when workers are saturated).\n * Pass `extra` from `runTasksLoop({ controlLaneTasks })` for app-specific ops\n * probes (e.g. v2 `hostInfo`) that must run while regular workers are full.\n *\n * @param {string|string[]|undefined|null} [extra]\n * @returns {string[]}\n */\nexport function controlLaneTaskNames(extra) {\n    const names = [...CONTROL_LANE_TASK_NAMES];\n    if (extra == null || extra === \"\") return names;\n    const more = Array.isArray(extra) ? extra : String(extra).split(\",\");\n    const seen = new Set(names);\n    for (const raw of more) {\n        const n = String(raw ?? \"\").trim();\n        if (!n || seen.has(n)) continue;\n        seen.add(n);\n        names.push(n);\n    }\n    return names;\n}\n\n/**\n * @param {unknown} value\n * @param {string} key\n * @returns {number}\n */\nfunction asPositiveInt(value, key, { min = 1 } = {}) {\n    const n = Number(value);\n    if (!Number.isFinite(n) || n < min) {\n        throw new ParamError(\n            `setRuntimeParam: ${key} must be a number >= ${min} (got ${JSON.stringify(value)})`\n        );\n    }\n    return Math.floor(n);\n}\n\n/**\n * Coerce / validate a single runtime value for a known key.\n * Unknown keys pass through unchanged (apps may handle via onRuntimeParam).\n *\n * @param {string} key\n * @param {unknown} value\n * @returns {unknown}\n */\nexport function coerceRuntimeValue(key, value) {\n    switch (key) {\n        case \"maxParallel\":\n            return asPositiveInt(value, key, { min: 1 });\n        case \"pollMs\":\n            return asPositiveInt(value, key, { min: 50 });\n        case \"claimJitterMs\":\n            return asPositiveInt(value, key, { min: 0 });\n        case \"scanLimit\":\n            return asPositiveInt(value, key, { min: 1 });\n        case \"tasksRetentionDays\":\n            return asPositiveInt(value, key, { min: 0 });\n        case \"tasksRetentionIntervalMs\":\n            return asPositiveInt(value, key, { min: 10_000 });\n        case \"tasksRetentionMinHours\":\n            return asPositiveInt(value, key, { min: 1 });\n        case \"tasksRetentionMinFreeRatio\": {\n            const n = Number(value);\n            if (!Number.isFinite(n) || n <= 0 || n >= 1) {\n                throw new ParamError(\n                    `setRuntimeParam: ${key} must be a number between 0 and 1 (got ${JSON.stringify(value)})`,\n                );\n            }\n            return n;\n        }\n        case \"tasksRetentionEnabled\":\n            if (typeof value === \"boolean\") return value;\n            if (value === \"true\" || value === \"1\") return true;\n            if (value === \"false\" || value === \"0\") return false;\n            throw new ParamError(\n                `setRuntimeParam: ${key} must be boolean (got ${JSON.stringify(value)})`,\n            );\n        case \"silent\":\n        case \"showLevel\":\n        case \"timestamp\":\n        case \"progressWithTimes\":\n        case \"progressWithRate\":\n            if (typeof value === \"boolean\") return value;\n            if (value === \"true\" || value === \"1\") return true;\n            if (value === \"false\" || value === \"0\") return false;\n            throw new ParamError(\n                `setRuntimeParam: ${key} must be boolean (got ${JSON.stringify(value)})`\n            );\n        case \"progressThrottleMs\":\n            return asPositiveInt(value, key, { min: 0 });\n        case \"levels\":\n        case \"mode\":\n        case \"route\":\n        case \"prefix\":\n            return value;\n        default:\n            return value;\n    }\n}\n\n/**\n * Ensure `context.tasksRuntime` exists (used by the loop and by setRuntimeParam).\n *\n * @param {object} context\n * @param {Partial<{ maxParallel: number, pollMs: number, claimJitterMs: number, scanLimit: number, paused: boolean }>} [seed]\n * @returns {Record<string, unknown>}\n */\nexport function ensureTasksRuntime(context, seed = {}) {\n    if (!context.tasksRuntime || typeof context.tasksRuntime !== \"object\") {\n        context.tasksRuntime = {};\n    }\n    const rt = context.tasksRuntime;\n    if (rt.maxParallel === undefined) rt.maxParallel = seed.maxParallel ?? 32;\n    if (rt.pollMs === undefined) rt.pollMs = seed.pollMs ?? 1000;\n    if (rt.claimJitterMs === undefined) rt.claimJitterMs = seed.claimJitterMs ?? 0;\n    if (rt.scanLimit === undefined) rt.scanLimit = seed.scanLimit ?? 100;\n    if (rt.paused === undefined) rt.paused = seed.paused === true;\n    return rt;\n}\n\n/**\n * Apply one key/value to the running process. Mutates `context.tasksRuntime`,\n * updates logger when relevant, invokes optional `context.tasksRuntimeOnParam`.\n *\n * @param {object} context\n * @param {string} key\n * @param {unknown} value\n * @returns {Promise<{ key: string, previous: unknown, next: unknown, applied: string[] }>}\n */\nexport async function applyRuntimeParam(context, key, value) {\n    const k = String(key ?? \"\").trim();\n    if (!k) throw new ParamError(\"setRuntimeParam: key is required\");\n\n    const runtime = ensureTasksRuntime(context);\n    const next = coerceRuntimeValue(k, value);\n    const previous = runtime[k];\n    const applied = [];\n\n    runtime[k] = next;\n    applied.push(\"tasksRuntime\");\n\n    if (LOGGER_RUNTIME_KEYS.includes(k) && context.logger?.configure) {\n        context.logger.configure({ [k]: next });\n        applied.push(\"logger\");\n    }\n\n    const hook = context.tasksRuntimeOnParam;\n    if (typeof hook === \"function\") {\n        await hook(k, next, runtime, context);\n        applied.push(\"onRuntimeParam\");\n    }\n\n    const reg = context.servicesRegistry;\n    if (reg?.rowId && reg?.registryTable) {\n        try {\n            // Prefer specs declared at loop start (also in registry metadata.runtimeParams).\n            const specs = Array.isArray(context.tasksRuntimeParamSpecs)\n                ? context.tasksRuntimeParamSpecs\n                : DEFAULT_RUNTIME_PARAM_SPECS;\n            const runtimeSnapshot = runtimeValuesForSpecs(context, specs);\n            for (const lk of LOOP_RUNTIME_KEYS) {\n                if (runtime[lk] !== undefined && runtimeSnapshot[lk] === undefined) {\n                    runtimeSnapshot[lk] = runtime[lk];\n                }\n            }\n            await updateServicesRegistryMetadata(context, reg, {\n                runtime: runtimeSnapshot,\n                runtimeUpdatedAt: new Date().toISOString(),\n            });\n            applied.push(\"servicesRegistry\");\n        } catch (err) {\n            context.logger?.warn?.(\n                `[setRuntimeParam] registry metadata update failed: ${err?.message ?? String(err)}`\n            );\n        }\n    }\n\n    return { key: k, previous, next, applied };\n}\n\n/**\n * Apply a patch object `{ key: value, ... }` sequentially.\n *\n * @param {object} context\n * @param {Record<string, unknown>} patch\n * @returns {Promise<Array<{ key: string, previous: unknown, next: unknown, applied: string[] }>>}\n */\nexport async function applyRuntimePatch(context, patch) {\n    if (!patch || typeof patch !== \"object\" || Array.isArray(patch)) {\n        throw new ParamError(\"setRuntimeParam: patch must be a plain object\");\n    }\n    const entries = Object.entries(patch);\n    if (entries.length === 0) {\n        throw new ParamError(\"setRuntimeParam: patch is empty\");\n    }\n    const out = [];\n    for (const [key, value] of entries) {\n        out.push(await applyRuntimeParam(context, key, value));\n    }\n    return out;\n}\n\n/**\n * Read loop knobs from `context.tasksRuntime` with sane clamps.\n *\n * @param {object} context\n * @returns {{ maxParallel: number, pollMs: number, claimJitterMs: number, scanLimit: number }}\n */\nexport function readLoopRuntime(context) {\n    const rt = ensureTasksRuntime(context);\n    return {\n        maxParallel: Math.max(1, Number(rt.maxParallel) || 1),\n        pollMs: Math.max(50, Number(rt.pollMs) || 1000),\n        claimJitterMs: Math.max(0, Number(rt.claimJitterMs) || 0),\n        scanLimit: Math.max(1, Number(rt.scanLimit) || 100),\n    };\n}\n","/**\n * Pause / unpause a task runner service.\n *\n * When paused, the runner finishes in-flight worker tasks and does not claim new\n * worker-lane work until unpaused. Control-lane tasks (stop, pause, unpause,\n * setRuntimeParam, …) still run.\n *\n * Target a service via `--serviceName` (same shape as stopRunner). Persists\n * `metadata.paused` on services_registry for operators / TUI status.\n *\n * Aliases: `pause` / `unpause`.\n */\n\nimport { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\nimport { updateServicesRegistryMetadata } from \"../servicesRegistry.js\";\nimport { ensureTasksRuntime } from \"../runtimeParams.js\";\n\n/**\n * @param {object} context\n * @param {boolean} paused\n * @returns {Promise<{ success: true, results: { paused: boolean, message: string } }>}\n */\nexport async function applyRunnerPaused(context, paused) {\n    const runtime = ensureTasksRuntime(context);\n    const was = runtime.paused === true;\n    runtime.paused = paused === true;\n\n    const registry = context.servicesRegistry;\n    if (registry && typeof registry === \"object\") {\n        await updateServicesRegistryMetadata(context, registry, {\n            paused: runtime.paused,\n            pausedAt: runtime.paused ? new Date().toISOString() : null,\n        });\n    }\n\n    const message = runtime.paused\n        ? was\n            ? \"Runner already paused (no new worker tasks).\"\n            : \"Runner paused: finishing in-flight work; no new worker tasks until unpause.\"\n        : was\n          ? \"Runner unpaused: claiming worker tasks again.\"\n          : \"Runner already running (not paused).\";\n\n    context.logger?.warn?.(\n        runtime.paused ? `[TaskPauseRunner] ${message}` : `[TaskUnpauseRunner] ${message}`\n    );\n\n    return {\n        success: true,\n        results: {\n            paused: runtime.paused,\n            message,\n        },\n    };\n}\n\n/**\n * Pause worker claiming on the targeted service.\n */\nexport class TaskPauseRunner extends AbstractTask {\n    static taskName = \"pauseRunner\";\n    static description =\n        \"Pause a runner: finish in-flight tasks, claim no new worker tasks until unpaused\";\n    static aliases = [\"pause\"];\n    static defaultWaitForResult = true;\n\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<object>}\n     */\n    static async resolveParams(context, overrides = {}) {\n        const main = await super.resolveParams(context, overrides);\n        if (!main.serviceName) {\n            throw new ParamError(\n                \"pause/pauseRunner requires --serviceName (registry instance name; optional --serviceGroup, --instanceNumber, --serverName to narrow targeting)\"\n            );\n        }\n        return main;\n    }\n\n    async run() {\n        return applyRunnerPaused(this.context, true);\n    }\n}\n\n/**\n * Resume worker claiming on the targeted service.\n */\nexport class TaskUnpauseRunner extends AbstractTask {\n    static taskName = \"unpauseRunner\";\n    static description = \"Unpause a runner: resume claiming worker tasks\";\n    static aliases = [\"unpause\"];\n    static defaultWaitForResult = true;\n\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<object>}\n     */\n    static async resolveParams(context, overrides = {}) {\n        const main = await super.resolveParams(context, overrides);\n        if (!main.serviceName) {\n            throw new ParamError(\n                \"unpause/unpauseRunner requires --serviceName (registry instance name; optional --serviceGroup, --instanceNumber, --serverName to narrow targeting)\"\n            );\n        }\n        return main;\n    }\n\n    async run() {\n        return applyRunnerPaused(this.context, false);\n    }\n}\n","/**\n * Pause / resume a single queue task (not the runner).\n *\n * pauseTask:\n *   - idle → status=paused (persists across runner restart/redeploy)\n *   - running → stamp progress.pauseRequested + call requestPause() on the\n *     in-process instance when this runner owns it; the task cooperatively\n *     finishes its current unit and returns `{ taskPaused: true }`\n *   - already paused → no-op success\n *\n * resumeTask:\n *   - paused → status=idle (clears pauseRequested)\n *   - stamps `past_due` + `next_run_at` so a scheduled row is claimed on the\n *     next poll (does not wait for the next cron slot)\n *\n * Both are control-lane tasks so they run even when workers are saturated or\n * the runner itself is paused.\n */\n\nimport { ParamError } from \"../../errors.js\";\nimport { toJsonColumn } from \"../../utils/index.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\nimport { queueToTableNames } from \"../taskUtils.js\";\n\n/**\n * @param {unknown} progress\n * @returns {Record<string, unknown>}\n */\nfunction parseProgressObject(progress) {\n    if (progress == null || progress === \"\") return {};\n    if (typeof progress === \"object\" && !Array.isArray(progress)) {\n        return { ...progress };\n    }\n    if (typeof progress === \"string\") {\n        const t = progress.trim();\n        if (t.startsWith(\"{\") || t.startsWith(\"[\")) {\n            try {\n                const parsed = JSON.parse(t);\n                if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) return { ...parsed };\n            } catch {\n                /* keep as message */\n            }\n        }\n        return { message: progress };\n    }\n    return { message: String(progress) };\n}\n\n/**\n * @param {object} context\n * @param {string} taskId\n * @returns {Promise<{ success: boolean, results: object }>}\n */\nexport async function applyPauseTask(context, taskId) {\n    const db = context.db;\n    if (!db) throw new Error(\"pauseTask: context.db is required\");\n    const id = String(taskId ?? \"\").trim();\n    if (!id) throw new ParamError('pauseTask: param \"taskId\" is required');\n\n    const { tasksTable } = queueToTableNames(context.tasksQueueName ?? \"tasks\");\n    const row = await db(tasksTable).where({ id }).first();\n    if (!row) {\n        return { success: false, results: { error: `Task ${id} not found`, taskId: id } };\n    }\n\n    if (row.status === \"paused\") {\n        return {\n            success: true,\n            results: { taskId: id, status: \"paused\", message: \"Task already paused\" },\n        };\n    }\n\n    if (row.status === \"idle\") {\n        const progress = parseProgressObject(row.progress);\n        progress.pauseRequested = true;\n        progress.pausedAt = new Date().toISOString();\n        await db(tasksTable).where({ id }).update({\n            status: \"paused\",\n            status_changed_at: db.fn.now(),\n            progress: toJsonColumn(progress),\n        });\n        context.logger?.warn?.(`[pauseTask] idle task ${id} (${row.name}) → paused`);\n        return {\n            success: true,\n            results: { taskId: id, status: \"paused\", message: \"Idle task paused\" },\n        };\n    }\n\n    if (row.status === \"running\") {\n        const progress = parseProgressObject(row.progress);\n        progress.pauseRequested = true;\n        progress.pauseRequestedAt = new Date().toISOString();\n        await db(tasksTable).where({ id }).update({\n            progress: toJsonColumn(progress),\n        });\n\n        const inst = context.runningTaskInstances?.get?.(id);\n        if (inst && typeof inst.requestPause === \"function\") {\n            await inst.requestPause();\n            context.logger?.warn?.(\n                `[pauseTask] signaled running task ${id} (${row.name}) to pause after current unit`,\n            );\n            return {\n                success: true,\n                results: {\n                    taskId: id,\n                    status: \"running\",\n                    signaled: true,\n                    message: \"Pause requested; task will finish current unit then park as paused\",\n                },\n            };\n        }\n\n        context.logger?.warn?.(\n            `[pauseTask] stamped pauseRequested on ${id} (${row.name}) — not running in this process`,\n        );\n        return {\n            success: true,\n            results: {\n                taskId: id,\n                status: \"running\",\n                signaled: false,\n                message:\n                    \"pauseRequested stamped on task row; target runner must observe it (enqueue pauseTask on that service)\",\n            },\n        };\n    }\n\n    return {\n        success: false,\n        results: {\n            error: `Cannot pause task in status \"${row.status}\"`,\n            taskId: id,\n            status: row.status,\n        },\n    };\n}\n\n/**\n * @param {object} context\n * @param {string} taskId\n * @returns {Promise<{ success: boolean, results: object }>}\n */\nexport async function applyResumeTask(context, taskId) {\n    const db = context.db;\n    if (!db) throw new Error(\"resumeTask: context.db is required\");\n    const id = String(taskId ?? \"\").trim();\n    if (!id) throw new ParamError('resumeTask: param \"taskId\" is required');\n\n    const { tasksTable } = queueToTableNames(context.tasksQueueName ?? \"tasks\");\n    const row = await db(tasksTable).where({ id }).first();\n    if (!row) {\n        return { success: false, results: { error: `Task ${id} not found`, taskId: id } };\n    }\n\n    if (row.status === \"idle\") {\n        return {\n            success: true,\n            results: { taskId: id, status: \"idle\", message: \"Task already idle (runnable)\" },\n        };\n    }\n\n    if (row.status !== \"paused\") {\n        return {\n            success: false,\n            results: {\n                error: `Cannot resume task in status \"${row.status}\" (expected paused)`,\n                taskId: id,\n                status: row.status,\n            },\n        };\n    }\n\n    const progress = parseProgressObject(row.progress);\n    delete progress.pauseRequested;\n    delete progress.pauseRequestedAt;\n    delete progress.pausedAt;\n    progress.resumedAt = new Date().toISOString();\n\n    const now = new Date();\n    await db(tasksTable).where({ id }).update({\n        status: \"idle\",\n        status_changed_at: db.fn.now(),\n        started_at: null,\n        completed_at: null,\n        success: null,\n        progress: toJsonColumn(progress),\n        // Clear claim binding so any matching worker can pick it up.\n        service_name: null,\n        server_name: null,\n        instance_number: null,\n        // Claim skips scheduled rows until cron matches unless past_due is set.\n        next_run_at: now,\n        past_due: now,\n    });\n\n    context.logger?.warn?.(`[resumeTask] paused task ${id} (${row.name}) → idle (run now)`);\n    return {\n        success: true,\n        results: { taskId: id, status: \"idle\", message: \"Task resumed (idle; will be claimed now)\" },\n    };\n}\n\nexport class TaskPauseTask extends AbstractTask {\n    static taskName = \"pauseTask\";\n    static description = \"Pause a specific task: finish current unit, persist status=paused\";\n    static defaultWaitForResult = true;\n\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(\n            context,\n            \"task-pause-task\",\n            { taskId: \"string\" },\n            overrides,\n        );\n        const taskId = typeof merged.taskId === \"string\" ? merged.taskId.trim() : \"\";\n        if (!taskId) throw new ParamError('pauseTask: param \"taskId\" is required');\n        return { taskId };\n    }\n\n    async run() {\n        return applyPauseTask(this.context, this.task?.params?.taskId);\n    }\n}\n\nexport class TaskResumeTask extends AbstractTask {\n    static taskName = \"resumeTask\";\n    static description = \"Resume a paused task (status paused → idle)\";\n    static defaultWaitForResult = true;\n\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(\n            context,\n            \"task-resume-task\",\n            { taskId: \"string\" },\n            overrides,\n        );\n        const taskId = typeof merged.taskId === \"string\" ? merged.taskId.trim() : \"\";\n        if (!taskId) throw new ParamError('resumeTask: param \"taskId\" is required');\n        return { taskId };\n    }\n\n    async run() {\n        return applyResumeTask(this.context, this.task?.params?.taskId);\n    }\n}\n","import { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\nimport { readTaskIpcLogsSnapshot } from \"../taskLogs.js\";\n\n/**\n * Fetches IPC FileDatabase rows for `dummyHarvest` (and similar) logs keyed by params.source / params.resource.\n * Intended for machine-targeted enqueue (`server_name` set, `service_group` null) so any runner on that host can execute.\n *\n * Params:\n *   - `source`   (required) — logical source name, e.g. `\"actris\"`\n *   - `resource` (required) — resource slug, e.g. `\"properties\"`\n *   - `tail`     — max records to return (clamped 1..10000; default 100)\n *   - `afterTs`  — ISO timestamp watermark; keeps only rows with `ts > afterTs`\n *   - `fromTs`   — inclusive lower bound (`ts >= fromTs`); scans older versions\n *   - `toTs`     — inclusive upper bound (`ts <= toTs`)\n *   - `taskId`   — keep only rows stamped with this task id\n */\nexport class TaskGetLogs extends AbstractTask {\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ source: string, resource: string, tail: number, afterTs?: string }>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(context, \"task-get-logs\", {\n            source: \"string\",\n            resource: \"string\",\n            tail: \"number default 100\",\n            afterTs: \"string\",\n            fromTs: \"string\",\n            toTs: \"string\",\n            taskId: \"string\",\n        }, overrides);\n        const source = typeof merged.source === \"string\" ? merged.source.trim() : \"\";\n        const resource = typeof merged.resource === \"string\" ? merged.resource.trim() : \"\";\n        if (!source) throw new ParamError('getLogs: param \"source\" is required');\n        if (!resource) throw new ParamError('getLogs: param \"resource\" is required');\n        let tail = Number(merged.tail);\n        if (!Number.isFinite(tail) || tail < 1) tail = 100;\n        tail = Math.min(10_000, Math.max(1, Math.floor(tail)));\n        const out = { source, resource, tail };\n        if (typeof merged.afterTs === \"string\" && merged.afterTs.trim()) {\n            out.afterTs = merged.afterTs.trim();\n        }\n        if (typeof merged.fromTs === \"string\" && merged.fromTs.trim()) {\n            out.fromTs = merged.fromTs.trim();\n        }\n        if (typeof merged.toTs === \"string\" && merged.toTs.trim()) {\n            out.toTs = merged.toTs.trim();\n        }\n        if (typeof merged.taskId === \"string\" && merged.taskId.trim()) {\n            out.taskId = merged.taskId.trim();\n        }\n        return out;\n    }\n\n    /**\n     * @param {unknown} _reportProgress Unused (single-shot read, no progress events).\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run(_reportProgress) {\n        const p = this.task.params ?? {};\n        const source = String(p.source ?? \"\").trim();\n        const resource = String(p.resource ?? \"\").trim();\n        const tail = Math.max(1, Math.min(10_000, Number(p.tail) > 0 ? Number(p.tail) : 100));\n        const afterTs = p.afterTs != null && String(p.afterTs).trim() ? String(p.afterTs).trim() : null;\n        const fromTs = p.fromTs != null && String(p.fromTs).trim() ? String(p.fromTs).trim() : null;\n        const toTs = p.toTs != null && String(p.toTs).trim() ? String(p.toTs).trim() : null;\n        const taskId = p.taskId != null && String(p.taskId).trim() ? String(p.taskId).trim() : null;\n\n        if (!source || !resource) {\n            return {\n                success: false,\n                results: { error: 'getLogs requires params \"source\" and \"resource\"' },\n            };\n        }\n\n        try {\n            const { records, latestTs } = await readTaskIpcLogsSnapshot(this.context, {\n                source,\n                resource,\n                tail,\n                afterTs,\n                fromTs,\n                toTs,\n                taskId,\n            });\n            return {\n                success: true,\n                results: { records, latestTs, source, resource },\n            };\n        } catch (e) {\n            return {\n                success: false,\n                results: { error: e?.message ?? String(e) },\n            };\n        }\n    }\n}\n","import { ParamError } from \"../../errors.js\";\nimport { AbstractTask } from \"../AbstractTask.js\";\nimport { applyRuntimeParam, applyRuntimePatch } from \"../runtimeParams.js\";\nimport { listServicesRegistry } from \"../servicesRegistry.js\";\nimport { enqueueTask } from \"../taskUtils.js\";\n\n/**\n * Hot-update runner knobs without restarting the process.\n *\n * Apply to `context.tasksRuntime` (loop re-reads `maxParallel` / `pollMs` /\n * `claimJitterMs` / `scanLimit` every tick) and to the logger for level-related\n * keys (`levels`, `silent`, …).\n *\n * Targeting (same idea as stop):\n *   - `--serviceName=<registry name>` → one instance\n *   - `--serviceGroup=photos` without serviceName → broadcast to every alive\n *     instance in that group (via {@link TaskSetRuntimeParam.enqueue})\n *\n * Params (any of):\n *   - `--paramKey=maxParallel --paramValue=16`\n *   - `--paramsJson='{\"key\":\"maxParallel\",\"value\":16}'`\n *   - `--paramsJson='{\"patch\":{\"maxParallel\":16,\"levels\":\"+debug\"}}'`\n */\nexport class TaskSetRuntimeParam extends AbstractTask {\n    static defaultWaitForResult = true;\n\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<object>}\n     */\n    static async resolveParams(context, overrides = {}) {\n        const main = await super.resolveParams(context, overrides);\n        if (!main.serviceName && !main.serviceGroup) {\n            throw new ParamError(\n                \"setRuntimeParam requires --serviceName (one instance) or --serviceGroup (broadcast to alive instances)\"\n            );\n        }\n        return main;\n    }\n\n    /**\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ key?: string, value?: unknown, patch?: Record<string, unknown> }>}\n     */\n    static async resolveCustomParams(context, overrides = {}) {\n        const merged = AbstractTask._mergeTypedParams(\n            context,\n            \"task-set-runtime-param\",\n            {\n                paramKey: \"string\",\n                paramValue: \"string\",\n                key: \"string\",\n                value: \"string\",\n            },\n            overrides\n        );\n\n        if (merged.patch && typeof merged.patch === \"object\" && !Array.isArray(merged.patch)) {\n            if (Object.keys(merged.patch).length === 0) {\n                throw new ParamError(\"setRuntimeParam: patch is empty\");\n            }\n            return { patch: { ...merged.patch } };\n        }\n\n        const key = merged.paramKey || merged.key;\n        const value = merged.paramValue !== undefined ? merged.paramValue : merged.value;\n\n        if (!key) {\n            throw new ParamError(\n                'setRuntimeParam requires --paramKey/--paramValue, or --paramsJson \\'{\"key\":\"maxParallel\",\"value\":16}\\' / \\'{\"patch\":{...}}\\''\n            );\n        }\n\n        // CLI strings: try JSON parse for numbers/bools/objects; else keep string\n        let parsed = value;\n        if (typeof value === \"string\") {\n            const t = value.trim();\n            if (t === \"true\") parsed = true;\n            else if (t === \"false\") parsed = false;\n            else if (t !== \"\" && !Number.isNaN(Number(t)) && /^-?\\d+(\\.\\d+)?$/.test(t)) {\n                parsed = Number(t);\n            } else if (\n                (t.startsWith(\"{\") && t.endsWith(\"}\")) ||\n                (t.startsWith(\"[\") && t.endsWith(\"]\")) ||\n                (t.startsWith('\"') && t.endsWith('\"'))\n            ) {\n                try {\n                    parsed = JSON.parse(t);\n                } catch {\n                    parsed = value;\n                }\n            }\n        }\n\n        return { key: String(key), value: parsed };\n    }\n\n    /**\n     * Enqueue one or many setRuntimeParam tasks. Prefer this over a bare\n     * `enqueueTask` when broadcasting to a service group.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<{ ids: string[], targets: string[] }>}\n     */\n    static async enqueue(context, overrides = {}) {\n        const payload = await this.resolveParams(context, { ...overrides, name: \"setRuntimeParam\" });\n        const queueName = payload.queueName ?? \"tasks\";\n\n        if (payload.serviceName) {\n            const id = await enqueueTask(context, payload);\n            return { ids: [id], targets: [payload.serviceName] };\n        }\n\n        const group = String(payload.serviceGroup || \"\").trim();\n        if (!group) {\n            throw new ParamError(\"setRuntimeParam.enqueue: serviceGroup required for broadcast\");\n        }\n\n        const alive = await listServicesRegistry(context, {\n            queueName,\n            serviceGroup: group,\n            staleMs: overrides.staleMs ?? 45_000,\n        });\n        if (!alive.length) {\n            throw new ParamError(\n                `setRuntimeParam: no alive services in group=\"${group}\" queue=\"${queueName}\"`\n            );\n        }\n\n        const ids = [];\n        const targets = [];\n        for (const reg of alive) {\n            const id = await enqueueTask(context, {\n                ...payload,\n                serviceGroup: group,\n                serviceName: reg.service_name,\n                serverName: reg.server_name ?? null,\n                instanceNumber: reg.instance_number ?? null,\n            });\n            ids.push(id);\n            targets.push(reg.service_name);\n        }\n        context.logger?.info?.(\n            `[setRuntimeParam] broadcast to ${targets.length} instance(s) in group=${group}: ${targets.join(\", \")}`\n        );\n        return { ids, targets };\n    }\n\n    /**\n     * @returns {Promise<{ success: true, results: object }>}\n     */\n    async run() {\n        const params = this.task?.params ?? {};\n        let changes;\n        if (params.patch && typeof params.patch === \"object\") {\n            changes = await applyRuntimePatch(this.context, params.patch);\n        } else {\n            changes = [await applyRuntimeParam(this.context, params.key, params.value)];\n        }\n\n        const summary = changes.map((c) => `${c.key}: ${JSON.stringify(c.previous)} → ${JSON.stringify(c.next)}`);\n        this.context.logger.warn?.(\n            `[TaskSetRuntimeParam] applied on ${this.context.servicesRegistry?.serviceName ?? \"runner\"}: ${summary.join(\"; \")}`\n        );\n\n        return {\n            success: true,\n            results: {\n                runtimeParamApplied: true,\n                changes,\n                runtime: { ...(this.context.tasksRuntime ?? {}) },\n            },\n        };\n    }\n}\n","/**\n * Shorter retention windows for high-volume ephemeral task names.\n * Apps inject defaults via {@link setTaskRetentionNameRulesDefaults}; runtime\n * may override with `tasksRetentionNameRules` (JSON object name → hours).\n */\n\n/** @type {Record<string, number> | null} */\nlet injectedDefaults = null;\n\n/**\n * @param {Record<string, number>|null|undefined} map  task name → retention hours\n */\nexport function setTaskRetentionNameRulesDefaults(map) {\n    if (map == null) {\n        injectedDefaults = null;\n        return;\n    }\n    injectedDefaults = { ...map };\n}\n\n/**\n * @param {unknown} raw JSON string or object from runtime / params\n * @returns {Record<string, number>}\n */\nexport function parseRetentionNameRulesRaw(raw) {\n    if (raw == null || raw === \"\") return {};\n    let obj = raw;\n    if (typeof raw === \"string\") {\n        const t = raw.trim();\n        if (!t) return {};\n        try {\n            obj = JSON.parse(t);\n        } catch {\n            return {};\n        }\n    }\n    if (!obj || typeof obj !== \"object\" || Array.isArray(obj)) return {};\n    const out = {};\n    for (const [name, hours] of Object.entries(obj)) {\n        const h = Number(hours);\n        if (String(name ?? \"\").trim() && Number.isFinite(h) && h > 0) {\n            out[String(name).trim()] = h;\n        }\n    }\n    return out;\n}\n\n/**\n * Merged name → hours map (runtime wins over injected defaults per name).\n *\n * @param {object} [runtime] context.tasksRuntime\n * @returns {{ name: string, hours: number }[]}\n */\nexport function resolveRetentionNameRules(runtime = {}) {\n    const merged = { ...(injectedDefaults ?? {}), ...parseRetentionNameRulesRaw(runtime.tasksRetentionNameRules) };\n    return Object.entries(merged)\n        .map(([name, hours]) => ({ name, hours: Number(hours) }))\n        .filter((r) => r.name && Number.isFinite(r.hours) && r.hours > 0)\n        .sort((a, b) => a.name.localeCompare(b.name));\n}\n","/**\n * Unified retention for `*_history` rows and IPC FileDatabase logs.\n *\n * The same cutoff is applied to both stores so Inspect history and `l` logs stay\n * aligned. FileDatabase `maxVersions` remains a process-restart backstop only.\n *\n * Config (CLI / env / getAllForModule, then hot-update via setRuntimeParam):\n *   tasksRetentionEnabled        default true\n *   tasksRetentionDays           default 7 (0 = disable time prune)\n *   tasksRetentionIntervalMs     default 1h between automatic passes\n *   tasksRetentionMinFreeRatio   default 0.10 — shrink the window if free/total is below this\n *   tasksRetentionMinHours       default 6 — floor when disk is tight\n */\n\nimport { getDiskUsage } from \"../utils/os-utils.js\";\nimport { queueToTableNames } from \"./taskUtils.js\";\nimport { ensureTasksRuntime } from \"./runtimeParams.js\";\nimport { pruneIpcLogsOlderThan, tasksLogsRoot } from \"./taskLogs.js\";\nimport { parseRetentionNameRulesRaw, resolveRetentionNameRules } from \"./taskRetentionNameRules.js\";\n\nexport const HISTORY_PRUNE_CHUNK = 2000;\n\nexport const DEFAULT_RETENTION_DAYS = 7;\nexport const DEFAULT_RETENTION_INTERVAL_MS = 60 * 60 * 1000;\nexport const DEFAULT_MIN_FREE_RATIO = 0.1;\nexport const DEFAULT_MIN_RETENTION_HOURS = 6;\n\nconst RETENTION_PARAM_DEFS = {\n    tasksRetentionEnabled: \"boolean default true\",\n    tasksRetentionDays: \"number default 7\",\n    tasksRetentionIntervalMs: \"number default 3600000\",\n    tasksRetentionMinFreeRatio: \"number default 0.1\",\n    tasksRetentionMinHours: \"number default 6\",\n    tasksRetentionNameRules: \"string\",\n};\n\n/**\n * Register CLI/env knobs and seed `context.tasksRuntime` once per process.\n *\n * @param {object} context\n * @returns {Record<string, unknown>}\n */\nexport function seedTaskRetentionRuntime(context) {\n    const fromParams =\n        typeof context.params?.getAllForModule === \"function\"\n            ? context.params.getAllForModule(\"tasks-retention\", RETENTION_PARAM_DEFS)\n            : {};\n    const rt = ensureTasksRuntime(context);\n    if (rt.tasksRetentionEnabled === undefined) {\n        rt.tasksRetentionEnabled = fromParams.tasksRetentionEnabled !== false;\n    }\n    if (rt.tasksRetentionDays === undefined) {\n        rt.tasksRetentionDays = Number(fromParams.tasksRetentionDays ?? DEFAULT_RETENTION_DAYS);\n    }\n    if (rt.tasksRetentionIntervalMs === undefined) {\n        rt.tasksRetentionIntervalMs = Number(\n            fromParams.tasksRetentionIntervalMs ?? DEFAULT_RETENTION_INTERVAL_MS,\n        );\n    }\n    if (rt.tasksRetentionMinFreeRatio === undefined) {\n        rt.tasksRetentionMinFreeRatio = Number(\n            fromParams.tasksRetentionMinFreeRatio ?? DEFAULT_MIN_FREE_RATIO,\n        );\n    }\n    if (rt.tasksRetentionMinHours === undefined) {\n        rt.tasksRetentionMinHours = Number(fromParams.tasksRetentionMinHours ?? DEFAULT_MIN_RETENTION_HOURS);\n    }\n    if (rt.tasksRetentionNameRules === undefined && fromParams.tasksRetentionNameRules != null) {\n        rt.tasksRetentionNameRules = fromParams.tasksRetentionNameRules;\n    }\n    return rt;\n}\n\n/**\n * @param {object} [runtime]\n * @returns {{\n *   enabled: boolean,\n *   days: number,\n *   intervalMs: number,\n *   minFreeRatio: number,\n *   minHours: number,\n * }}\n */\nexport function readRetentionConfig(runtime = {}) {\n    const days = Number(runtime.tasksRetentionDays);\n    const intervalMs = Number(runtime.tasksRetentionIntervalMs);\n    const minFreeRatio = Number(runtime.tasksRetentionMinFreeRatio);\n    const minHours = Number(runtime.tasksRetentionMinHours);\n    return {\n        enabled: runtime.tasksRetentionEnabled !== false && Number.isFinite(days) && days > 0,\n        days: Number.isFinite(days) && days > 0 ? days : 0,\n        intervalMs: Number.isFinite(intervalMs) && intervalMs >= 10_000 ? intervalMs : DEFAULT_RETENTION_INTERVAL_MS,\n        minFreeRatio:\n            Number.isFinite(minFreeRatio) && minFreeRatio > 0 && minFreeRatio < 1\n                ? minFreeRatio\n                : DEFAULT_MIN_FREE_RATIO,\n        minHours: Number.isFinite(minHours) && minHours >= 1 ? minHours : DEFAULT_MIN_RETENTION_HOURS,\n    };\n}\n\n/**\n * Scale the configured window down when the logs volume is short on free space.\n * At/above `minFreeRatio` keep `days`. As free → 0, approach `minHours`.\n *\n * @param {{ days: number, minFreeRatio: number, minHours: number }} cfg\n * @param {{ free: number, total: number, freeRatio: number } | null} disk\n * @returns {{ days: number, diskAdjusted: boolean, freeRatio: number | null }}\n */\nexport function effectiveRetentionDays(cfg, disk) {\n    const minDays = cfg.minHours / 24;\n    if (!disk || !Number.isFinite(disk.freeRatio) || disk.freeRatio >= cfg.minFreeRatio) {\n        return { days: cfg.days, diskAdjusted: false, freeRatio: disk?.freeRatio ?? null };\n    }\n    const scaled = cfg.days * (disk.freeRatio / cfg.minFreeRatio);\n    const days = Math.max(minDays, scaled);\n    return { days, diskAdjusted: true, freeRatio: disk.freeRatio };\n}\n\n/**\n * @param {number} days\n * @param {Date} [now]\n * @returns {string} ISO cutoff\n */\nexport function retentionCutoffIso(days, now = new Date()) {\n    const ms = Math.max(0, Number(days) || 0) * 24 * 60 * 60 * 1000;\n    return new Date(now.getTime() - ms).toISOString();\n}\n\n/**\n * @param {number} hours\n * @param {Date} [now]\n * @returns {string} ISO cutoff\n */\nexport function retentionCutoffFromHours(hours, now = new Date()) {\n    const ms = Math.max(0, Number(hours) || 0) * 60 * 60 * 1000;\n    return new Date(now.getTime() - ms).toISOString();\n}\n\nexport { parseRetentionNameRulesRaw, resolveRetentionNameRules };\n\nexport { getDiskUsage as readDiskUsage };\n\n/**\n * Delete history rows older than `cutoff` in chunks (re-run safe).\n *\n * @param {Function} db\n * @param {string} historyTable\n * @param {string|Date} cutoff\n * @param {{ chunkSize?: number, isStop?: () => boolean }} [opts]\n * @returns {Promise<number>}\n */\nexport async function deleteHistoryOlderThan(db, historyTable, cutoff, opts = {}) {\n    const chunkSize = Math.max(1, Number(opts.chunkSize) || HISTORY_PRUNE_CHUNK);\n    const isStop = typeof opts.isStop === \"function\" ? opts.isStop : () => false;\n    const name =\n        opts.name != null && String(opts.name).trim() ? String(opts.name).trim() : null;\n    let total = 0;\n    for (;;) {\n        if (isStop()) break;\n        let q = db(historyTable).where(\"completed_at\", \"<\", cutoff);\n        if (name) q = q.where({ name });\n        const rows = await q.select(\"id\").limit(chunkSize);\n        if (!Array.isArray(rows) || rows.length === 0) break;\n        const ids = rows.map((r) => r.id).filter(Boolean);\n        if (!ids.length) break;\n        const deleted = await db(historyTable).whereIn(\"id\", ids).delete();\n        total += Number(deleted) || ids.length;\n        if (rows.length < chunkSize) break;\n    }\n    return total;\n}\n\n/**\n * Run one prune pass: disk-aware cutoff → IPC logs → tasks_history.\n *\n * @param {object} context\n * @param {{\n *   queueName?: string,\n *   historyTable?: string,\n *   force?: boolean,\n *   now?: Date,\n *   readDisk?: (p: string) => Promise<{ free: number, total: number, freeRatio: number } | null>,\n *   pruneLogs?: typeof pruneIpcLogsOlderThan,\n * }} [options]\n * @returns {Promise<object>}\n */\nexport async function pruneTaskRetention(context, options = {}) {\n    seedTaskRetentionRuntime(context);\n    const cfg = readRetentionConfig(context.tasksRuntime);\n    if (!cfg.enabled) {\n        return { skipped: true, reason: \"disabled\" };\n    }\n\n    const queueName = options.queueName ?? context.tasksQueueName ?? \"tasks\";\n    const historyTable = options.historyTable ?? queueToTableNames(queueName).historyTable;\n    const now = options.now ?? new Date();\n    const logsRoot = tasksLogsRoot(context);\n    const readDisk = options.readDisk ?? getDiskUsage;\n    const disk = await readDisk(logsRoot);\n    const effective = effectiveRetentionDays(cfg, disk);\n    const cutoff = retentionCutoffIso(effective.days, now);\n\n    const pruneLogs = options.pruneLogs ?? pruneIpcLogsOlderThan;\n    const logs = await pruneLogs(context, cutoff, {\n        isStop: () => context.isStop?.() === true,\n    });\n\n    let historyDeleted = 0;\n    if (context.db && typeof context.db === \"function\") {\n        historyDeleted = await deleteHistoryOlderThan(context.db, historyTable, cutoff, {\n            isStop: () => context.isStop?.() === true,\n        });\n    }\n\n    const nameRules = resolveRetentionNameRules(context.tasksRuntime);\n    const nameRuleResults = [];\n    if (context.db && typeof context.db === \"function\") {\n        for (const rule of nameRules) {\n            const ruleCutoff = retentionCutoffFromHours(rule.hours, now);\n            const deleted = await deleteHistoryOlderThan(context.db, historyTable, ruleCutoff, {\n                name: rule.name,\n                isStop: () => context.isStop?.() === true,\n            });\n            if (deleted > 0) {\n                nameRuleResults.push({ name: rule.name, hours: rule.hours, cutoff: ruleCutoff, deleted });\n            }\n            historyDeleted += deleted;\n        }\n    }\n\n    const summary = {\n        skipped: false,\n        cutoff,\n        days: effective.days,\n        configuredDays: cfg.days,\n        diskAdjusted: effective.diskAdjusted,\n        freeRatio: effective.freeRatio,\n        historyTable,\n        historyDeleted,\n        nameRules: nameRuleResults,\n        logs,\n    };\n    context.logger?.info?.(\n        `[tasks-retention] cutoff=${cutoff} days=${effective.days.toFixed(2)}` +\n            `${effective.diskAdjusted ? ` (disk ${(effective.freeRatio * 100).toFixed(1)}% free)` : \"\"}` +\n            ` history=${historyDeleted}` +\n            (nameRuleResults.length\n                ? ` nameRules=${nameRuleResults.map((r) => `${r.name}:${r.deleted}@${r.hours}h`).join(\",\")}`\n                : \"\") +\n            ` logTables=${logs?.tables ?? 0} logDropped=${logs?.dropped ?? 0}`,\n    );\n    return summary;\n}\n\n/**\n * Throttled prune for the runner loop / after each handler. Overlapping calls no-op.\n *\n * @param {object} context\n * @param {{ queueName?: string, historyTable?: string, force?: boolean }} [options]\n * @returns {Promise<object|null>}\n */\nexport async function maybePruneTaskRetention(context, options = {}) {\n    seedTaskRetentionRuntime(context);\n    const cfg = readRetentionConfig(context.tasksRuntime);\n    if (!cfg.enabled) return null;\n\n    const now = Date.now();\n    const last = Number(context.__tasksRetentionLastAt) || 0;\n    if (!options.force && last && now - last < cfg.intervalMs) return null;\n    if (context.__tasksRetentionInFlight) return null;\n\n    context.__tasksRetentionLastAt = now;\n    context.__tasksRetentionInFlight = true;\n    try {\n        return await pruneTaskRetention(context, options);\n    } catch (err) {\n        context.logger?.warn?.(`[tasks-retention] prune failed: ${err?.message ?? String(err)}`);\n        return { skipped: true, reason: \"error\", error: err?.message ?? String(err) };\n    } finally {\n        context.__tasksRetentionInFlight = false;\n    }\n}\n","import { AbstractTask } from \"../AbstractTask.js\";\nimport { pruneTaskRetention, seedTaskRetentionRuntime } from \"../taskRetention.js\";\n\n/**\n * Run one history + IPC log retention pass on this host (same cutoff both stores).\n * Also runs automatically from the tasks loop; this task is the \"do it now\" hook.\n */\nexport class TaskPruneTaskRetention extends AbstractTask {\n    static defaultWaitForResult = true;\n\n    /**\n     * @returns {Promise<{ success: boolean, results: unknown }>}\n     */\n    async run() {\n        seedTaskRetentionRuntime(this.context);\n        const results = await pruneTaskRetention(this.context, { force: true });\n        return { success: true, results };\n    }\n}\n","import { ParamError } from \"../errors.js\";\nimport { TaskPing } from \"./coreTasks/TaskPing.js\";\nimport { TaskSampleProcess } from \"./coreTasks/TaskSampleProcess.js\";\nimport { TaskShellCommand } from \"./coreTasks/TaskShellCommand.js\";\nimport { TaskSystemInfo } from \"./coreTasks/TaskSystemInfo.js\";\nimport { TaskSumAB } from \"./coreTasks/TaskSumAB.js\";\nimport { TaskStopRunner } from \"./coreTasks/TaskStopRunner.js\";\nimport { TaskPauseRunner, TaskUnpauseRunner } from \"./coreTasks/TaskPauseRunner.js\";\nimport { TaskPauseTask, TaskResumeTask } from \"./coreTasks/TaskPauseTask.js\";\nimport { TaskGetLogs } from \"./coreTasks/TaskGetLogs.js\";\nimport { TaskSetRuntimeParam } from \"./coreTasks/TaskSetRuntimeParam.js\";\nimport { TaskPruneTaskRetention } from \"./coreTasks/TaskPruneTaskRetention.js\";\n\n/**\n * Name → task class map. Runners look up the class by `task.name` when claiming\n * a row. Keep names stable across versions: the DB queue references them as strings.\n *\n * Backward-compat aliases (e.g. `stop` → `TaskStopRunner`, `info` → `TaskSystemInfo`)\n * are seeded by {@link TasksRegistry.withCoreTasks}.\n */\nexport class TasksRegistry {\n    /**\n     * @param {Record<string, Function>} [initial] Optional seed entries to copy in.\n     */\n    constructor(initial) {\n        this.map = {};\n        if (initial) {\n            this.addMany(initial);\n        }\n    }\n\n    /**\n     * Build a registry pre-populated with every core task plus legacy aliases.\n     * Prefer this over `new TasksRegistry()` for anything that wants `ping`/`stop`/etc.\n     *\n     * @returns {TasksRegistry}\n     */\n    static withCoreTasks() {\n        return new TasksRegistry()\n            .add(\"ping\", TaskPing)\n            .add(\"sampleProcess\", TaskSampleProcess)\n            .add(\"shellCommand\", TaskShellCommand)\n            .add(\"systemInfo\", TaskSystemInfo)\n            .add(\"info\", TaskSystemInfo)\n            .add(\"taskSumAB\", TaskSumAB)\n            .add(\"stopRunner\", TaskStopRunner)\n            // Backward-compat alias\n            .add(\"stop\", TaskStopRunner)\n            .add(\"pauseRunner\", TaskPauseRunner)\n            .add(\"pause\", TaskPauseRunner)\n            .add(\"unpauseRunner\", TaskUnpauseRunner)\n            .add(\"unpause\", TaskUnpauseRunner)\n            .add(\"pauseTask\", TaskPauseTask)\n            .add(\"resumeTask\", TaskResumeTask)\n            .add(\"getLogs\", TaskGetLogs)\n            .add(\"setRuntimeParam\", TaskSetRuntimeParam)\n            .add(\"setRunnerParam\", TaskSetRuntimeParam)\n            .add(\"pruneTaskRetention\", TaskPruneTaskRetention);\n    }\n\n    /**\n     * Register a single task class under a name. Overwrites any previous entry.\n     *\n     * @param {string} taskName\n     * @param {Function} taskClass Subclass of `AbstractTask`.\n     * @returns {this}\n     */\n    add(taskName, taskClass) {\n        this.map[taskName] = taskClass;\n        return this;\n    }\n\n    /**\n     * Bulk-register a name → class map. Later calls override earlier ones.\n     *\n     * @param {Record<string, Function>} entries\n     * @returns {this}\n     */\n    addMany(entries) {\n        for (const [name, klass] of Object.entries(entries)) {\n            this.add(name, klass);\n        }\n        return this;\n    }\n\n    /**\n     * Look up a task class by name. Returns `undefined` when the name is unknown;\n     * the runner treats that as \"some other worker may handle this\" and skips.\n     *\n     * @param {string} taskName\n     * @returns {Function | undefined}\n     */\n    get(taskName) {\n        return this.map[taskName];\n    }\n\n    /**\n     * Strict variant of {@link get}: throws {@link ParamError} (with the list\n     * of supported names) when `taskName` is unknown. Use from enqueuer code\n     * paths where an unknown name is a hard CLI/programmer error.\n     *\n     * @param {string} taskName\n     * @returns {Function}\n     */\n    requireClass(taskName) {\n        const TaskClass = taskName ? this.map[taskName] : undefined;\n        if (!TaskClass) {\n            const supported = this.listSupportedTasks().join(\", \") || \"(none)\";\n            throw new ParamError(\n                `Unknown task \"${taskName ?? \"\"}\". Supported on this registry: ${supported}`\n            );\n        }\n        return TaskClass;\n    }\n\n    /**\n     * Dispatcher used by `send-task` / programmatic enqueuers: pick `name`\n     * from `overrides` or `context.params`, look up the class, and delegate\n     * to its static {@link AbstractTask.resolveParams} with `name` seeded into\n     * the overrides. The returned object is shaped for {@link enqueueTask}.\n     *\n     * Validation failures (unknown task, missing required custom params, etc.)\n     * surface as {@link ParamError} so the caller aborts cleanly before any\n     * row is inserted.\n     *\n     * @param {object} context\n     * @param {Record<string, unknown>} [overrides]\n     * @returns {Promise<object>}\n     */\n    async resolveTaskParams(context, overrides = {}) {\n        const overrideName = typeof overrides.name === \"string\" ? overrides.name.trim() : overrides.name;\n        const fromCli = context.params.get(\"name\", \"string\");\n        const cliName = typeof fromCli === \"string\" ? fromCli.trim() : fromCli;\n        const name = overrideName || cliName;\n        if (!name) {\n            throw new ParamError(\"Task --name is required (e.g. ping, stop, dummyHarvest)\");\n        }\n        const TaskClass = this.requireClass(name);\n        return TaskClass.resolveParams(context, { ...overrides, name });\n    }\n\n    /**\n     * Names of every registered task, sorted alphabetically (useful for CLI output\n     * and allowlist sanity checks).\n     *\n     * @returns {string[]}\n     */\n    listSupportedTasks() {\n        return Object.keys(this.map).sort();\n    }\n\n    /**\n     * Shallow copy of the internal map, for handing to `addMany` on another registry\n     * or for serialization.\n     *\n     * @returns {Record<string, Function>}\n     */\n    toObject() {\n        return { ...this.map };\n    }\n}\n","/**\n * Shared allowlist helpers for task runners: normalize CLI strings, merge with service (control) tasks.\n */\n\n/**\n * Task names every runner should be willing to claim (in addition to `--allowedTasks` or\n * service-group config). These map to core `TasksRegistry.withCoreTasks` handlers.\n */\nexport const SERVICE_TASK_NAMES = [\n    \"ping\",\n    \"stop\",\n    \"stopRunner\",\n    \"pause\",\n    \"pauseRunner\",\n    \"unpause\",\n    \"unpauseRunner\",\n    \"pauseTask\",\n    \"resumeTask\",\n    \"shellCommand\",\n    \"systemInfo\",\n    \"info\",\n    \"getLogs\",\n    \"setRuntimeParam\",\n    \"setRunnerParam\",\n    \"pruneTaskRetention\",\n];\n\n/**\n * Coerce a caller-supplied allowlist value (CLI string, array, or undefined) into\n * a clean string array, or `undefined` when nothing was provided / only blanks.\n *\n *   - `\"a,b\"`  → `[\"a\", \"b\"]`\n *   - `[\"a \", \"\", \" b\"]` → `[\"a\", \"b\"]`\n *   - `\"  \"` / `undefined` / `null` → `undefined`\n *\n * @param {unknown} value\n * @returns {string[] | undefined}\n */\nexport function normalizeAllowedTasks(value) {\n    if (!value) return undefined;\n    if (Array.isArray(value)) {\n        const out = value.map((v) => String(v).trim()).filter(Boolean);\n        return out.length ? out : undefined;\n    }\n    const out = String(value)\n        .split(\",\")\n        .map((v) => v.trim())\n        .filter(Boolean);\n    return out.length ? out : undefined;\n}\n\n/**\n * Union of `SERVICE_TASK_NAMES` and caller-provided names (deduped, sorted).\n * Use when building the allowlist for `runTasksLoop` / `claimNextRunnableTask`.\n *\n * @param {string[]} [names]\n * @returns {string[]}\n */\nexport function mergeAllowedTasksWithServiceTasks(names) {\n    const set = new Set([...SERVICE_TASK_NAMES, ...(names ?? [])]);\n    return Array.from(set).sort();\n}\n","/**\n * Claim order for idle queue rows:\n *   1. Due tasks first, earliest due instant wins\n *   2. If none are due, highest priority (lowest `priority` number)\n *\n * A row is due when `past_due` or `next_run_at` is set. The claim query already\n * gates `next_run_at` (NULL or <= now), so a stored next_run_at here means\n * \"ready / overdue\". The due instant is the earlier of the two timestamps.\n *\n * Tie-breakers (same due instant, or several non-due rows): priority, then\n * never-run first / oldest `completed_at`, then `created_at`.\n */\n\nfunction toMs(value) {\n    if (value == null || value === \"\") return null;\n    const t = value instanceof Date ? value.getTime() : new Date(value).getTime();\n    return Number.isFinite(t) ? t : null;\n}\n\n/** Earlier of `next_run_at` and `past_due`, or null when neither is set. */\nexport function claimDueInstantMs(row) {\n    const nextRun = toMs(row?.next_run_at);\n    const pastDue = toMs(row?.past_due);\n    if (nextRun == null) return pastDue;\n    if (pastDue == null) return nextRun;\n    return Math.min(nextRun, pastDue);\n}\n\nexport function isClaimDue(row) {\n    return claimDueInstantMs(row) != null;\n}\n\n/**\n * Sort comparator matching {@link applyClaimOrder}. Negative => `a` is claimed first.\n *\n * @param {object} a\n * @param {object} b\n * @returns {number}\n */\nexport function compareClaimCandidates(a, b) {\n    const dueA = claimDueInstantMs(a);\n    const dueB = claimDueInstantMs(b);\n    const aDue = dueA != null;\n    const bDue = dueB != null;\n    if (aDue !== bDue) return aDue ? -1 : 1;\n    if (aDue && dueA !== dueB) return dueA - dueB;\n\n    const priA = Number(a?.priority);\n    const priB = Number(b?.priority);\n    const pA = Number.isFinite(priA) ? priA : 50;\n    const pB = Number.isFinite(priB) ? priB : 50;\n    if (pA !== pB) return pA - pB;\n\n    const doneA = toMs(a?.completed_at);\n    const doneB = toMs(b?.completed_at);\n    if ((doneA == null) !== (doneB == null)) return doneA == null ? -1 : 1;\n    if (doneA != null && doneB != null && doneA !== doneB) return doneA - doneB;\n\n    const createdA = toMs(a?.created_at) ?? 0;\n    const createdB = toMs(b?.created_at) ?? 0;\n    if (createdA !== createdB) return createdA - createdB;\n    return 0;\n}\n\n/**\n * Knex ORDER BY matching {@link compareClaimCandidates} (must stay in sync so\n * `scanLimit` keeps the rows that should actually be claimed first).\n *\n * @param {import(\"knex\").Knex.QueryBuilder} query\n * @returns {import(\"knex\").Knex.QueryBuilder}\n */\nexport function applyClaimOrder(query) {\n    return query\n        .orderByRaw(\n            \"CASE WHEN past_due IS NOT NULL OR next_run_at IS NOT NULL THEN 0 ELSE 1 END ASC\"\n        )\n        .orderByRaw(\n            \"LEAST(COALESCE(next_run_at, past_due), COALESCE(past_due, next_run_at)) ASC NULLS LAST\"\n        )\n        .orderBy([{ column: \"priority\", order: \"asc\" }])\n        .orderByRaw(\"CASE WHEN completed_at IS NULL THEN 0 ELSE 1 END ASC\")\n        .orderBy([{ column: \"completed_at\", order: \"asc\" }, { column: \"created_at\", order: \"asc\" }]);\n}\n","import { spawn } from \"node:child_process\";\nimport {\n    appendTaskIpcLog,\n    flushTaskIpcLogs,\n    resolveIpcFileLogsDir,\n} from \"./taskLogs.js\";\n\n/** Upper bound on the `progress` column write; keeps a runaway child from bloating the row. */\nconst MAX_PROGRESS_TEXT_LEN = 4000;\n\n/**\n * Remove empty / non-string entries from a CLI args array.\n *\n * @param {unknown[]} [args]\n * @returns {string[]}\n */\nfunction toCliArgs(args = []) {\n    return args.filter((a) => typeof a === \"string\" && a.length > 0);\n}\n\n/**\n * Short prefix for child-side log lines: `<taskName>:<id8>[:<opid>]`.\n *\n * @param {{ name: string, id: string, opid?: string|null }} task\n * @returns {string}\n */\nfunction formatChildLogPrefix(task) {\n    return `${task.name}:${task.id.slice(0, 8)}${task.opid ? `:${task.opid}` : \"\"}`;\n}\n\n/**\n * True progress event: must carry `level === \"progress\"` and numeric `count`/`total`.\n * Anything else (debug, info, error, worker-result sentinel...) is treated as a regular log.\n *\n * @param {unknown} payload\n * @returns {boolean}\n */\nfunction isProgressPayload(payload) {\n    if (!payload || typeof payload !== \"object\") return false;\n    if (payload.level !== \"progress\") return false;\n    const count = Number(payload.count);\n    const total = Number(payload.total);\n    return Number.isFinite(count) && Number.isFinite(total) && total > 0;\n}\n\n/**\n * Render a progress payload as `\"[prefix ][message ]count/total\"` for the DB `progress` column.\n *\n * @param {{ prefix?: string, message?: string, count: number, total: number }} payload\n * @param {string} fallbackPrefix Used when `payload.prefix` is missing.\n * @returns {string}\n */\nfunction formatProgressText(payload, fallbackPrefix) {\n    const pfx = payload.prefix ? `${payload.prefix} ` : (fallbackPrefix ? `${fallbackPrefix} ` : \"\");\n    const label = typeof payload.message === \"string\" && payload.message ? `${payload.message} ` : \"\";\n    return `${pfx}${label}${payload.count}/${payload.total}`;\n}\n\n/**\n * Forward a structured IPC log line from the child to the parent's logger at the\n * matching level. `stdout`/`stderr` go through a different path (raw forwarding);\n * this only handles `{ level, message, ... }` payloads.\n *\n * @param {object} context\n * @param {string} prefix\n * @param {unknown} message\n * @returns {void}\n */\nfunction forwardChildLogToParent(context, prefix, message) {\n    if (!message || typeof message !== \"object\") return;\n    const text = typeof message.message === \"string\" ? message.message : null;\n    if (!text) return;\n    const level = typeof message.level === \"string\" ? message.level.toLowerCase() : \"\";\n    const line = `[child:${prefix}] ${text}`;\n    const logger = context.logger;\n    switch (level) {\n        case \"error\":\n        case \"fatal\":\n            logger.error?.(line);\n            return;\n        case \"warn\":\n        case \"warning\":\n            logger.warn?.(line);\n            return;\n        case \"debug\":\n            logger.debug?.(line);\n            return;\n        case \"info\":\n        default:\n            logger.info?.(line);\n    }\n}\n\n/**\n * Build the `node` argv for `spawn`. Workers are plain `.js` (ESM), so we just\n * run them with `node`. Any exec flags the parent was started with (e.g.\n * `--inspect`) are inherited so child workers behave consistently.\n *\n * @param {string} scriptPath\n * @param {string[]} cliArgs\n * @returns {string[]}\n */\nfunction buildNodeArgs(scriptPath, cliArgs) {\n    const inheritedExecArgs = Array.isArray(process.execArgv) ? [...process.execArgv] : [];\n    return [...inheritedExecArgs, scriptPath, ...cliArgs];\n}\n\n/**\n * Where progress writes land: `context.tasksQueueName` > `params.get(\"table\")` > `\"tasks\"`.\n *\n * @param {object} context\n * @returns {string}\n */\nfunction resolveTasksTableName(context) {\n    return context.tasksQueueName || context.params?.get?.(\"table\") || \"tasks\";\n}\n\n/**\n * Announce the IPC-file-logs target once at spawn time. Emits a single info line\n * with the resolved directory and notes when `tasksLogsEnabled=false` keeps logs in-memory only.\n *\n * @param {object} context\n * @param {{ ipcFileLogs?: { basePath?: string, namespace?: string, tableName: string } }} options\n * @returns {void}\n */\nfunction announceIpcFileLogsTarget(context, options) {\n    if (!options.ipcFileLogs) return;\n    const logsDir = resolveIpcFileLogsDir(context, options.ipcFileLogs);\n    const enabledRaw = context.params?.get?.(\"tasksLogsEnabled\");\n    const logsEnabled = enabledRaw === undefined ? true : !!enabledRaw;\n    context.logger.info?.(\n        `[tasks] IPC file logs: ${logsDir}` +\n            (logsEnabled ? \"\" : \" (tasksLogsEnabled=false; not persisted)\")\n    );\n}\n\n/**\n * Single-consumer FIFO for async work: each `push` runs after the previous one\n * finishes (success or failure). Thrown errors are swallowed by the chain so one\n * bad task never wedges the rest; callers handle errors inside their own `fn`.\n *\n * @returns {{ push: (fn: () => Promise<void>) => Promise<void>, drain: () => Promise<void> }}\n */\nfunction createSerializedQueue() {\n    let chain = Promise.resolve();\n    return {\n        push(fn) {\n            chain = chain.then(fn, () => {}).catch(() => {});\n            return chain;\n        },\n        drain() {\n            return chain.catch(() => {});\n        },\n    };\n}\n\n/**\n * Fork `scriptPath` as a Node child with IPC, forward its stdio + IPC logs to the\n * parent logger, update the task row's `progress` column on `{ level: \"progress\" }`\n * payloads, and resolve with a summary once the child closes.\n *\n * Contract:\n *   - **Only** IPC payloads matching {@link isProgressPayload} touch the `progress` column.\n *     stdout/stderr are diagnostic — accumulated and forwarded to logger but never\n *     persisted to `progress`.\n *   - The worker returns its final value via `process.send({ __taskWorkerResult: ... })`;\n *     that sentinel is captured and exposed as `workerResult`.\n *   - DB write and `onProgress` callback for a given payload run sequentially on a shared\n *     queue so ordering is preserved across rapid updates.\n *\n * @param {object} context\n * @param {{\n *   scriptPath: string,\n *   task: { id: string, name: string, opid?: string|null },\n *   args?: string[],\n *   cwd?: string,\n *   onProgress?: (progressText: string) => unknown | Promise<unknown>,\n *   onChildIpcMessage?: (message: unknown) => void,\n *   ipcFileLogs?: { basePath?: string, namespace?: string, tableName: string },\n * }} options\n * @returns {Promise<{\n *   exitCode: number | null,\n *   signal: NodeJS.Signals | null,\n *   stdout: string,\n *   stderr: string,\n *   workerResult: unknown,\n *   hadErrorMessage: boolean,\n * }>}\n */\nexport async function runNodeTaskScript(context, options) {\n    const cliArgs = toCliArgs([\"--route=ipc\", \"--mode=json\", ...(options.args || [])]);\n    const nodeArgs = buildNodeArgs(options.scriptPath, cliArgs);\n    const child = spawn(process.execPath, nodeArgs, {\n        cwd: options.cwd || process.cwd(),\n        stdio: [\"ignore\", \"pipe\", \"pipe\", \"ipc\"],\n        env: {\n            ...process.env,\n            TASK_ID: options.task.id,\n            TASK_NAME: options.task.name,\n            TASK_OPID: options.task.opid || \"\",\n        },\n    });\n\n    announceIpcFileLogsTarget(context, options);\n\n    const prefix = formatChildLogPrefix(options.task);\n    const tasksTable = resolveTasksTableName(context);\n    const progressQueue = createSerializedQueue();\n\n    const state = {\n        stdout: \"\",\n        stderr: \"\",\n        workerResult: null,\n        hadErrorMessage: false,\n    };\n\n    /**\n     * Serialize a progress update: write to DB, then invoke the optional callback.\n     * Each half is independently try/caught so one failure doesn't skip the other.\n     *\n     * @param {string} text\n     */\n    const writeProgress = (text) => {\n        const trimmed = typeof text === \"string\" ? text.slice(0, MAX_PROGRESS_TEXT_LEN) : \"\";\n        if (!trimmed) return;\n        progressQueue.push(async () => {\n            const db = context.db;\n            if (db) {\n                try {\n                    await db(tasksTable).where({ id: options.task.id }).update({ progress: trimmed });\n                } catch (error) {\n                    context.logger.warn?.(\n                        `[tasks] failed to update progress for task=${options.task.id}: ${error?.message ?? String(error)}`\n                    );\n                }\n            }\n            if (options.onProgress) {\n                try {\n                    await options.onProgress(trimmed);\n                } catch (error) {\n                    context.logger.warn?.(\n                        `[tasks] reportProgress callback failed for task=${options.task.id}: ${error?.message ?? String(error)}`\n                    );\n                }\n            }\n        });\n    };\n\n    child.stdout?.on(\"data\", (chunk) => {\n        const text = String(chunk);\n        state.stdout += text;\n        if (text.trim()) {\n            context.logger.info?.(`[child:${prefix}] ${text.trimEnd()}`);\n        }\n    });\n    child.stderr?.on(\"data\", (chunk) => {\n        const text = String(chunk);\n        state.stderr += text;\n        if (text.trim()) {\n            context.logger.warn?.(`[child:${prefix}] ${text.trimEnd()}`);\n        }\n    });\n\n    child.on(\"message\", (message) => {\n        if (message && typeof message === \"object\" && \"__taskWorkerResult\" in message) {\n            state.workerResult = message.__taskWorkerResult;\n            return;\n        }\n\n        if (message && typeof message === \"object\") {\n            const level = typeof message.level === \"string\" ? message.level.toLowerCase() : \"\";\n            if (level === \"error\" || level === \"fatal\") {\n                state.hadErrorMessage = true;\n            }\n        }\n\n        appendTaskIpcLog(context, options.task, message, options.ipcFileLogs);\n\n        try {\n            options.onChildIpcMessage?.(message);\n        } catch (e) {\n            context.logger.warn?.(`[tasks] onChildIpcMessage failed: ${e?.message ?? String(e)}`);\n        }\n\n        if (isProgressPayload(message)) {\n            context.logger.progress(message.message || \"progress\", {\n                prefix: message.prefix || prefix,\n                count: Number(message.count),\n                total: Number(message.total),\n            });\n            writeProgress(formatProgressText(message, prefix));\n            return;\n        }\n\n        forwardChildLogToParent(context, prefix, message);\n    });\n\n    return await new Promise((resolve, reject) => {\n        child.on(\"error\", (error) => reject(error));\n        child.on(\"close\", (exitCode, signal) => {\n            void (async () => {\n                await flushTaskIpcLogs(context);\n                await progressQueue.drain();\n                resolve({\n                    exitCode,\n                    signal,\n                    stdout: state.stdout.trim(),\n                    stderr: state.stderr.trim(),\n                    workerResult: state.workerResult,\n                    hadErrorMessage: state.hadErrorMessage,\n                });\n            })();\n        });\n    });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,kBAAe;;;ACiIR,SAAS,kBAAkB,YAAY;AAE1C,QAAM,WAAW;AAEjB,MAAI,CAAC,SAAS,KAAK,UAAU,GAAG;AAC5B,WAAO;AAAA,EACX;AAEA,QAAM,OAAO,IAAI,KAAK,UAAU;AAChC,SAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,KAAK,KAAK,QAAQ,IAAI;AACtD;;;ACpIA,gBAAe;AACf,kBAAiB;AAOjB,eAAsB,cAAc,WAAW;AAC3C,QAAM,WAAW,YAAAC,QAAK,QAAQ,GAAG,SAAS;AAE1C,MAAI,CAAC,UAAAC,QAAG,WAAW,QAAQ,GAAG;AAC1B,UAAM,UAAAA,QAAG,SAAS,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,EACzD;AAEA,SAAO;AACX;AAkBO,SAAS,iBAAiB,UAAU;AACvC,UAAQ,UAAU;AAAA,IACd,KAAK;AAAA,IACL,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX;AACI,aAAO;AAAA,EACf;AACJ;;;AC9CA,IAAAC,aAAe;AACf,IAAAC,eAAiB;AACjB,2BAAyB;AAOlB,SAAS,iBAAiB,YAAY;AACzC,MAAI;AAEA,QAAI,cAAc;AAClB,QAAI,CAAC,WAAAC,QAAG,WAAW,UAAU,GAAG;AAC5B,YAAM,YAAY,aAAAC,QAAK,QAAQ,UAAU;AACzC,UAAI,WAAAD,QAAG,WAAW,SAAS,GAAG;AAC1B,sBAAc;AAAA,MAClB,OAAO;AAEH,sBAAc,QAAQ,aAAa,UAAU,SAAS;AAAA,MAC1D;AAAA,IACJ;AAEA,QAAI,QAAQ,aAAa,SAAS;AAG9B,aAAO;AAAA,IACX,OAAO;AAEH,YAAM,aAAS,+BAAS,UAAU,WAAW,KAAK,EAAE,UAAU,OAAO,CAAC;AACtE,YAAM,QAAQ,OAAO,KAAK,EAAE,MAAM,IAAI;AACtC,YAAM,QAAQ,MAAM,CAAC,EAAE,MAAM,KAAK;AAClC,YAAM,SAAS,SAAS,MAAM,CAAC,GAAG,EAAE;AACpC,aAAO,SAAS;AAAA,IACpB;AAAA,EACJ,SAAS,OAAO;AAEZ,WAAO;AAAA,EACX;AACJ;AASA,eAAsB,aAAa,YAAY;AAC3C,QAAM,aAAa,MAAM,OAAO,aAAkB;AAClD,MAAI;AACA,QAAI,cAAc;AAClB,QAAI,CAAC,WAAAA,QAAG,WAAW,WAAW,GAAG;AAC7B,YAAM,YAAY,aAAAC,QAAK,QAAQ,WAAW;AAC1C,oBAAc,WAAAD,QAAG,WAAW,SAAS,IAC/B,YACA,QAAQ,aAAa,UACnB,SACA;AAAA,IACZ;AACA,QAAI,OAAO,WAAW,WAAW,WAAY,QAAO;AACpD,UAAM,QAAQ,MAAM,WAAW,OAAO,WAAW;AACjD,UAAM,QAAQ,OAAO,MAAM,KAAK,IAAI,OAAO,MAAM,MAAM;AACvD,UAAM,OAAO,OAAO,MAAM,KAAK,IAAI,OAAO,MAAM,MAAM;AACtD,QAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,EAAG,QAAO;AAClD,WAAO,EAAE,MAAM,OAAO,WAAW,OAAO,MAAM;AAAA,EAClD,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;;;AClEO,SAAS,qBAAqB,OAAO;AACxC,MAAI,UAAU,EAAG,QAAO;AAExB,QAAM,IAAI;AACV,QAAM,QAAQ,CAAC,KAAK,MAAM,MAAM,MAAM,MAAM,IAAI;AAChD,QAAM,IAAI,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC;AAElD,SAAO,YAAY,QAAQ,KAAK,IAAI,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,MAAM,MAAM,CAAC;AAC1E;;;ACdO,SAAS,QAAQ,IAAI;AACxB,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAC3D;AAEO,SAAS,aAAa,OAAO;AAChC,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,SAAO,KAAK,UAAU,KAAK;AAC/B;;;ACXA,qBAAe;;;ACAf,yBAA2B;;;AC2C3B,IAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,QAAQ;AAU5C,eAAsB,gBAAgB,IAAI,MAAM,UAAU,CAAC,GAAG;AAC1D,QAAM,SAAS,mCAAmC,IAAI;AACtD,MAAI,CAAC,QAAQ,QAAQ;AACjB,UAAM,GAAG,IAAI,MAAM;AAAA,EACvB;AACA,UAAQ,QAAQ,QAAQ,YAAY,QAAQ,EAAE,CAAC,KAAK,MAAM,GAAG,QAAQ,SAAS,cAAc,EAAE,EAAE;AAChG,SAAO,EAAE,OAAO;AACpB;AAYA,eAAsB,YAAY,IAAI,WAAW,MAAM,UAAU,CAAC,GAAG;AACjE,QAAM,EAAE,SAAS,OAAO,OAAO,IAAI;AACnC,QAAM,UAAU,CAAC;AACjB,QAAM,SAAS,MAAM,GAAG,YAAY,SAAS;AAE7C,MAAI,CAAC,QAAQ;AACT,YAAQ,KAAK,gBAAgB,SAAS,KAAK,OAAO,KAAK,KAAK,OAAO,EAAE,MAAM,WAAW;AACtF,QAAI,CAAC,QAAQ;AACT,YAAM,GAAG,OAAO,YAAY,WAAW,CAAC,MAAM;AAC1C,mBAAW,UAAU,OAAO,OAAO,KAAK,OAAO,GAAG;AAC9C,iBAAO,GAAG,EAAE;AAAA,QAChB;AAAA,MACJ,CAAC;AAAA,IACL;AAAA,EACJ,OAAO;AAEH,UAAM,UAAU,CAAC;AACjB,eAAW,UAAU,OAAO,KAAK,KAAK,OAAO,GAAG;AAC5C,UAAI,CAAE,MAAM,GAAG,OAAO,UAAU,WAAW,MAAM,GAAI;AACjD,gBAAQ,KAAK,MAAM;AAAA,MACvB;AAAA,IACJ;AACA,QAAI,QAAQ,SAAS,GAAG;AACpB,cAAQ,KAAK,eAAe,SAAS,eAAe,QAAQ,KAAK,IAAI,CAAC,EAAE;AACxE,UAAI,CAAC,QAAQ;AACT,cAAM,GAAG,OAAO,WAAW,WAAW,CAAC,MAAM;AACzC,qBAAW,UAAU,SAAS;AAC1B,iBAAK,QAAQ,MAAM,EAAE,GAAG,EAAE;AAAA,UAC9B;AAAA,QACJ,CAAC;AAAA,MACL;AAAA,IACJ;AAAA,EACJ;AAEA,aAAW,SAAS,KAAK,WAAW,CAAC,GAAG;AACpC,UAAM,eAAe,MAAM,YAAY,IAAI,WAAW,OAAO,OAAO;AACpE,YAAQ,KAAK,GAAG,YAAY;AAAA,EAChC;AAEA,aAAW,UAAU,SAAS;AAC1B,YAAQ,QAAQ,YAAY,QAAQ,EAAE,CAAC,KAAK,MAAM,GAAG,SAAS,cAAc,EAAE,EAAE;AAAA,EACpF;AACA,SAAO;AACX;AAaA,eAAsB,YAAY,IAAI,WAAW,OAAO,UAAU,CAAC,GAAG;AAClE,QAAM,EAAE,SAAS,MAAM,IAAI;AAC3B,QAAM,OAAO,MAAM,SAAS,iBAAiB;AAC7C,QAAM,OAAO,MAAM,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI;AACzD,QAAM,OAAO,OAAO,IAAI,QAAQ,oBAAoB,EAAE,EAAE,WAAW,YAAY;AAE/E,MAAI,MAAM;AACN,UAAME,OAAM,UAAU,IAAI,mBAAmB,MAAM,IAAI,SAAS,SAAS,MAAM,IAAI;AACnF,UAAM,EAAE,KAAK,IAAI,MAAM,GAAG,IAAI,gDAAgD,CAAC,MAAM,IAAI,CAAC;AAC1F,QAAI,KAAK,SAAS,EAAG,QAAO,CAAC;AAC7B,QAAI,CAAC,OAAQ,OAAM,GAAG,IAAIA,IAAG;AAC7B,WAAO,CAACA,IAAG;AAAA,EACf;AAGA,QAAM,MAAM,UAAU,IAAI,IAAI,MAAM,IAAI,OAAO,SAAS,KAAK,IAAI;AACjE,MAAI,CAAC,QAAQ;AACT,QAAI;AACA,YAAM,GAAG,IAAI,GAAG;AAAA,IACpB,SAAS,OAAO;AACZ,UAAI,CAAC,4BAA4B,KAAK,OAAO,WAAW,EAAE,EAAG,OAAM;AACnE,aAAO,CAAC;AAAA,IACZ;AAAA,EACJ;AACA,SAAO,CAAC,GAAG;AACf;AAYA,eAAsB,aAAa,IAAI,MAAM,UAAU,CAAC,GAAG;AACvD,QAAM,UAAU,CAAC;AACjB,aAAW,aAAa,KAAK,cAAc,CAAC,GAAG;AAE3C,UAAM,EAAE,OAAO,IAAI,MAAM,gBAAgB,IAAI,WAAW,OAAO;AAC/D,QAAI,QAAQ,OAAQ,SAAQ,KAAK,MAAM;AAAA,EAC3C;AACA,aAAW,CAAC,WAAW,SAAS,KAAK,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,GAAG;AACpE,YAAQ,KAAK,GAAI,MAAM,YAAY,IAAI,WAAW,WAAW,OAAO,CAAE;AAAA,EAC1E;AACA,SAAO,EAAE,UAAU,QAAQ,EAAE,GAAG,QAAQ;AAC5C;;;ACxKA,IAAM,SAAS,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,KAAK;AAUtD,SAAS,iBAAiB,OAAO,OAAO;AAC3C,SAAO,MAAM,SAAS,GAAG,IAAI,MAAM,QAAQ,KAAK,KAAK,IAAI;AAC7D;AAUO,SAAS,cAAc,OAAO;AACjC,QAAM,QAAQ;AACd,MAAI,UAAU;AACd,SAAO,MAAM;AACT,UAAM,QAAQ,MAAM,KAAK,OAAO;AAChC,QAAI,CAAC,MAAO;AACZ,UAAM,MAAM,MAAM,CAAC;AACnB,QAAI,QAAQ,OAAO,MAAM,CAAC,CAAC;AAC3B,QAAI,OAAO,OAAO,MAAM,CAAC,CAAC;AAC1B,QAAI,OAAO,OAAO;AACd,OAAC,OAAO,IAAI,IAAI,CAAC,MAAM,KAAK;AAAA,IAChC;AACA,UAAM,SAAS,CAAC;AAChB,aAAS,IAAI,OAAO,KAAK,MAAM,KAAK,GAAG;AACnC,aAAO,KAAK,CAAC;AAAA,IACjB;AACA,cAAU,QAAQ,QAAQ,KAAK,OAAO,KAAK,GAAG,CAAC;AAAA,EACnD;AACA,SAAO;AACX;AASO,SAAS,aAAa,OAAO;AAChC,QAAM,QAAQ,gBAAgB,KAAK,KAAK;AACxC,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAO,MAAM,CAAC;AACpB,QAAM,OAAO,OAAO,MAAM,CAAC,CAAC;AAC5B,MAAI,CAAC,OAAO,SAAS,IAAI,KAAK,QAAQ,EAAG,QAAO;AAChD,SAAO,KACF,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC,EACpB,OAAO,CAAC,MAAM,OAAO,SAAS,CAAC,KAAK,IAAI,SAAS,CAAC,EAClD,KAAK,GAAG;AACjB;AAUO,SAAS,eAAe,SAAS;AACpC,QAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,KAAK;AACxC,MAAI,MAAM,WAAW,GAAG;AACpB,UAAM,IAAI,MAAM,qBAAqB,OAAO,sDAAsD;AAAA,EACtG;AACA,SAAO,MACF,IAAI,CAAC,OAAO,QAAQ,iBAAiB,OAAO,OAAO,GAAG,CAAC,CAAC,EACxD,IAAI,CAAC,UAAU,cAAc,KAAK,CAAC,EACnC,IAAI,CAAC,UAAU,aAAa,KAAK,CAAC;AAC3C;AASA,SAAS,aAAa,OAAO,OAAO;AAChC,QAAM,UAAU,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC;AACrD,SAAO,QAAQ,SAAS,KAAK;AACjC;AAUO,SAAS,qBAAqB,QAAQ,MAAM;AAC/C,SACI,aAAa,OAAO,CAAC,GAAG,KAAK,WAAW,CAAC,KACzC,aAAa,OAAO,CAAC,GAAG,KAAK,WAAW,CAAC,KACzC,aAAa,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,KACvC,aAAa,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,KACtC,aAAa,OAAO,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,KAC3C,aAAa,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC;AAE7C;AAYO,SAAS,YAAY,SAAS,OAAO,oBAAI,KAAK,GAAG;AACpD,QAAM,SAAS,eAAe,OAAO;AACrC,SAAO,qBAAqB,QAAQ,IAAI;AAC5C;AAEA,IAAM,gBAAgB;AACtB,IAAM,4BAA4B,KAAK,MAAM,KAAK,KAAK,KAAK;AAWrD,SAAS,cACZ,SACA,OAAO,oBAAI,KAAK,GAChB,cAAc,2BAChB;AACE,QAAM,SAAS,eAAe,OAAO;AACrC,MAAI,IAAI,KAAK,MAAM,KAAK,QAAQ,IAAI,KAAK,aAAa,IAAI;AAC1D,QAAM,MAAM,IAAI;AAChB,SAAO,KAAK,KAAK;AACb,UAAM,OAAO,IAAI,KAAK,CAAC;AACvB,QAAI,qBAAqB,QAAQ,IAAI,GAAG;AACpC,aAAO;AAAA,IACX;AACA,SAAK;AAAA,EACT;AACA,QAAM,IAAI;AAAA,IACN,gCAAgC,OAAO,YAAY,WAAW,YAAY,KAAK,YAAY,CAAC;AAAA,EAChG;AACJ;;;AFzJA,SAAS,MAAM,SAAS;AACpB,QAAM,KAAK,QAAQ;AACnB,MAAI,CAAC,IAAI;AACL,UAAM,IAAI,MAAM,iFAAiF;AAAA,EACrG;AACA,SAAO;AACX;AAYO,SAAS,kBAAkB,WAAW;AACzC,SAAO;AAAA,IACH,YAAY;AAAA,IACZ,cAAc,GAAG,SAAS;AAAA,IAC1B,eAAe,GAAG,SAAS;AAAA,EAC/B;AACJ;AAWA,SAAS,eAAe,mBAAmB;AACvC,SAAO;AAAA,IACH,SAAS;AAAA,MACL,IAAI,CAAC,GAAG,OAAO,EAAE,KAAK,IAAI,EAAE,QAAQ,EAAE,UAAU,GAAG,IAAI,oBAAoB,CAAC;AAAA,MAC5E,YAAY,CAAC,GAAG,OAAO,EAAE,UAAU,YAAY,EAAE,YAAY,EAAE,UAAU,GAAG,GAAG,IAAI,CAAC;AAAA,MACpF,YAAY,CAAC,MAAM,EAAE,UAAU,YAAY;AAAA,MAC3C,cAAc,CAAC,MAAM,EAAE,UAAU,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA,MAK/C,UAAU,CAAC,MAAM,EAAE,QAAQ,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE;AAAA,MAEjE,UAAU,CAAC,MAAM,EAAE,KAAK,UAAU;AAAA,MAClC,aAAa,CAAC,MAAM,EAAE,UAAU,aAAa,EAAE,UAAU,IAAI;AAAA,MAC7D,UAAU,CAAC,MAAM,EAAE,UAAU,UAAU,EAAE,UAAU,IAAI;AAAA,MAEvD,MAAM,CAAC,MAAM,EAAE,KAAK,MAAM,EAAE,YAAY;AAAA,MACxC,MAAM,CAAC,MAAM,EAAE,KAAK,MAAM;AAAA,MAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,QAAQ;AAAA;AAAA,MAG/B,eAAe,CAAC,MAAM,EAAE,KAAK,eAAe;AAAA;AAAA,MAC5C,iBAAiB,CAAC,MAAM,EAAE,QAAQ,iBAAiB;AAAA,MACnD,cAAc,CAAC,MAAM,EAAE,KAAK,cAAc;AAAA;AAAA,MAC1C,aAAa,CAAC,MAAM,EAAE,KAAK,aAAa;AAAA;AAAA,MAExC,QAAQ,CAAC,MAAM,EAAE,KAAK,QAAQ,EAAE,YAAY,EAAE,UAAU,MAAM;AAAA;AAAA,MAC9D,mBAAmB,CAAC,MAAM,EAAE,UAAU,mBAAmB,EAAE,UAAU,IAAI;AAAA,MAEzE,UAAU,CAAC,MAAM,EAAE,KAAK,UAAU;AAAA,MAClC,SAAS,CAAC,MAAM,EAAE,QAAQ,SAAS;AAAA,MACnC,SAAS,CAAC,MAAM,EAAE,MAAM,SAAS;AAAA,IACrC;AAAA,IACA,SAAS;AAAA,MACL;AAAA,QACI,SAAS,CAAC,iBAAiB,UAAU,YAAY,YAAY;AAAA,QAC7D,MAAM,GAAG,iBAAiB;AAAA,MAC9B;AAAA,MACA,EAAE,SAAS,CAAC,iBAAiB,MAAM,GAAG,MAAM,GAAG,iBAAiB,kBAAkB;AAAA,MAClF,EAAE,SAAS,CAAC,cAAc,GAAG,MAAM,GAAG,iBAAiB,oBAAoB;AAAA,MAC3E,EAAE,SAAS,CAAC,QAAQ,cAAc,GAAG,MAAM,GAAG,iBAAiB,yBAAyB;AAAA,IAC5F;AAAA,EACJ;AACJ;AAQA,SAAS,kBAAkB,eAAe;AACtC,SAAO;AAAA,IACH,SAAS;AAAA,MACL,IAAI,CAAC,GAAG,OAAO,EAAE,KAAK,IAAI,EAAE,QAAQ,EAAE,UAAU,GAAG,IAAI,oBAAoB,CAAC;AAAA,MAE5E,YAAY,CAAC,MAAM,EAAE,KAAK,YAAY,EAAE,YAAY;AAAA,MACpD,eAAe,CAAC,MAAM,EAAE,KAAK,eAAe,EAAE,YAAY;AAAA;AAAA,MAC1D,iBAAiB,CAAC,MAAM,EAAE,QAAQ,iBAAiB,EAAE,YAAY,EAAE,UAAU,CAAC;AAAA,MAC9E,cAAc,CAAC,MAAM,EAAE,KAAK,cAAc,EAAE,YAAY;AAAA;AAAA,MACxD,aAAa,CAAC,MAAM,EAAE,KAAK,aAAa,EAAE,YAAY;AAAA;AAAA,MACtD,KAAK,CAAC,MAAM,EAAE,QAAQ,KAAK;AAAA,MAE3B,UAAU,CAAC,MAAM,EAAE,KAAK,UAAU;AAAA,MAElC,YAAY,CAAC,GAAG,OAAO,EAAE,UAAU,YAAY,EAAE,YAAY,EAAE,UAAU,GAAG,GAAG,IAAI,CAAC;AAAA,MACpF,cAAc,CAAC,GAAG,OAAO,EAAE,UAAU,cAAc,EAAE,YAAY,EAAE,UAAU,GAAG,GAAG,IAAI,CAAC;AAAA,IAC5F;AAAA,IACA,SAAS;AAAA,MACL;AAAA,QACI,SAAS,CAAC,cAAc,cAAc;AAAA,QACtC,MAAM,GAAG,aAAa;AAAA,QACtB,QAAQ;AAAA,MACZ;AAAA,MACA;AAAA,QACI,SAAS,CAAC,cAAc,iBAAiB,cAAc;AAAA,QACvD,MAAM,GAAG,aAAa;AAAA,MAC1B;AAAA,MACA,EAAE,SAAS,CAAC,cAAc,cAAc,GAAG,MAAM,GAAG,aAAa,kBAAkB;AAAA,IACvF;AAAA;AAAA,EAEJ;AACJ;AAUO,SAAS,gBAAgB,YAAY,SAAS;AACjD,QAAM,EAAE,YAAY,cAAc,cAAc,IAAI,kBAAkB,SAAS;AAC/E,SAAO;AAAA,IACH,YAAY,CAAC,WAAW;AAAA,IACxB,QAAQ;AAAA,MACJ,CAAC,UAAU,GAAG,eAAe,UAAU;AAAA,MACvC,CAAC,YAAY,GAAG,eAAe,YAAY;AAAA,MAC3C,CAAC,aAAa,GAAG,kBAAkB,aAAa;AAAA,IACpD;AAAA,EACJ;AACJ;AAcO,SAAS,8BAA8B,KAAK,YAAY,CAAC,GAAG;AAC/D,QAAM,EAAE,IAAI,GAAG,SAAS,IAAI;AAC5B,QAAM,OACF,UAAU,SAAS,SACb,UAAU,OACV,SAAS,QAAQ,QAAQ,OAAO,SAAS,IAAI,EAAE,KAAK,MAAM,KACxD,SAAS,OACT;AACZ,SAAO;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH;AAAA,EACJ;AACJ;AA0BA,eAAsB,iBAAiB,SAAS,UAAU,CAAC,GAAG;AAC1D,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,YAAY,QAAQ,aAAa,CAAC,MAAM,OAAO,CAAC;AACtD,QAAM,MAAM,QAAQ,UAAU;AAC9B,QAAM,EAAE,YAAY,cAAc,cAAc,IAAI,kBAAkB,SAAS;AAC/E,QAAM,OAAO,gBAAgB,SAAS;AAEtC,aAAW,MAAM,WAAW;AACxB,UAAM,QAAQ,IAAI,QAAQ,QAAQ;AAElC,QAAI,UAAU;AACV,UAAI,QAAQ;AACR,YAAI;AAAA,UACA,gCAA2B,KAAK,0BAA0B,YAAY,KAAK,UAAU,KAAK,aAAa;AAAA,QAC3G;AAAA,MACJ,OAAO;AACH,cAAM,GAAG,OAAO,kBAAkB,YAAY;AAC9C,cAAM,GAAG,OAAO,kBAAkB,UAAU;AAC5C,cAAM,GAAG,OAAO,kBAAkB,aAAa;AAAA,MACnD;AAAA,IACJ;AAEA,UAAM,EAAE,QAAQ,IAAI,MAAM,aAAa,IAAI,MAAM,EAAE,QAAQ,QAAQ,QAAQ,OAAO,CAAC;AAInF,UAAM,cAAc,MAAM,yBAAyB,IAAI,CAAC,YAAY,YAAY,GAAG;AAAA,MAC/E;AAAA,MACA;AAAA,MACA;AAAA,IACJ,CAAC;AAED,UAAM,aAAa,CAAC,GAAG,SAAS,GAAG,WAAW;AAC9C,QAAI,QAAQ;AACR,UAAI,WAAW,WAAW,GAAG;AACzB,YAAI,OAAO,gCAA2B,KAAK,YAAY,SAAS,8BAA8B;AAAA,MAClG,OAAO;AACH,YAAI;AAAA,UACA,gCAA2B,KAAK,eAAe,WAAW,MAAM,4BAA4B,SAAS;AAAA,QACzG;AACA,mBAAW,KAAK,WAAY,KAAI,OAAO,OAAO,CAAC,EAAE;AAAA,MACrD;AAAA,IACJ,WAAW,WAAW,SAAS,GAAG;AAC9B,UAAI;AAAA,QACA,kBAAkB,KAAK,aAAa,WAAW,MAAM,gCAAgC,SAAS;AAAA,MAClG;AAAA,IACJ;AAAA,EACJ;AACJ;AAMA,eAAe,yBAAyB,IAAI,YAAY,EAAE,QAAQ,KAAK,MAAM,GAAG;AAC5E,QAAM,UAAU,CAAC;AACjB,aAAW,SAAS,YAAY;AAC5B,QAAI,CAAE,MAAM,GAAG,YAAY,KAAK,EAAE,MAAM,MAAM,KAAK,EAAI;AACvD,UAAM,UAAU,MAAM,GAAG,OAAO,UAAU,OAAO,MAAM;AACvD,UAAM,UAAU,MAAM,GAAG,OAAO,UAAU,OAAO,MAAM;AACvD,QAAI,CAAC,WAAW,CAAC,QAAS;AAC1B,UAAM,MAAM,gBAAgB,KAAK;AACjC,YAAQ,KAAK,GAAG;AAChB,QAAI,QAAQ;AACR,WAAK,OAAO,gCAA2B,KAAK,KAAK,GAAG,EAAE;AAAA,IAC1D,OAAO;AACH,YAAM,GAAG,IAAI,GAAG;AAChB,WAAK,OAAO,kBAAkB,KAAK,2BAA2B,KAAK,OAAO;AAAA,IAC9E;AAAA,EACJ;AACA,SAAO;AACX;AAwBA,eAAsB,YAAY,SAAS,SAAS;AAChD,QAAM,KAAK,MAAM,OAAO;AACxB,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,EAAE,WAAW,IAAI,kBAAkB,SAAS;AAClD,QAAM,SAAK,+BAAW;AAEtB,QAAM,OAAO,QAAQ,QAAQ,QAAQ;AACrC,MAAI,CAAC,MAAM;AACP,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC7D;AAEA,QAAM,WAAW,QAAQ,UAAU,KAAK,IAAI,QAAQ,WAAW;AAC/D,MAAI,YAAY;AAChB,MAAI,QAAQ,cAAc,QAAW;AACjC,gBAAY,QAAQ,aAAa,OAAO,OAAO,IAAI,KAAK,QAAQ,SAAS;AAAA,EAC7E,WAAW,UAAU;AACjB,gBAAY,cAAc,UAAU,oBAAI,KAAK,CAAC;AAAA,EAClD;AAEA,QAAM,MAAM;AAAA,IACR;AAAA,IACA;AAAA,IACA,QAAQ,aAAa,QAAQ,UAAU,IAAI;AAAA,IAC3C,MAAM,QAAQ,QAAQ;AAAA,IACtB,UAAU,QAAQ,YAAY;AAAA,IAC9B;AAAA,IACA,aAAa;AAAA,IACb,eAAe,QAAQ,gBAAgB;AAAA,IACvC,iBAAiB,QAAQ,kBAAkB;AAAA,IAC3C,cAAc,QAAQ,eAAe;AAAA,IACrC,aAAa,QAAQ,cAAc;AAAA,IACnC,QAAQ;AAAA,IACR,mBAAmB,GAAG,GAAG,IAAI;AAAA,EACjC;AAGA,MAAI,MAAM,yBAAyB,IAAI,UAAU,GAAG;AAChD,QAAI,OAAO;AAAA,EACf;AAEA,QAAM,GAAG,UAAU,EAAE,OAAO,GAAG;AAC/B,SAAO;AACX;AAGA,IAAM,wBAAwB,oBAAI,IAAI;AAEtC,eAAe,yBAAyB,IAAI,WAAW;AACnD,QAAM,MAAM,GAAG,IAAI,QAAQ,QAAQ,IAAI,IAAI,SAAS;AACpD,MAAI,CAAC,sBAAsB,IAAI,GAAG,GAAG;AACjC,0BAAsB,IAAI,KAAK,MAAM,GAAG,OAAO,UAAU,WAAW,MAAM,CAAC;AAAA,EAC/E;AACA,SAAO,sBAAsB,IAAI,GAAG;AACxC;AAYA,eAAsB,mBAAmB,SAAS,YAAY,QAAQ,UAAU;AAC5E,QAAM,KAAK,MAAM,OAAO;AACxB,QAAM,GAAG,UAAU,EAAE,MAAM,EAAE,IAAI,OAAO,CAAC,EAAE,OAAO;AAAA,IAC9C,UAAU,OAAO,aAAa,WAAW,WAAW,KAAK,UAAU,QAAQ;AAAA,EAC/E,CAAC;AACL;AAYO,SAAS,2BAA2B,SAAS,YAAY,QAAQ;AACpE,MAAI,OAAO;AACX,MAAI,UAAU;AACd,MAAI,aAAa;AAEjB,SAAO,CAAC,aAAa;AACjB,cAAU;AACV,iBAAa;AACb,QAAI,KAAM,QAAO;AAEjB,YAAQ,YAAY;AAChB,UAAI;AACA,eAAO,YAAY;AACf,uBAAa;AACb,gBAAM,QAAQ;AACd,cAAI;AACA,kBAAM,mBAAmB,SAAS,YAAY,QAAQ,KAAK;AAAA,UAC/D,SAAS,KAAK;AACV,oBAAQ,QAAQ;AAAA,cACZ,sCAAsC,MAAM,KAAK,KAAK,WAAW,GAAG;AAAA,YACxE;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ,UAAE;AACE,eAAO;AAAA,MACX;AAAA,IACJ,GAAG;AAEH,WAAO;AAAA,EACX;AACJ;AAGA,IAAI,0BAA0B;AASvB,SAAS,2BAA2B,IAAI;AAC3C,4BAA0B,OAAO,OAAO,aAAa,KAAK;AAC9D;AAEA,SAAS,gBAAgB,KAAK;AAC1B,MAAI,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO;AAClE,MAAI,OAAO,QAAQ,UAAU;AACzB,QAAI;AACA,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,UAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,EAAG,QAAO;AAAA,IAC/E,QAAQ;AAAA,IAER;AAAA,EACJ;AACA,SAAO;AACX;AAUO,SAAS,gBAAgB,KAAK;AACjC,QAAM,OAAO,OAAO,KAAK,QAAQ,MAAM,EAAE,KAAK,KAAK;AACnD,QAAM,SAAS,gBAAgB,KAAK,MAAM;AAC1C,QAAM,WAAW,QAAQ,WAAW,OAAO,OAAO,OAAO,OAAO,EAAE,KAAK,IAAI;AAC3E,MAAI,SAAU,QAAO;AACrB,MAAI,yBAAyB;AACzB,UAAM,QAAQ,wBAAwB,KAAK,EAAE,MAAM,OAAO,CAAC;AAC3D,QAAI,SAAS,QAAQ,OAAO,KAAK,EAAE,KAAK,EAAG,QAAO,OAAO,KAAK,EAAE,KAAK;AAAA,EACzE;AACA,QAAM,SAAS,QAAQ,UAAU,OAAO,OAAO,OAAO,MAAM,EAAE,KAAK,IAAI;AACvE,MAAI,OAAQ,QAAO,GAAG,IAAI,IAAI,MAAM;AACpC,SAAO;AACX;;;ADncA,SAASC,OAAM,SAAS;AACpB,QAAM,KAAK,QAAQ;AACnB,MAAI,CAAC,IAAI;AACL,UAAM,IAAI,MAAM,uCAAuC;AAAA,EAC3D;AACA,SAAO;AACX;AAUA,SAAS,oBAAoB,OAAO;AAChC,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,MAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO;AAC/D,MAAI,OAAO,UAAU,UAAU;AAC3B,QAAI;AACA,YAAM,IAAI,KAAK,MAAM,KAAK;AAC1B,aAAO,KAAK,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,KAAK,IAAI,IAAI,CAAC;AAAA,IACtE,QAAQ;AACJ,aAAO,CAAC;AAAA,IACZ;AAAA,EACJ;AACA,SAAO,CAAC;AACZ;AASA,IAAI,4BAA4B,uBAAO,OAAO,IAAI;AAQ3C,SAAS,6BAA6B,KAAK;AAC9C,QAAM,OAAO,uBAAO,OAAO,IAAI;AAC/B,MAAI,OAAO,OAAO,QAAQ,UAAU;AAChC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC5C,YAAM,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,YAAY;AACzC,UAAI,CAAC,KAAK,CAAC,OAAO,SAAS,OAAO,KAAK,CAAC,EAAG;AAC3C,WAAK,CAAC,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IACnD;AAAA,EACJ;AACA,8BAA4B;AAChC;AASA,SAAS,iBAAiB,KAAK;AAC3B,QAAM,IAAI,OAAO,OAAO,EAAE,EACrB,KAAK,EACL,QAAQ,qBAAqB,GAAG,EAChC,QAAQ,YAAY,EAAE;AAC3B,SAAO,EAAE,MAAM,GAAG,EAAE,KAAK;AAC7B;AAUA,SAAS,oBAAoB,cAAc,UAAU;AACjD,MAAI,aAAa,UAAa,OAAO,SAAS,QAAQ,GAAG;AACrD,WAAO,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,QAAQ,CAAC,CAAC;AAAA,EACnD;AACA,QAAM,IAAI,aAAa,KAAK,EAAE,YAAY;AAC1C,SAAO,0BAA0B,CAAC,KAAK;AAC3C;AAGO,SAAS,yBAAyB,cAAc,UAAU;AAC7D,SAAO,oBAAoB,cAAc,QAAQ;AACrD;AAcA,eAAe,kBACX,IACA,eACA,WACA,cACA,SACA,cACF;AACE,QAAM,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO;AAC5C,MAAI,IAAI,GAAG,aAAa,EACnB,MAAM,EAAE,YAAY,WAAW,eAAe,aAAa,CAAC,EAC5D,MAAM,gBAAgB,KAAK,MAAM;AACtC,MAAI,cAAc;AACd,QAAI,EAAE,SAAS,MAAM,YAAY;AAAA,EACrC;AACA,QAAM,MAAM,MAAM,EAAE,MAAM,aAAa,EAAE,MAAM;AAC/C,SAAO,OAAO,KAAK,SAAS,CAAC;AACjC;AAYA,eAAe,yBACX,IACA,eACA,WACA,cACA,SACF;AACE,QAAM,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO;AAC5C,QAAM,OAAO,MAAM,GAAG,aAAa,EAC9B,MAAM,EAAE,YAAY,WAAW,eAAe,aAAa,CAAC,EAC5D,MAAM,gBAAgB,KAAK,MAAM,EACjC,OAAO,iBAAiB;AAC7B,QAAM,MAAM,oBAAI,IAAI;AACpB,aAAW,KAAK,MAAM;AAClB,UAAM,IAAI,OAAO,EAAE,eAAe;AAClC,QAAI,OAAO,SAAS,CAAC,KAAK,KAAK,EAAG,KAAI,IAAI,KAAK,MAAM,CAAC,CAAC;AAAA,EAC3D;AACA,SAAO;AACX;AASA,SAAS,kBAAkB,OAAO;AAC9B,QAAM,OAAO,OAAO,QAAQ,OAAO;AACnC,SAAO,SAAS,WAAW,OAAO,OAAO,WAAW,EAAE,EAAE,SAAS,eAAe;AACpF;AAUA,SAAS,cAAc,SAAS;AAC5B,QAAM,OAAO,QAAQ,YAAY,OAAO,QAAQ,aAAa,WAAW,EAAE,GAAG,QAAQ,SAAS,IAAI,CAAC;AACnG,MAAI,QAAQ,QAAQ;AAChB,SAAK,eAAe,QAAQ;AAAA,EAChC;AACA,SAAO,aAAa,OAAO,KAAK,IAAI,EAAE,SAAS,OAAO,IAAI;AAC9D;AAWA,SAAS,uBAAuB,UAAU,UAAU,UAAU;AAC1D,MAAI,aAAa,UAAa,aAAa,QAAQ,OAAO,SAAS,OAAO,QAAQ,CAAC,GAAG;AAClF,UAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,QAAQ,CAAC,CAAC;AAClD,QAAI,SAAS,IAAI,CAAC,GAAG;AACjB,YAAM,IAAI,MAAM,qCAAqC,CAAC,uCAAuC;AAAA,IACjG;AACA,QAAI,aAAa,UAAa,WAAW,KAAK,IAAI,UAAU;AACxD,YAAM,IAAI,MAAM,gCAAgC,CAAC,iCAAiC,QAAQ,iBAAiB;AAAA,IAC/G;AACA,WAAO;AAAA,EACX;AACA,QAAM,MAAM,aAAa,UAAa,WAAW,IAAI,WAAW;AAChE,WAAS,IAAI,GAAG,KAAK,KAAK,KAAK;AAC3B,QAAI,CAAC,SAAS,IAAI,CAAC,EAAG,QAAO;AAAA,EACjC;AACA,QAAM,IAAI,MAAM,0DAA0D,GAAG,GAAG;AACpF;AAWA,SAAS,mBAAmB,WAAW,UAAU,gBAAgB;AAC7D,SAAO,GAAG,SAAS,IAAI,QAAQ,IAAI,cAAc;AACrD;AA6BA,eAAsB,2BAA2B,SAAS,SAAS;AAC/D,QAAM,KAAKA,OAAM,OAAO;AACxB,QAAM,gBAAgB,kBAAkB,QAAQ,SAAS,EAAE;AAC3D,QAAM,eAAe,QAAQ,aAAa,KAAK;AAC/C,MAAI,CAAC,cAAc;AACf,UAAM,IAAI,MAAM,sDAAsD;AAAA,EAC1E;AAEA,QAAM,aAAa,eAAAC,QAAG,SAAS;AAC/B,QAAM,MAAM,OAAO,QAAQ,QAAQ,WAAW,QAAQ,MAAM;AAC5D,QAAM,OAAO,cAAc,OAAO;AAClC,QAAM,YAAY,iBAAiB,YAAY;AAC/C,QAAM,WAAW,iBAAiB,UAAU;AAE5C,QAAM,aAAa,oBAAoB,cAAc,QAAQ,iBAAiB;AAC9E,QAAM,aAAa,MAAM,kBAAkB,IAAI,eAAe,QAAQ,WAAW,cAAc,QAAQ,SAAS,MAAS;AAEzH,MAAI,aAAa,KAAK,cAAc,YAAY;AAC5C,UAAM,MAAM,gDAAgD,YAAY,MAAM,UAAU,eAAe,UAAU,WAAW,QAAQ,SAAS;AAC7I,QAAI,QAAQ,qBAAqB;AAC7B,YAAM,IAAI,MAAM,GAAG;AAAA,IACvB;AACA,YAAQ,OAAO,OAAO,GAAG,GAAG,qDAAqD;AAAA,EACrF;AAEA,QAAM,WAAW,aAAa,IAAI,aAAa;AAC/C,QAAM,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ,OAAO;AAEpD,QAAM,eAAe;AACrB,WAAS,UAAU,GAAG,UAAU,cAAc,WAAW;AACrD,UAAM,WAAW,MAAM,yBAAyB,IAAI,eAAe,QAAQ,WAAW,cAAc,QAAQ,OAAO;AACnH,UAAM,iBAAiB,uBAAuB,UAAU,QAAQ,gBAAgB,QAAQ;AAExF,UAAM,iBAAiB,QAAQ,aAAa,KAAK,IAC3C,iBAAiB,QAAQ,YAAY,KAAK,CAAC,IAC3C,mBAAmB,WAAW,UAAU,cAAc;AAE5D,UAAM,WAAW,MAAM,GAAG,aAAa,EAClC,MAAM,EAAE,YAAY,QAAQ,WAAW,cAAc,eAAe,CAAC,EACrE,MAAM;AAEX,QAAI,UAAU;AACV,YAAM,WAAW,IAAI,KAAK,SAAS,YAAY;AAC/C,YAAM,UAAU,CAAC,OAAO,MAAM,SAAS,QAAQ,CAAC,KAAK,WAAW;AAEhE,UAAI,SAAS;AACT,YAAI,QAAQ,aAAa,KAAK,GAAG;AAC7B,gBAAM,IAAI;AAAA,YACN,qCAAqC,cAAc;AAAA,UACvD;AAAA,QACJ;AACA,gBAAQ,OAAO;AAAA,UACX,qCAAqC,cAAc,iDAAiD,UAAU,CAAC;AAAA,QACnH;AACA,YAAI,QAAQ,mBAAmB,UAAa,QAAQ,mBAAmB,MAAM;AACzE,gBAAM,IAAI;AAAA,YACN,qCAAqC,cAAc,YAAY,cAAc;AAAA,UACjF;AAAA,QACJ;AACA,cAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,KAAK,UAAU,EAAE,CAAC;AACzD;AAAA,MACJ;AAEA,YAAM,GAAG,aAAa,EACjB,MAAM,EAAE,IAAI,SAAS,GAAG,CAAC,EACzB,OAAO;AAAA,QACJ,aAAa;AAAA,QACb;AAAA,QACA,UAAU;AAAA,QACV,eAAe;AAAA,QACf,iBAAiB;AAAA,QACjB,cAAc,GAAG,GAAG,IAAI;AAAA,MAC5B,CAAC;AAEL,YAAM,MAAM;AAAA,QACR,aAAa;AAAA,QACb;AAAA,QACA,WAAW,QAAQ;AAAA,QACnB,QAAQ,QAAQ;AAAA,QAChB,OAAO,OAAO,SAAS,EAAE;AAAA,QACzB;AAAA,QACA;AAAA,MACJ;AACA,cAAQ,mBAAmB;AAC3B,cAAQ,kBAAkB;AAE1B,cAAQ,OAAO;AAAA,QACX,gDAAgD,cAAc,aAAa,cAAc,UAAU,YAAY,UAAU,QAAQ,SAAS;AAAA,MAC9I;AACA,aAAO;AAAA,IACX;AAEA,QAAI;AACA,YAAM,OAAO,MAAM,GAAG,aAAa,EAC9B,OAAO;AAAA,QACJ,YAAY,QAAQ;AAAA,QACpB,eAAe;AAAA,QACf,iBAAiB;AAAA,QACjB,cAAc;AAAA,QACd,aAAa;AAAA,QACb;AAAA,QACA,UAAU;AAAA,QACV,cAAc,GAAG,GAAG,IAAI;AAAA,QACxB,YAAY,GAAG,GAAG,IAAI;AAAA,MAC1B,CAAC,EACA,UAAU,CAAC,MAAM,cAAc,CAAC;AAErC,YAAM,MAAM,MAAM,QAAQ,IAAI,IAAI,KAAK,CAAC,IAAI;AAC5C,UAAI,QAAQ,OAAO,OAAO,QAAQ,WAAW,OAAO,IAAI,MAAM,EAAE,IAAI;AACpE,UAAI,CAAC,OAAO;AACR,cAAM,QAAQ,MAAM,GAAG,aAAa,EAC/B,MAAM,EAAE,YAAY,QAAQ,WAAW,cAAc,eAAe,CAAC,EACrE,MAAM;AACX,gBAAQ,OAAO,MAAM,OAAO,OAAO,MAAM,EAAE,IAAI;AAAA,MACnD;AACA,UAAI,CAAC,MAAO;AAEZ,YAAM,SAAS;AAAA,QACX,aAAa,OAAO,KAAK,gBAAgB,cAAc;AAAA,QACvD;AAAA,QACA,WAAW,QAAQ;AAAA,QACnB,QAAQ,QAAQ;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,MACJ;AACA,cAAQ,mBAAmB;AAC3B,cAAQ,kBAAkB;AAE1B,cAAQ,OAAO;AAAA,QACX,uCAAuC,OAAO,WAAW,aAAa,cAAc,UAAU,YAAY,UAAU,QAAQ,SAAS;AAAA,MACzI;AACA,aAAO;AAAA,IACX,SAAS,OAAO;AACZ,UAAI,CAAC,kBAAkB,KAAK,GAAG;AAC3B,cAAM;AAAA,MACV;AACA,cAAQ,OAAO,OAAO,uCAAuC,cAAc,wBAAwB,UAAU,CAAC,GAAG;AAAA,IACrH;AAAA,EACJ;AAEA,QAAM,IAAI;AAAA,IACN,mEAAmE,YAAY,UAAU,QAAQ,SAAS,UAAU,YAAY;AAAA,EACpI;AACJ;AAUA,eAAsB,sBAAsB,SAAS,cAAc;AAC/D,QAAM,KAAKD,OAAM,OAAO;AACxB,QAAM,aAAa,eAAAC,QAAG,SAAS;AAC/B,QAAM,MAAM,OAAO,QAAQ,QAAQ,WAAW,QAAQ,MAAM;AAC5D,QAAM,GAAG,aAAa,aAAa,EAC9B,MAAM,EAAE,IAAI,aAAa,MAAM,CAAC,EAChC,OAAO;AAAA,IACJ,cAAc,GAAG,GAAG,IAAI;AAAA,IACxB,aAAa;AAAA,IACb;AAAA,EACJ,CAAC;AACT;AAWA,eAAsB,+BAA+B,SAAS,cAAc,OAAO;AAC/E,QAAM,KAAKD,OAAM,OAAO;AACxB,QAAM,MAAM,MAAM,GAAG,aAAa,aAAa,EAAE,MAAM,EAAE,IAAI,aAAa,MAAM,CAAC,EAAE,MAAM;AACzF,QAAM,OAAO,oBAAoB,KAAK,QAAQ;AAC9C,QAAM,SAAS,EAAE,GAAG,MAAM,GAAG,MAAM;AACnC,QAAM,GAAG,aAAa,aAAa,EAC9B,MAAM,EAAE,IAAI,aAAa,MAAM,CAAC,EAChC,OAAO;AAAA,IACJ,UAAU,aAAa,MAAM;AAAA,IAC7B,cAAc,GAAG,GAAG,IAAI;AAAA,EAC5B,CAAC;AACL,UAAQ,OAAO,OAAO,4CAA4C,aAAa,WAAW,EAAE;AAChG;AAUA,eAAsB,2BAA2B,SAAS,cAAc;AACpE,QAAM,KAAKA,OAAM,OAAO;AACxB,QAAM,GAAG,aAAa,aAAa,EAAE,MAAM,EAAE,IAAI,aAAa,MAAM,CAAC,EAAE,OAAO;AAC9E,UAAQ,OAAO,OAAO,yCAAyC,aAAa,WAAW,OAAO,aAAa,KAAK,EAAE;AACtH;AASA,eAAsB,qBAAqB,SAAS,UAAU,EAAE,WAAW,QAAQ,GAAG;AAClF,QAAM,KAAKA,OAAM,OAAO;AACxB,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO;AAC5C,QAAM,QAAQ,kBAAkB,QAAQ,SAAS,EAAE;AACnD,MAAI,IAAI,GAAG,KAAK,EAAE,MAAM,gBAAgB,KAAK,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,iBAAiB,OAAO,MAAM,GAAG,EAAE,QAAQ,gBAAgB,OAAO,MAAM,CAAC,CAAC;AAClJ,MAAI,QAAQ,cAAc,KAAK,GAAG;AAC9B,QAAI,EAAE,MAAM,EAAE,eAAe,QAAQ,aAAa,KAAK,EAAE,CAAC;AAAA,EAC9D;AACA,SAAO,MAAM;AACjB;;;AIjeA,sBAAe;AACf,uBAAiB;;;ACUjB,IAAAE,aAAe;AACf,IAAAC,eAAiB;;;ACDV,SAAS,eAAe,MAAM;AACjC,MAAI,MAAM,QAAQ,IAAI,GAAG;AACrB,WAAO;AAAA,EACX,WAAW,OAAO,SAAS,YAAY,SAAS,MAAM;AAClD,WAAO;AAAA,EACX,WAAW,OAAO,SAAS,UAAU;AAEjC,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,QAAQ,WAAW,OAAO,KAAK,QAAQ,WAAW,GAAG,GAAG;AACxD,aAAO;AAAA,IACX;AACA,WAAO;AAAA,EACX,OAAO;AACH,WAAO;AAAA,EACX;AACJ;AAKO,SAAS,cAAc,MAAM;AAChC,QAAM,WAAW,eAAe,IAAI;AAEpC,MAAI,aAAa,gBAAgB,aAAa,eAAe;AACzD,WAAO,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA,EACvC,OAAO;AAEH,WAAO,OAAO,IAAI;AAAA,EACtB;AACJ;AAKO,SAAS,gBAAgB,SAAS,UAAU;AAC/C,MAAI,aAAa,gBAAgB,aAAa,eAAe;AACzD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC7B,OAAO;AAEH,WAAO;AAAA,EACX;AACJ;;;AChDO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACtC,YAAY,SAAS;AACjB,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EAChB;AACJ;AAEO,IAAM,aAAN,cAAyB,eAAe;AAAA,EAC3C,YAAY,SAAS;AACjB,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EAChB;AACJ;AA8BO,IAAM,oBAAN,cAAgC,eAAe;AAAA,EAClD,YAAY,SAAS;AACjB,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EAChB;AACJ;;;AFnBO,IAAM,eAAN,MAAM,cAAa;AAAA,EACtB;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA,iBAAiB;AAAA,EACjB,uBAAuB;AAAA,EACvB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,eAAe;AAAA;AAAA,EAEf,gBAAgB;AAAA;AAAA,EAChB;AAAA;AAAA,EAGA,uBAAuB;AAAA,EACvB,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1B,YAAY,iBAAiB,SAAS;AAClC,QAAI;AAGJ,QAAI,mBAAmB,OAAO,oBAAoB,YAAY,YAAY,iBAAiB;AAEvF,YAAM,UAAU;AAChB,YAAM,OAAO,WAAW,CAAC;AAGzB,YAAM,OAAO;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,QACX,WAAW;AAAA,QACX,aAAa;AAAA,QACb,UAAU;AAAA,MACd;AACA,YAAM,aAAa,QAAQ,OAAO,gBAAgB,IAAI;AACtD,eAAS,EAAE,GAAG,YAAY,GAAG,MAAM,QAAQ,QAAQ,OAAO;AAAA,IAC9D,OAAO;AAEH,eAAS;AAAA,IACb;AAGA,QAAI,CAAC,OAAO,UAAU;AAClB,YAAM,IAAI,WAAW,qCAAqC;AAAA,IAC9D;AAEA,SAAK,WAAW,OAAO;AACvB,SAAK,YAAY,OAAO,aAAa;AACrC,SAAK,YAAY,OAAO,aAAa;AACrC,SAAK,YAAY,OAAO,aAAa;AACrC,SAAK,cAAc,OAAO,eAAe;AACzC,SAAK,WAAW,OAAO,YAAY;AACnC,SAAK,cAAc,OAAO,gBAAgB;AAC1C,SAAK,qBAAqB,OAAO,sBAAsB,MAAM,OAAO;AACpE,SAAK,SAAS,OAAO,UAAU;AAC/B,SAAK,uBAAuB,CAAC;AAG7B,SAAK,WAAW,KAAK,mBAAmB;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,KAAK,SAAS,SAAS;AAC1B,WAAO,IAAI,cAAa,SAAS,WAAW,CAAC,CAAC;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqB;AACjB,WAAO;AAAA,MACH,SAAS,KAAK,kBAAkB;AAAA,MAChC,OAAO,CAAC;AAAA,MACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACnC,cAAc;AAAA,MACd,UAAU;AAAA,MACV,UAAU;AAAA,IACd;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB,SAAS;AACxB,UAAM,SAAS,CAAC,YAAY,aAAa,WAAW,EAC/C,OAAO,UAAQ,CAAC,KAAK,IAAK,CAAC,EAC3B,IAAI,UAAQ,GAAG,IAAI,aAAa;AACrC,QAAI,OAAO,QAAQ;AACf,YAAM,IAAI,kBAAkB,kBAAkB,OAAO,KAAK,IAAI,CAAC,EAAE;AAAA,IACrE;AAEA,UAAM,QAAQ,CAAC,KAAK,UAAU,KAAK,SAAS;AAC5C,QAAI,KAAK,WAAW;AAChB,YAAM,KAAK,GAAG,KAAK,UAAU,MAAM,GAAG,CAAC;AAAA,IAC3C;AAGA,QAAI,KAAK,aAAa,SAAS;AAC3B,YAAM,KAAK,OAAO;AAAA,IACtB;AAEA,WAAO,aAAAC,QAAK,QAAQ,GAAG,KAAK;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,SAAS;AAC7B,SAAK,iBAAiB;AACtB,SAAK,uBAAuB,MAAM,WAAW,KAAK,mBAAmB,GAAG,OAAO;AAAA,EACnF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,iBAAiB;AACnB,QAAI,CAAC,KAAK,WAAW;AACjB,YAAM,IAAI,kBAAkB,+CAA+C;AAAA,IAC/E;AAGA,SAAK,WAAW,KAAK,mBAAmB;AAExC,UAAM,mBAAmB,MAAM,KAAK,YAAY;AAChD,UAAM,cAAc,IAAI,IAAI,gBAAgB;AAE5C,QAAI,cAAc,KAAK,IAAI;AAC3B,QAAI,iBAAiB,SAAS,GAAG;AAC7B,UAAI,QAAQ;AACZ,iBAAW,WAAW,kBAAkB;AACpC,cAAM,KAAK,IAAI,KAAK,OAAO,EAAE,QAAQ;AACrC,YAAI,OAAO,SAAS,EAAE,KAAK,KAAK,MAAO,SAAQ;AAAA,MACnD;AAEA,UAAI,eAAe,OAAO;AACtB,sBAAc,QAAQ;AAAA,MAC1B;AAAA,IACJ;AAEA,QAAI,cAAc,IAAI,KAAK,WAAW,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,IAAI;AACtE,WAAO,YAAY,IAAI,WAAW,GAAG;AACjC,qBAAe;AACf,oBAAc,IAAI,KAAK,WAAW,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,IAAI;AAAA,IACtE;AAEA,UAAM,KAAK,kBAAkB,WAAW;AAGxC,SAAK,oBAAoB;AAGzB,UAAM,WAAW,MAAM,KAAK,YAAY;AACxC,WAAO,SAAS,SAAS,KAAK,aAAa;AACvC,YAAM,kBAAkB,aAAAA,QAAK,QAAQ,KAAK,mBAAmB,GAAG,SAAS,MAAM,CAAC;AAChF,WAAK,OAAO,QAAQ,wCAAwC,eAAe,EAAE;AAC7E,YAAM,WAAAC,QAAG,SAAS,GAAG,iBAAiB,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IAC1E;AAEA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAc;AAChB,QAAI,CAAC,KAAK,WAAW;AACjB,aAAO,CAAC;AAAA,IACZ;AAEA,UAAM,WAAW,KAAK,mBAAmB;AAEzC,QAAI;AACA,YAAM,WAAW,QAAQ;AACzB,YAAM,QAAQ,MAAM,WAAAA,QAAG,SAAS,QAAQ,QAAQ;AAChD,YAAM,WAAW,MAAM,OAAO,UAAQ;AAClC,cAAM,WAAW,aAAAD,QAAK,KAAK,UAAU,IAAI;AACzC,cAAM,OAAO,WAAAC,QAAG,SAAS,QAAQ;AACjC,eAAO,KAAK,YAAY,KAAK,kBAAkB,IAAI;AAAA,MACvD,CAAC;AAED,aAAO,SAAS,KAAK;AAAA,IACzB,SAAS,OAAO;AACZ,aAAO,CAAC;AAAA,IACZ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,mBAAmB;AACrB,QAAI,CAAC,KAAK,WAAW;AACjB,YAAM,IAAI,kBAAkB,iDAAiD;AAAA,IACjF;AAEA,UAAM,WAAW,MAAM,KAAK,YAAY;AACxC,QAAI,SAAS,WAAW,GAAG;AACvB,aAAO;AAAA,IACX;AAEA,WAAO,SAAS,SAAS,SAAS,CAAC;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAU;AACZ,UAAM,YAAY,KAAK,mBAAmB;AAE1C,QAAI,CAAC,WAAAA,QAAG,WAAW,SAAS,GAAG;AAC3B,aAAO;AAAA,IACX;AAEA,QAAI,KAAK,WAAW;AAEhB,YAAM,WAAW,MAAM,KAAK,YAAY;AACxC,aAAO,SAAS,SAAS;AAAA,IAC7B,OAAO;AAEH,YAAM,QAAQ,MAAM,WAAAA,QAAG,SAAS,QAAQ,SAAS;AACjD,aAAO,MAAM;AAAA,QAAK,UACd,SAAS,mBACT,KAAK,MAAM,yBAAyB,KACpC,KAAK,SAAS,OAAO;AAAA,MACzB;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,mBAIN;AACI,UAAM,YAAY,KAAK,mBAAmB;AAE1C,QAAI,CAAC,WAAAA,QAAG,WAAW,SAAS,GAAG;AAC3B,aAAO,EAAE,WAAW,OAAO,aAAa,OAAO,UAAU,KAAK;AAAA,IAClE;AAEA,UAAM,QAAQ,MAAM,WAAAA,QAAG,SAAS,QAAQ,SAAS;AAGjD,QAAI,MAAM,SAAS,eAAe,GAAG;AACjC,YAAM,WAAW,KAAK;AAAA,QAClB,MAAM,WAAAA,QAAG,SAAS,SAAS,aAAAD,QAAK,KAAK,WAAW,eAAe,GAAG,MAAM;AAAA,MAC5E;AACA,aAAO;AAAA,QACH,WAAW;AAAA,QACX,aAAa;AAAA,QACb,UAAU,SAAS,YAAY;AAAA,MACnC;AAAA,IACJ;AAGA,UAAM,iBAAiB,MAAM,OAAO,UAAQ;AACxC,YAAM,WAAW,aAAAA,QAAK,KAAK,WAAW,IAAI;AAC1C,YAAM,OAAO,WAAAC,QAAG,SAAS,QAAQ;AACjC,aAAO,KAAK,YAAY,KAAK,kBAAkB,IAAI;AAAA,IACvD,CAAC;AAED,QAAI,eAAe,SAAS,GAAG;AAE3B,YAAM,gBAAgB,eAAe,KAAK,EAAE,IAAI;AAChD,YAAM,sBAAsB,aAAAD,QAAK,KAAK,WAAW,eAAe,eAAe;AAE/E,aAAO;AAAA,QACH,WAAW;AAAA,QACX,aAAa,WAAAC,QAAG,WAAW,mBAAmB;AAAA,QAC9C,UAAU;AAAA,MACd;AAAA,IACJ;AAGA,UAAM,YAAY,MAAM,OAAO,OAAK,EAAE,MAAM,yBAAyB,CAAC;AACtE,QAAI,UAAU,SAAS,GAAG;AACtB,aAAO;AAAA,QACH,WAAW;AAAA,QACX,aAAa;AAAA,QACb,UAAU;AAAA,MACd;AAAA,IACJ;AAEA,WAAO,EAAE,WAAW,OAAO,aAAa,OAAO,UAAU,KAAK;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,iBAAiB,SAAS;AAC5B,UAAM,SAAS,MAAM,KAAK,qBAAqB,OAAO;AACtD,WAAO,OAAO;AAAA,EAClB;AAAA,EAEA,MAAM,qBAAqB,SAAS;AAChC,UAAM,eAAe,aAAAD,QAAK,KAAK,KAAK,mBAAmB,GAAG,SAAS,eAAe;AAClF,QAAI,CAAC,WAAAC,QAAG,WAAW,YAAY,GAAG;AAC9B,aAAO,EAAE,UAAU,MAAM,YAAY,MAAM;AAAA,IAC/C;AACA,QAAI;AACA,YAAM,UAAU,MAAM,WAAAA,QAAG,SAAS,SAAS,cAAc,MAAM;AAC/D,aAAO,EAAE,UAAU,KAAK,MAAM,OAAO,GAAG,YAAY,MAAM;AAAA,IAC9D,QAAQ;AACJ,aAAO,EAAE,UAAU,MAAM,YAAY,KAAK;AAAA,IAC9C;AAAA,EACJ;AAAA,EAEA,MAAM,oBAAoB,SAAS,UAAU;AACzC,QAAI,CAAC,KAAK,eAAe,CAAC,UAAU;AAChC;AAAA,IACJ;AACA,UAAM,eAAe,aAAAD,QAAK,KAAK,KAAK,mBAAmB,GAAG,SAAS,eAAe;AAClF,QAAI;AACA,YAAM,WAAAC,QAAG,SAAS,UAAU,cAAc,KAAK,UAAU,UAAU,MAAM,CAAC,GAAG,MAAM;AAAA,IACvF,SAAS,GAAG;AACR,WAAK,OAAO,QAAQ,kDAAkD,OAAO,MAAM,EAAE,OAAO,EAAE;AAAA,IAClG;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,+BAA+B,SAAS;AAC1C,UAAM,cAAc,aAAAD,QAAK,KAAK,KAAK,mBAAmB,GAAG,OAAO;AAEhE,QAAI,CAAC,WAAAC,QAAG,WAAW,WAAW,GAAG;AAC7B,aAAO,KAAK,mBAAmB;AAAA,IACnC;AAEA,UAAM,SAAS,MAAM,WAAAA,QAAG,SAAS,QAAQ,WAAW,GAC/C,OAAO,UAAQ,SAAS,mBAAmB,CAAC,KAAK,WAAW,GAAG,CAAC,EAChE,KAAK;AAEV,UAAM,WAAW,KAAK,mBAAmB;AACzC,aAAS,UAAU;AACnB,aAAS,QAAQ,CAAC;AAElB,QAAI,eAAe;AACnB,QAAI,mBAAmB;AAEvB,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACnC,YAAM,WAAW,MAAM,CAAC;AACxB,YAAM,WAAW,aAAAD,QAAK,KAAK,aAAa,QAAQ;AAEhD,UAAI;AACA,cAAM,UAAU,MAAM,WAAAC,QAAG,SAAS,SAAS,UAAU,MAAM;AAC3D,cAAM,YAAY,aAAAD,QAAK,QAAQ,QAAQ,EAAE,YAAY;AACrD,YAAI,WAAW;AAEf,YAAI,cAAc,SAAS;AACvB,qBAAW;AAAA,QACf,WAAW,cAAc,QAAQ;AAC7B,qBAAW;AAAA,QACf;AAEA,cAAM,WAAW,gBAAgB,SAAS,QAAQ;AAClD,cAAM,eAAe,MAAM,QAAQ,QAAQ,IAAI,SAAS,SAAS;AAEjE,YAAI,qBAAqB,MAAM;AAC3B,6BAAmB,eAAe,QAAQ;AAAA,QAC9C;AAEA,cAAM,WAAW;AAAA,UACb,QAAQ,IAAI;AAAA,UACZ;AAAA,UACA;AAAA,QACJ;AAEA,iBAAS,MAAM,KAAK,QAAQ;AAC5B,wBAAgB;AAAA,MACpB,SAAS,OAAO;AACZ,aAAK,OAAO,QAAQ,sCAAsC,QAAQ,KAAM,MAAQ,OAAO,EAAE;AAAA,MAC7F;AAAA,IACJ;AAEA,aAAS,eAAe;AACxB,aAAS,WAAW;AAEpB,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,uBAAuB,SAAS;AAClC,UAAM,cAAc,aAAAA,QAAK,KAAK,KAAK,mBAAmB,GAAG,OAAO;AAEhE,QAAI,CAAC,WAAAC,QAAG,WAAW,WAAW,GAAG;AAC7B,aAAO,KAAK,mBAAmB;AAAA,IACnC;AAEA,UAAM,SAAS,MAAM,WAAAA,QAAG,SAAS,QAAQ,WAAW,GAC/C,OAAO,UAAQ,SAAS,mBAAmB,CAAC,KAAK,WAAW,GAAG,CAAC,EAChE,KAAK;AAEV,QAAI,MAAM,WAAW,GAAG;AACpB,aAAO,KAAK,mBAAmB;AAAA,IACnC;AAEA,UAAM,WAAW,KAAK,mBAAmB;AACzC,aAAS,UAAU;AACnB,aAAS,QAAQ,MAAM,IAAI,CAAC,UAAU,WAAW;AAAA,MAC7C,QAAQ,QAAQ;AAAA,MAChB,cAAc;AAAA,MACd;AAAA,IACJ,EAAE;AAGF,UAAM,YAAY,SAAS,MAAM,CAAC;AAClC,UAAM,gBAAgB,aAAAD,QAAK,KAAK,aAAa,UAAU,QAAQ;AAC/D,UAAM,eAAe,MAAM,WAAAC,QAAG,SAAS,SAAS,eAAe,MAAM;AAErE,QAAI;AACJ,QAAI;AACA,sBAAgB,KAAK,MAAM,YAAY;AAAA,IAC3C,SAAS,GAAG;AACR,sBAAgB;AAAA,IACpB;AAEA,aAAS,WAAW,eAAe,aAAa;AAGhD,QAAI,SAAS,aAAa,cAAc;AACpC,YAAM,iBAAiB,MAAM,QAAQ,aAAa,IAAI,cAAc,SAAS;AAC7E,gBAAU,eAAe;AAGzB,eAAS,IAAI,GAAG,IAAI,SAAS,MAAM,SAAS,GAAG,KAAK;AAChD,iBAAS,MAAM,CAAC,EAAE,eAAe;AAAA,MACrC;AAGA,UAAI,MAAM,SAAS,GAAG;AAClB,cAAM,WAAW,SAAS,MAAM,SAAS,MAAM,SAAS,CAAC;AACzD,cAAM,eAAe,aAAAD,QAAK,KAAK,aAAa,SAAS,QAAQ;AAC7D,cAAM,cAAc,MAAM,WAAAC,QAAG,SAAS,SAAS,cAAc,MAAM;AACnE,cAAM,eAAe,gBAAgB,aAAa,SAAS,QAAQ;AACnE,iBAAS,eAAe,MAAM,QAAQ,YAAY,IAAI,aAAa,SAAS;AAAA,MAChF;AAGA,eAAS,eAAe,SAAS,MAAM,OAAO,CAAC,KAAK,SAAS,MAAM,KAAK,cAAc,CAAC;AAAA,IAC3F,OAAO;AAEH,eAAS,MAAM,QAAQ,UAAQ;AAC3B,aAAK,eAAe;AAAA,MACxB,CAAC;AACD,eAAS,eAAe,MAAM;AAAA,IAClC;AAEA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,SAAS,eAAe,MAAM;AAC/C,QAAI,aAAa;AACjB,QAAI,KAAK,aAAa;AAClB,YAAM,SAAS,MAAM,KAAK,qBAAqB,OAAO;AACtD,UAAI,OAAO,UAAU;AACjB,eAAO,OAAO;AAAA,MAClB;AACA,mBAAa,OAAO;AAAA,IACxB;AAIA,UAAM,UAAW,gBAAgB,CAAC,KAAK,wBAAwB,CAAC,KAAK,0BAC/D,MAAM,KAAK,uBAAuB,OAAO,IACzC,MAAM,KAAK,+BAA+B,OAAO;AAEvD,QAAI,YAAY;AACZ,YAAM,KAAK,oBAAoB,SAAS,OAAO;AAAA,IACnD;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBAAoB,SAAS;AAC/B,UAAM,WAAW,MAAM,KAAK,eAAe,OAAO;AAClD,SAAK,WAAW;AAChB,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBAAoB,UAAU;AAChC,QAAI,CAAC,KAAK,aAAa;AACnB;AAAA,IACJ;AAEA,UAAM,iBAAiB,YAAY,KAAK;AACxC,QAAI;AAEJ,QAAI,KAAK,WAAW;AAEhB,UAAI,CAAC,KAAK,gBAAgB;AACtB;AAAA,MACJ;AACA,qBAAe,aAAAD,QAAK,KAAK,KAAK,mBAAmB,GAAG,KAAK,gBAAgB,eAAe;AAAA,IAC5F,OAAO;AAEH,qBAAe,aAAAA,QAAK,KAAK,KAAK,mBAAmB,GAAG,eAAe;AAAA,IACvE;AAEA,UAAM,WAAAC,QAAG,SAAS,UAAU,cAAc,KAAK,UAAU,gBAAgB,MAAM,CAAC,GAAG,MAAM;AAAA,EAC7F;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc;AACV,SAAK,qBAAqB,KAAK,qBAAqB,KAAK;AAEzD,UAAM,WAAW,KAAK,SAAS,YAAY;AAC3C,UAAM,YAAY;AAAA,MACd,QAAQ,KAAK;AAAA,MACb,cAAc;AAAA,MACd,UAAU,GAAG,KAAK,kBAAkB,SAAS,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,iBAAiB,QAAQ,CAAC;AAAA,IACjG;AAEA,SAAK,SAAS,MAAM,KAAK,SAAS;AAClC,SAAK,eAAe;AAEpB,SAAK,OAAO,QAAQ,oCAAoC,UAAU,QAAQ,iBAAiB,KAAK,iBAAiB,EAAE;AAAA,EACvH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,4BAA4B,MAAM,kBAAkB,MAAM,eAAe,OAAO;AAC5E,QAAI;AACJ,QAAI;AAIJ,UAAM,mBAAmB,eAAe,IAAI;AAC5C,QAAI,KAAK,SAAS,aAAa,kBAAkB;AAC7C,WAAK,SAAS,WAAW;AAAA,IAC7B;AAGA,QAAI,oBAAoB,QAAQ,kBAAkB,KAAK,SAAS,MAAM,QAAQ;AAC1E,YAAM,aAAa,KAAK,SAAS,MAAM,eAAe;AAEtD,UAAI,CAAC,MAAM,QAAQ,IAAI,GAAG;AACtB,sBAAc;AACd,uBAAe;AACf,eAAO,EAAE,aAAa,cAAc,UAAU,WAAW,SAAS;AAAA,MACtE,OAAO;AAEH,sBAAc,KAAK,MAAM,GAAG,KAAK,QAAQ;AACzC,uBAAe,KAAK,MAAM,KAAK,QAAQ;AACvC,aAAK,eAAe;AACpB,eAAO,EAAE,aAAa,cAAc,UAAU,WAAW,SAAS;AAAA,MACtE;AAAA,IACJ;AAIA,QAAI,wBAAwB;AAC5B,QAAI,cAAc;AACd,YAAM,oBAAoB,KAAK,SAAS,MAAM;AAC9C,WAAK,YAAY;AACjB,8BAAwB;AACxB,WAAK,OAAO,QAAQ,wFAAwF,KAAK,iBAAiB,EAAE;AAAA,IACxI,WAAW,KAAK,SAAS,MAAM,WAAW,GAAG;AAEzC,WAAK,YAAY;AAAA,IACrB;AAGA,UAAM,WAAW,KAAK,SAAS,MAAM,KAAK,SAAS,MAAM,SAAS,CAAC;AACnE,UAAM,uBAAuB,SAAS;AAGtC,QAAI,gBAAgB,0BAA0B,MAAM;AAChD,YAAM,mBAAmB,KAAK,SAAS,MAAM,qBAAqB;AAClE,UAAI,oBAAoB,iBAAiB,aAAa,SAAS,UAAU;AACrE,aAAK,OAAO,OAAO,8CAA8C,iBAAiB,QAAQ,4BAA4B,SAAS,QAAQ,EAAE;AAAA,MAC7I;AAAA,IACJ;AAIA,QAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,CAAC,cAAc;AACvC,YAAM,oBAAoB,aAAAD,QAAK,QAAQ,SAAS,QAAQ;AACxD,YAAM,oBAAoB,IAAI,iBAAiB,gBAAgB,CAAC;AAGhE,UAAI,sBAAsB,mBAAmB;AAEzC,YAAI,uBAAuB,GAAG;AAC1B,eAAK,YAAY;AAAA,QACrB,OAAO;AAEH,mBAAS,WAAW,GAAG,KAAK,kBAAkB,SAAS,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,iBAAiB,gBAAgB,CAAC;AAAA,QACnH;AAAA,MACJ;AAAA,IACJ,WAAW,CAAC,MAAM,QAAQ,IAAI,KAAK,cAAc;AAE7C,YAAM,oBAAoB,aAAAA,QAAK,QAAQ,SAAS,QAAQ;AACxD,YAAM,oBAAoB,IAAI,iBAAiB,gBAAgB,CAAC;AAChE,UAAI,sBAAsB,mBAAmB;AACzC,iBAAS,WAAW,GAAG,KAAK,kBAAkB,SAAS,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,iBAAiB,gBAAgB,CAAC;AAAA,MACnH;AAAA,IACJ;AAEA,QAAI,MAAM,QAAQ,IAAI,GAAG;AAGrB,UAAI,cAAc;AAEd,sBAAc,KAAK,MAAM,GAAG,KAAK,QAAQ;AACzC,uBAAe,KAAK,MAAM,KAAK,QAAQ;AACvC,aAAK,eAAe;AAAA,MACxB,WAAW,uBAAuB,KAAK,UAAU;AAE7C,sBAAc,CAAC,GAAI,KAAK,gBAAgB,CAAC,GAAI,GAAG,KAAK,MAAM,GAAG,KAAK,WAAW,oBAAoB,CAAC;AACnG,uBAAe,KAAK,MAAM,KAAK,WAAW,oBAAoB;AAC9D,aAAK,eAAe;AAAA,MACxB,OAAO;AAEH,aAAK,YAAY;AACjB,sBAAc,KAAK,MAAM,GAAG,KAAK,QAAQ;AACzC,uBAAe,KAAK,MAAM,KAAK,QAAQ;AACvC,aAAK,eAAe;AAAA,MACxB;AAAA,IACJ,OAAO;AAEH,oBAAc;AACd,qBAAe;AAAA,IACnB;AAIA,UAAM,WAAW,KAAK,SAAS,MAAM,KAAK,SAAS,MAAM,SAAS,CAAC,EAAE;AAErE,SAAK,OAAO;AAAA,MACR,wDAAwD,QAAQ,kBAAkB,YAAY,qBAAqB,eAAe,wBAAwB,MAAM,QAAQ,WAAW,IAAI,YAAY,SAAS,KAAK,0BAA0B,oBAAoB;AAAA,IACnQ;AAEA,WAAO,EAAE,aAAa,cAAc,SAAS;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,MAAM,YAAY,KAAK,SAAS,MAAM,SAAS,GAAG;AACpE,QAAI,CAAC,KAAK,sBAAsB;AAC5B;AAAA,IACJ;AACA,UAAM,WAAW,KAAK,SAAS,MAAM,SAAS;AAC9C,UAAM,mBAAmB,KAAK,qBAAqB,UAAU,IAAI;AACjE,SAAK,SAAS,MAAM,SAAS,IAAI;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,2BAA2B;AACvB,QAAI,CAAC,KAAK,yBAAyB;AAC/B;AAAA,IACJ;AACA,UAAM,mBAAmB,KAAK,wBAAwB,KAAK,QAAQ;AACnE,SAAK,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,aAAa,UAAU,gBAAgB;AAClD,QAAI;AAEJ,QAAI,UAAU;AAEV,YAAM,YAAY,KAAK,SAAS,MAAM,KAAK,UAAQ,KAAK,aAAa,QAAQ;AAC7E,UAAI,CAAC,WAAW;AACZ,aAAK,OAAO,OAAO,uBAAuB,QAAQ,yCAAyC;AAC3F,sBAAc,KAAK,SAAS,MAAM,KAAK,SAAS,MAAM,SAAS,CAAC;AAAA,MACpE,OAAO;AACH,sBAAc;AAAA,MAClB;AAAA,IACJ,OAAO;AAEH,oBAAc,KAAK,SAAS,MAAM,KAAK,SAAS,MAAM,SAAS,CAAC;AAAA,IACpE;AAGA,UAAM,eAAe,MAAM,QAAQ,WAAW,IAAI,YAAY,SAAS;AAGvE,gBAAY,eAAe;AAG3B,QAAI,gBAAgB;AAChB,aAAO,OAAO,aAAa,cAAc;AAAA,IAC7C;AAGA,UAAM,YAAY,KAAK,SAAS,MAAM,QAAQ,WAAW;AACzD,QAAI,cAAc,IAAI;AAClB,WAAK,sBAAsB,aAAa,SAAS;AAAA,IACrD;AAGA,SAAK,SAAS,UAAU,KAAK;AAC7B,SAAK,SAAS,cAAa,oBAAI,KAAK,GAAE,YAAY;AAClD,SAAK,SAAS,WAAW,eAAe,WAAW;AAGnD,SAAK,SAAS,eAAe,KAAK,SAAS,MAAM,OAAO,CAAC,KAAK,SAAS,OAAO,KAAK,gBAAgB,IAAI,CAAC;AAExG,SAAK,OAAO;AAAA,MACR,4CAA4C,YAAY,QAAQ,kBAAkB,YAAY,kBAAkB,KAAK,SAAS,YAAY;AAAA,IAC9I;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,UAAU,MAAM;AAC5B,UAAM,iBAAiB,cAAc,IAAI;AACzC,UAAM,MAAM,aAAAA,QAAK,QAAQ,QAAQ;AACjC,UAAM,gBAAgB,OAAO,WAAW,gBAAgB,MAAM;AAG9D,UAAM,YAAY,iBAAiB,GAAG;AACtC,QAAI,cAAc,MAAM;AACpB,UAAI,YAAY,eAAe;AAC3B,cAAM,IAAI;AAAA,UACN,oCAAoC,qBAAqB,aAAa,CAAC,WAAW,qBAAqB,SAAS,CAAC;AAAA,QACrH;AAAA,MACJ;AAEA,UAAI,YAAY,KAAK,oBAAoB;AACrC,aAAK,OAAO,OAAO,gCAAgC,qBAAqB,SAAS,CAAC,OAAO;AAAA,MAC7F;AAAA,IACJ;AAEA,QAAI;AACA,YAAM,WAAAC,QAAG,SAAS,UAAU,UAAU,gBAAgB,MAAM;AAC5D,WAAK,OAAO,QAAQ,wBAAwB,qBAAqB,aAAa,CAAC,OAAO,QAAQ,EAAE;AAAA,IACpG,SAAS,OAAO;AACZ,YAAM,IAAI,kBAAkB,wBAAwB,QAAQ,KAAM,MAAQ,OAAO,EAAE;AAAA,IACvF;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAQ,SAUZ;AACE,UAAM,EAAE,OAAO,MAAM,SAAS,oBAAoB,IAAI;AACtD,QAAI,OAAO;AACP,UAAI,KAAK,WAAW;AAEhB,YAAI,KAAK,mBAAmB,MAAM;AAC9B,cAAI,CAAC,qBAAqB;AACtB,kBAAM,KAAK,eAAe;AAC1B,iBAAK,WAAW,KAAK,mBAAmB;AACxC,iBAAK,SAAS,UAAU,KAAK;AAC7B,iBAAK,YAAY;AAAA,UACrB;AAAA,QACJ,OAAO;AAEH,cAAI,CAAC,KAAK,SAAS,MAAM,QAAQ;AAC7B,iBAAK,WAAW,MAAM,KAAK,eAAe,KAAK,cAAc;AAE7D,gBAAI,KAAK,SAAS,SAAS,KAAK,SAAS,MAAM,SAAS,GAAG;AACvD,mBAAK,oBAAoB,KAAK,IAAI,GAAG,KAAK,SAAS,MAAM,IAAI,OAAK,EAAE,UAAU,CAAC,CAAC;AAAA,YACpF,OAAO;AACH,mBAAK,oBAAoB;AAAA,YAC7B;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ,OAAO;AAEH,cAAM,WAAW,KAAK,mBAAmB,CAAC;AAG1C,YAAI,KAAK,gBAAgB,MAAM;AAE3B,gBAAM,eAAe,aAAAD,QAAK,KAAK,KAAK,mBAAmB,GAAG,eAAe;AACzE,cAAI,WAAAC,QAAG,WAAW,YAAY,GAAG;AAC7B,gBAAI;AACA,oBAAM,UAAU,MAAM,WAAAA,QAAG,SAAS,SAAS,cAAc,MAAM;AAC/D,mBAAK,WAAW,KAAK,MAAM,OAAO;AAElC,kBAAI,KAAK,SAAS,SAAS,KAAK,SAAS,MAAM,SAAS,GAAG;AACvD,qBAAK,oBAAoB,KAAK,IAAI,GAAG,KAAK,SAAS,MAAM,IAAI,OAAK,EAAE,UAAU,CAAC,CAAC;AAAA,cACpF,OAAO;AACH,qBAAK,oBAAoB;AAAA,cAC7B;AAAA,YACJ,SAAS,GAAG;AACR,mBAAK,WAAW,KAAK,mBAAmB;AACxC,mBAAK,oBAAoB;AAAA,YAC7B;AAAA,UACJ,OAAO;AAGH,iBAAK,WAAW,KAAK,mBAAmB;AACxC,iBAAK,oBAAoB;AAAA,UAC7B;AAAA,QACJ,OAAO;AAGH,eAAK,WAAW,KAAK,mBAAmB;AACxC,eAAK,oBAAoB;AAAA,QAC7B;AAAA,MACJ;AAAA,IACJ,WAAW,MAAM;AACb,UAAI,KAAK,WAAW;AAEhB,cAAM,WAAW,MAAM,KAAK,YAAY;AACxC,YAAI,SAAS,WAAW,GAAG;AACvB,gBAAM,IAAI,kBAAkB,+CAA+C;AAAA,QAC/E;AAEA,cAAM,gBAAgB,WAAW,SAAS,SAAS,SAAS,CAAC;AAC7D,YAAI,WAAW,CAAC,SAAS,SAAS,OAAO,GAAG;AACxC,gBAAM,IAAI,kBAAkB,2BAA2B,OAAO,aAAa;AAAA,QAC/E;AACA,YAAI,KAAK,SAAS,YAAY,eAAe;AACzC,eAAK,WAAW,KAAK,mBAAmB;AACxC,eAAK,gBAAgB;AACrB,eAAK,mBAAmB;AAAA,QAC5B;AACA,cAAM,KAAK,kBAAkB,aAAa;AAE1C,YAAI,CAAC,KAAK,SAAS,MAAM,QAAQ;AAC7B,eAAK,WAAW,MAAM,KAAK,eAAe,KAAK,cAAc;AAE7D,cAAI,KAAK,SAAS,SAAS,KAAK,SAAS,MAAM,SAAS,GAAG;AACvD,iBAAK,oBAAoB,KAAK,IAAI,GAAG,KAAK,SAAS,MAAM,IAAI,OAAK,EAAE,UAAU,CAAC,CAAC;AAAA,UACpF,OAAO;AACH,iBAAK,oBAAoB;AAAA,UAC7B;AAAA,QACJ;AAAA,MACJ,OAAO;AAEH,aAAK,iBAAiB;AAGtB,YAAI,KAAK,gBAAgB,QAAW;AAChC,gBAAM,SAAS,MAAM,KAAK,iBAAiB;AAC3C,eAAK,cAAc,OAAO;AAAA,QAC9B;AAEA,YAAI,KAAK,aAAa;AAElB,gBAAM,WAAW,KAAK,mBAAmB;AACzC,gBAAM,eAAe,aAAAD,QAAK,KAAK,UAAU,eAAe;AACxD,cAAI,WAAAC,QAAG,WAAW,YAAY,GAAG;AAC7B,gBAAI;AACA,oBAAM,UAAU,MAAM,WAAAA,QAAG,SAAS,SAAS,cAAc,MAAM;AAC/D,mBAAK,WAAW,KAAK,MAAM,OAAO;AAElC,kBAAI,KAAK,SAAS,SAAS,KAAK,SAAS,MAAM,SAAS,GAAG;AACvD,qBAAK,oBAAoB,KAAK,IAAI,GAAG,KAAK,SAAS,MAAM,IAAI,OAAK,EAAE,UAAU,CAAC,CAAC;AAAA,cACpF,OAAO;AACH,qBAAK,oBAAoB;AAAA,cAC7B;AAAA,YACJ,SAAS,GAAG;AACR,oBAAM,IAAI,kBAAkB,4BAA6B,EAAI,OAAO,EAAE;AAAA,YAC1E;AAAA,UACJ,OAAO;AACH,kBAAM,IAAI;AAAA,cACN,uEAAuE,YAAY,iBAAiB,QAAQ;AAAA,YAChH;AAAA,UACJ;AAAA,QACJ,OAAO;AAEH,eAAK,WAAW,MAAM,KAAK,+BAA+B,EAAE;AAE5D,cAAI,KAAK,SAAS,SAAS,KAAK,SAAS,MAAM,SAAS,GAAG;AACvD,iBAAK,oBAAoB,KAAK,IAAI,GAAG,KAAK,SAAS,MAAM,IAAI,OAAK,EAAE,UAAU,CAAC,CAAC;AAAA,UACpF,OAAO;AACH,iBAAK,oBAAoB;AAAA,UAC7B;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,MAAM,UAAU,CAAC,GAAG;AAE5B,QAAI,QAAQ,UAAU;AAClB,YAAMC,YAAW,KAAK,mBAAmB;AACzC,YAAM,WAAWA,SAAQ;AACzB,YAAM,WAAW,aAAAF,QAAK,KAAKE,WAAU,QAAQ,QAAQ;AACrD,YAAM,KAAK,UAAU,UAAU,IAAI;AACnC;AAAA,IACJ;AAGA,QAAI,QAAQ,mBAAmB,CAAC,KAAK,WAAW;AAC5C,YAAM,IAAI,kBAAkB,kDAAkD;AAAA,IAClF;AAKA,UAAM,KAAK,QAAQ,EAAE,OAAO,MAAM,qBAAqB,CAAC,EAAE,QAAQ,mBAAmB,KAAK,WAAW,CAAC;AAItG,UAAM,mBAAmB,eAAe,IAAI;AAC5C,SAAK,SAAS,WAAW;AAGzB,QAAI,QAAQ,iBAAiB;AACzB,YAAM,KAAK,eAAe;AAC1B,WAAK,WAAW,KAAK,mBAAmB;AACxC,WAAK,SAAS,UAAU,KAAK;AAE7B,WAAK,SAAS,WAAW;AACzB,WAAK,YAAY;AAAA,IACrB;AAGA,QAAI,kBAAkB;AACtB,UAAM,oBAAoB,QAAQ,kBAAkB,OAAO,KAAK,QAAQ,cAAc,EAAE,SAAS;AAEjG,QAAI,mBAAmB;AAEnB,eAAS,IAAI,GAAG,IAAI,KAAK,SAAS,MAAM,QAAQ,KAAK;AACjD,cAAM,YAAY,KAAK,SAAS,MAAM,CAAC;AAGvC,cAAM,UAAU,OAAO,KAAK,QAAQ,cAAc,EAAE,MAAM,SAAO;AAE7D,iBAAO,OAAO,aAAa,UAAU,GAAG,MAAM,QAAQ,eAAe,GAAG;AAAA,QAC5E,CAAC;AACD,YAAI,SAAS;AACT,4BAAkB;AAClB,eAAK,OAAO,QAAQ,qEAAqE,UAAU,QAAQ,eAAe,KAAK,UAAU,QAAQ,cAAc,CAAC,EAAE;AAClK;AAAA,QACJ,OAAO;AACH,eAAK,OAAO,QAAQ,uBAAuB,UAAU,QAAQ,oCAAoC,KAAK,UAAU,QAAQ,cAAc,CAAC,EAAE;AAAA,QAC7I;AAAA,MACJ;AACA,UAAI,oBAAoB,MAAM;AAC1B,aAAK,OAAO,QAAQ,+DAA+D,KAAK,UAAU,QAAQ,cAAc,CAAC,wBAAwB;AAAA,MACrJ;AAAA,IACJ,OAAO;AACH,WAAK,OAAO,QAAQ,kEAAkE;AAAA,IAC1F;AAGA,QAAI,oBAAoB,MAAM;AAC1B,YAAM,aAAa,KAAK,SAAS,MAAM,eAAe;AAEtD,WAAK,oBAAoB,WAAW;AAEpC,WAAK,eAAe;AACpB,WAAK,gBAAgB;AACrB,WAAK,mBAAmB;AAAA,IAC5B;AAGA,UAAM,eAAe,qBAAqB,oBAAoB;AAE9D,QAAI,EAAE,aAAa,cAAc,SAAS,IAAI,KAAK,4BAA4B,MAAM,iBAAiB,YAAY;AAGlH,UAAM,WAAW,KAAK,mBAAmB,KAAK,kBAAkB,MAAS;AACzE,UAAM,KAAK,UAAU,aAAAF,QAAK,KAAK,UAAU,QAAQ,GAAG,WAAW;AAC/D,SAAK,eAAe,aAAa,UAAU,QAAQ,cAAc;AAIjE,WAAO,gBAAgB,aAAa,SAAS,KAAK,oBAAoB,MAAM;AACxE,YAAM,eAAe,KAAK,4BAA4B,YAAY;AAClE,YAAM,KAAK,UAAU,aAAAA,QAAK,KAAK,UAAU,aAAa,QAAQ,GAAG,aAAa,WAAW;AACzF,WAAK,eAAe,aAAa,aAAa,aAAa,UAAU,QAAQ,cAAc;AAC3F,qBAAe,aAAa;AAAA,IAChC;AAGA,SAAK,yBAAyB;AAG9B,QAAI,KAAK,aAAa;AAClB,YAAM,KAAK,oBAAoB,KAAK,QAAQ;AAAA,IAChD;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,UAAU,CAAC,GAAG;AACrB,UAAM,EAAE,SAAS,WAAW,OAAO,UAAU,SAAS,IAAI;AAG1D,QAAI,UAAU;AACV,YAAM,WAAW,KAAK,mBAAmB,OAAO;AAChD,YAAM,WAAW,aAAAA,QAAK,KAAK,UAAU,QAAQ;AAC7C,UAAI;AACA,cAAM,UAAU,MAAM,WAAAC,QAAG,SAAS,SAAS,UAAU,MAAM;AAC3D,eAAO,KAAK,MAAM,OAAO;AAAA,MAC7B,SAAS,OAAO;AACZ,cAAM,IAAI,kBAAkB,uBAAuB,QAAQ,KAAM,MAAQ,OAAO,EAAE;AAAA,MACtF;AAAA,IACJ;AAGA,UAAM,KAAK,QAAQ,EAAE,MAAM,MAAM,QAAQ,CAAC;AAG1C,UAAM,qBACF,KAAK,SAAS,aAAa,UAAU,KAAK,SAAS,aAAa,SAAS,KAAK,SAAS,aAAa;AAExG,QAAI,oBAAoB;AAEpB,YAAM,OAAO,KAAK,SAAS,MAAM,CAAC;AAClC,YAAM,WAAW,aAAAD,QAAK,KAAK,KAAK,mBAAmB,KAAK,kBAAkB,MAAS,GAAG,KAAK,QAAQ;AACnG,UAAI;AACA,cAAM,UAAU,MAAM,WAAAC,QAAG,SAAS,SAAS,UAAU,MAAM;AAC3D,eAAO,gBAAgB,SAAS,KAAK,SAAS,QAAQ;AAAA,MAC1D,SAAS,OAAO;AACZ,cAAM,IAAI,kBAAkB,uBAAuB,KAAK,QAAQ,KAAM,MAAQ,OAAO,EAAE;AAAA,MAC3F;AAAA,IACJ;AAGA,QAAI;AAEJ,QAAI,YAAY,KAAK,kBAAkB;AAInC,0BAAoB,YAAY,KAAK;AAAA,IACzC,WAAW,CAAC,UAAU;AAElB,0BAAoB,aAAa,SAAY,WAAW,KAAK,SAAS;AACtE,WAAK,gBAAgB;AAAA,IACzB,OAAO;AAEH,0BAAoB,YAAY,KAAK;AAAA,IACzC;AAGA,QAAI,KAAK,iBAAiB,KAAK,SAAS,cAAc;AAClD,aAAO,CAAC;AAAA,IACZ;AAEA,UAAM,SAAS,CAAC;AAChB,SAAK,uBAAuB,CAAC;AAC7B,QAAI,cAAc;AAClB,QAAI,mBAAmB;AACvB,QAAI,oBAAoB;AAGxB,QAAI,eAAe;AACnB,aAAS,IAAI,GAAG,IAAI,KAAK,SAAS,MAAM,QAAQ,KAAK;AACjD,YAAM,OAAO,KAAK,SAAS,MAAM,CAAC;AAClC,UAAI,KAAK,gBAAgB,eAAe,KAAK,cAAc;AACvD,2BAAmB;AACnB,4BAAoB;AACpB;AAAA,MACJ;AACA,sBAAgB,KAAK;AAAA,IACzB;AAIA,QAAI,oBAAoB;AACxB,aAAS,IAAI,kBAAkB,IAAI,KAAK,SAAS,MAAM,UAAU,cAAc,mBAAmB,KAAK;AACnG,YAAM,OAAO,KAAK,SAAS,MAAM,CAAC;AAClC,YAAM,WAAW,aAAAD,QAAK,KAAK,KAAK,mBAAmB,KAAK,kBAAkB,MAAS,GAAG,KAAK,QAAQ;AAEnG,UAAI;AACA,YAAI;AACJ,YAAI,KAAK,eAAe,aAAa,YAAY,MAAM,QAAQ,KAAK,cAAc,IAAI,GAAG;AACrF,qBAAW,KAAK,cAAc;AAAA,QAClC,OAAO;AACH,gBAAM,UAAU,MAAM,WAAAC,QAAG,SAAS,SAAS,UAAU,MAAM;AAC3D,qBAAW,gBAAgB,SAAS,KAAK,SAAS,QAAQ;AAC1D,eAAK,gBAAgB,EAAE,UAAU,MAAM,SAAS;AAAA,QACpD;AAEA,YAAI,aAAa;AACjB,YAAI,MAAM,kBAAkB;AACxB,uBAAa,KAAK,gBAAgB;AAAA,QACtC;AAEA,cAAM,WAAW,KAAK,IAAI,cAAc,oBAAoB,cAAc,SAAS,MAAM;AACzF,cAAM,sBAAsB,SAAS,MAAM,YAAY,QAAQ;AAE/D,iBAAS,IAAI,GAAG,IAAI,oBAAoB,QAAQ,KAAK;AACjD,iBAAO,KAAK,oBAAoB,CAAC,CAAC;AAAA,QACtC;AACA,uBAAe,oBAAoB;AAEnC,6BAAqB,KAAK;AAAA,MAC9B,SAAS,OAAO;AACZ,YAAI,OAAO,SAAS,UAAU;AAC1B,cAAI,CAAC,KAAK,qBAAsB,MAAK,uBAAuB,CAAC;AAC7D,eAAK,qBAAqB,KAAK,KAAK,QAAQ;AAC5C,+BAAqB,KAAK;AAC1B;AAAA,QACJ;AACA,cAAM,IAAI,kBAAkB,uBAAuB,KAAK,QAAQ,KAAM,MAAQ,OAAO,EAAE;AAAA,MAC3F;AAAA,IACJ;AAIA,SAAK,iBAAiB;AAKtB,QAAI,OAAO,SAAS,GAAG;AACnB,UAAI,YAAa,aAAa,UAAa,WAAW,KAAK,SAAS,cAAe;AAC/E,aAAK,mBAAmB;AAAA,MAC5B;AAAA,IACJ;AAEA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,aAAa;AACxB,SAAK,gBAAgB,cAAc;AACnC,SAAK,mBAAmB;AACxB,SAAK,gBAAgB;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB;AACd,SAAK,gBAAgB;AACrB,SAAK,mBAAmB;AACxB,SAAK,gBAAgB;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBAAgB;AAClB,UAAM,WAAW,KAAK,aAAa,KAAK,iBAClC,aAAAD,QAAK,KAAK,KAAK,mBAAmB,GAAG,KAAK,cAAc,IACxD,KAAK,mBAAmB;AAC9B,QAAI;AACA,YAAM,UAAU,MAAM,WAAAC,QAAG,SAAS,QAAQ,UAAU,EAAE,eAAe,KAAK,CAAC;AAC3E,aAAO,QACF,OAAO,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE,SAAS,mBAAmB,qBAAqB,KAAK,EAAE,IAAI,CAAC,EAC3F,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,IAC1B,SAAS,KAAK;AACV,UAAI,KAAK,SAAS,SAAU,QAAO,CAAC;AACpC,YAAM,IAAI,kBAAkB,yBAA0B,IAAM,OAAO,EAAE;AAAA,IACzE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,UAAU;AACvB,UAAM,WAAW,KAAK,aAAa,KAAK,iBAClC,aAAAD,QAAK,KAAK,KAAK,mBAAmB,GAAG,KAAK,cAAc,IACxD,KAAK,mBAAmB;AAC9B,UAAM,WAAW,aAAAA,QAAK,KAAK,UAAU,QAAQ;AAC7C,QAAI;AACA,YAAM,WAAAC,QAAG,SAAS,OAAO,QAAQ;AAAA,IACrC,SAAS,KAAK;AACV,UAAI,KAAK,SAAS,SAAU;AAC5B,YAAM,IAAI,kBAAkB,yBAAyB,QAAQ,KAAM,IAAM,OAAO,EAAE;AAAA,IACtF;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAAgB,UAAU;AAC5B,QAAI,KAAK,WAAW;AAChB,YAAM,IAAI,kBAAkB,yDAAyD;AAAA,IACzF;AACA,UAAM,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AACjC,UAAM,MAAM,KAAK,SAAS,MAAM,UAAU,CAAC,MAAM,EAAE,aAAa,QAAQ;AACxE,QAAI,QAAQ,IAAI;AACZ,YAAM,IAAI,kBAAkB,cAAc,QAAQ,wBAAwB;AAAA,IAC9E;AACA,UAAM,QAAQ,KAAK,SAAS,MAAM,GAAG;AACrC,UAAM,eAAe,MAAM,gBAAgB;AAC3C,SAAK,SAAS,MAAM,OAAO,KAAK,CAAC;AACjC,SAAK,SAAS,eAAe,KAAK,IAAI,IAAI,KAAK,SAAS,gBAAgB,KAAK,YAAY;AACzF,UAAM,WAAW,KAAK,mBAAmB;AACzC,UAAM,WAAW,aAAAD,QAAK,KAAK,UAAU,QAAQ;AAC7C,QAAI;AACA,YAAM,WAAAC,QAAG,SAAS,OAAO,QAAQ;AAAA,IACrC,SAAS,KAAK;AACV,UAAI,KAAK,SAAS,UAAU;AACxB,aAAK,OAAO,OAAO,uBAAuB,QAAQ,0BAA0B;AAAA,MAChF,OAAO;AACH,cAAM,IAAI,kBAAkB,yBAAyB,QAAQ,KAAM,IAAM,OAAO,EAAE;AAAA,MACtF;AAAA,IACJ;AACA,QAAI,KAAK,aAAa;AAClB,YAAM,KAAK,oBAAoB,KAAK,QAAQ;AAAA,IAChD;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,wBAAwB,IAAI;AACxB,SAAK,uBAAuB;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,2BAA2B,IAAI;AAC3B,SAAK,0BAA0B;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB;AAChB,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB;AACb,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc;AACV,WAAO,EAAE,GAAG,KAAK,SAAS;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,SAAS,gBAMf;AACI,UAAM,UAMX,CAAC;AAGI,QAAI,CAAC,KAAK,WAAW;AAEjB,YAAM,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AACjC,YAAM,WAAW,KAAK,YAAY;AAGlC,iBAAW,aAAa,SAAS,OAAO;AAEpC,cAAM,UAAU,OAAO,KAAK,cAAc,EAAE,MAAM,SAAO;AACrD,iBAAO,UAAU,GAAG,MAAM,eAAe,GAAG;AAAA,QAChD,CAAC;AAED,YAAI,SAAS;AAET,gBAAM,WAAW,KAAK,mBAAmB;AACzC,gBAAM,WAAW,aAAAD,QAAK,KAAK,UAAU,UAAU,QAAQ;AACvD,gBAAM,WAAW,MAAM,WAAAC,QAAG,SAAS,SAAS,UAAU,MAAM;AAC5D,gBAAM,OAAO,gBAAgB,UAAU,SAAS,YAAY,aAAa;AAEzE,kBAAQ,KAAK;AAAA,YACT;AAAA,YACA,UAAU,UAAU;AAAA,YACpB,SAAS;AAAA,YACT,UAAU;AAAA,YACV;AAAA,UACJ,CAAC;AAAA,QACL;AAAA,MACJ;AAAA,IACJ,OAAO;AAEH,YAAM,WAAW,MAAM,KAAK,YAAY;AAExC,iBAAW,WAAW,UAAU;AAE5B,cAAM,KAAK,QAAQ,EAAE,MAAM,MAAM,QAAQ,CAAC;AAC1C,cAAM,WAAW,KAAK,YAAY;AAGlC,mBAAW,aAAa,SAAS,OAAO;AAEpC,gBAAM,UAAU,OAAO,KAAK,cAAc,EAAE,MAAM,SAAO;AACrD,mBAAO,UAAU,GAAG,MAAM,eAAe,GAAG;AAAA,UAChD,CAAC;AAED,cAAI,SAAS;AAET,kBAAM,WAAW,KAAK,mBAAmB,OAAO;AAChD,kBAAM,WAAW,aAAAD,QAAK,KAAK,UAAU,UAAU,QAAQ;AACvD,kBAAM,WAAW,MAAM,WAAAC,QAAG,SAAS,SAAS,UAAU,MAAM;AAC5D,kBAAM,OAAO,gBAAgB,UAAU,SAAS,YAAY,aAAa;AAEzE,oBAAQ,KAAK;AAAA,cACT;AAAA,cACA,UAAU,UAAU;AAAA,cACpB;AAAA,cACA,UAAU;AAAA,cACV;AAAA,YACJ,CAAC;AAAA,UACL;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAEA,WAAO;AAAA,EACX;AACJ;;;ADh4CA,SAAS,aAAa,SAAS;AAC3B,QAAM,SAAS;AACf,MAAI,OAAO,iBAAkB,QAAO,OAAO;AAE3C,QAAM,WAAW,OAAO,QAAQ,MAAM,mBAAmB,KAAK;AAC9D,QAAM,YAAY,OAAO,QAAQ,MAAM,oBAAoB,KAAK;AAChE,QAAM,YAAY,OAAO,QAAQ,MAAM,gBAAgB,KAAK;AAC5D,QAAM,iBAAiB,OAAO,QAAQ,MAAM,qBAAqB,KAAK,GAAG,SAAS;AAClF,QAAM,iBAAiB,OAAO,OAAO,QAAQ,MAAM,sBAAsB,CAAC;AAC1E,QAAM,cAAc,OAAO,OAAO,QAAQ,MAAM,mBAAmB,CAAC;AAEpE,QAAM,UAAU,IAAI,aAAa;AAAA,IAC7B;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,IACb,aAAa,OAAO,SAAS,cAAc,KAAK,iBAAiB,IAAI,iBAAiB;AAAA,IACtF,UAAU,OAAO,SAAS,WAAW,KAAK,cAAc,IAAI,cAAc;AAAA,IAC1E,QAAQ,OAAO;AAAA,EACnB,CAAC;AAED,QAAM,aAAa,OAAO,QAAQ,MAAM,kBAAkB;AAC1D,QAAM,UAAU,eAAe,SAAY,OAAO,CAAC,CAAC;AACpD,MAAI,CAAC,SAAS;AACV,UAAM,gBAAgB;AAAA,MAClB,IAAI;AAAA,MACJ;AAAA,MACA,OAAO,QAAQ,QAAQ;AAAA,MACvB,aAAa;AAAA,MACb,kBAAkB;AAAA,IACtB;AACA,WAAO,mBAAmB;AAC1B,WAAO;AAAA,EACX;AAEA,QAAM,KAAK,IAAI,aAAa;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,aAAa;AAAA,IACb,aAAa,OAAO,SAAS,cAAc,KAAK,iBAAiB,IAAI,iBAAiB;AAAA,IACtF,UAAU,OAAO,SAAS,WAAW,KAAK,cAAc,IAAI,cAAc;AAAA,IAC1E,QAAQ,OAAO;AAAA,EACnB,CAAC;AACD,QAAM,QAAQ;AAAA,IACV;AAAA,IACA;AAAA,IACA,OAAO,QAAQ,QAAQ;AAAA,IACvB,aAAa;AAAA,IACb,kBAAkB;AAAA,EACtB;AACA,SAAO,mBAAmB;AAC1B,SAAO;AACX;AAUA,SAAS,gBAAgB,QAAQ;AAC7B,QAAM,KAAK,OAAO,YAAY;AAC9B,QAAM,KAAK,OAAO,aAAa;AAC/B,SAAO,GAAG,EAAE,KAAK,EAAE,KAAK,OAAO,SAAS;AAC5C;AAUO,SAAS,sCAAsC,QAAQ,UAAU;AACpE,QAAM,MAAM,CAAC,MAAM;AACf,UAAM,IAAI,OAAO,CAAC,EAAE,KAAK,EAAE,QAAQ,qBAAqB,GAAG,EAAE,QAAQ,YAAY,EAAE;AACnF,WAAO,EAAE,SAAS,IAAI;AAAA,EAC1B;AACA,SAAO,GAAG,IAAI,MAAM,CAAC,IAAI,IAAI,QAAQ,CAAC;AAC1C;AAkBO,SAAS,oBAAoB,SAAS,EAAE,SAAS,QAAQ,MAAM,OAAO,IAAI,CAAC,GAAG;AACjF,QAAM,QAAQ,WAAW,OAAO,OAAO,EAAE,KAAK,IAAI,OAAO,OAAO,EAAE,KAAK,IAAI;AAC3E,QAAM,OAAO,UAAU,OAAO,MAAM,EAAE,KAAK,IAAI,OAAO,MAAM,EAAE,KAAK,IAAI;AACvE,QAAM,KAAK,QAAQ,OAAO,IAAI,EAAE,KAAK,IAAI,OAAO,IAAI,EAAE,KAAK,IAAI;AAC/D,QAAM,KAAK,UAAU,QAAQ,OAAO,MAAM,EAAE,KAAK,IAAI,OAAO,MAAM,EAAE,KAAK,IAAI;AAC7E,UAAQ,MAAM,QAAQ,OAAO,IAAI,UAAU,CAAC,GAAG,OAAO,CAAC,MAAM;AACzD,QAAI,CAAC,KAAK,OAAO,EAAE,OAAO,SAAU,QAAO;AAC3C,UAAM,KAAK,OAAO,EAAE,EAAE;AACtB,QAAI,SAAS,EAAE,KAAK,OAAQ,QAAO;AACnC,QAAI,QAAQ,KAAK,KAAM,QAAO;AAC9B,QAAI,MAAM,KAAK,GAAI,QAAO;AAC1B,QAAI,MAAM,OAAO,EAAE,UAAU,EAAE,MAAM,GAAI,QAAO;AAChD,WAAO;AAAA,EACX,CAAC;AACL;AAEA,SAAS,kBAAkB,SAAS;AAChC,MAAI,WAAW;AACf,aAAW,KAAK,WAAW,CAAC,GAAG;AAC3B,UAAM,KAAK,OAAO,GAAG,OAAO,WAAW,OAAO,EAAE,EAAE,IAAI;AACtD,QAAI,OAAO,CAAC,YAAY,KAAK,UAAW,YAAW;AAAA,EACvD;AACA,SAAO;AACX;AAEA,eAAsB,wBAAwB,SAAS,SAAS;AAC5D,QAAM,SAAS;AACf,QAAM,WAAW,OAAO,QAAQ,MAAM,mBAAmB,KAAK;AAC9D,QAAM,YAAY,OAAO,QAAQ,MAAM,oBAAoB,KAAK;AAChE,QAAM,YAAY,sCAAsC,QAAQ,QAAQ,QAAQ,QAAQ;AACxF,QAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,KAAQ,OAAO,QAAQ,IAAI,IAAI,IAAI,OAAO,QAAQ,IAAI,IAAI,GAAG,CAAC;AAChG,QAAM,SAAS,QAAQ,UAAU,OAAO,QAAQ,MAAM,EAAE,KAAK,IAAI,OAAO,QAAQ,MAAM,EAAE,KAAK,IAAI;AACjG,QAAM,OAAO,QAAQ,QAAQ,OAAO,QAAQ,IAAI,EAAE,KAAK,IAAI,OAAO,QAAQ,IAAI,EAAE,KAAK,IAAI;AACzF,QAAM,cAAc,CAAC,EAAE,UAAU;AAEjC,QAAM,KAAK,IAAI,aAAa;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,aAAa;AAAA,IACb,aAAa;AAAA,IACb,UAAU;AAAA,IACV,QAAQ,OAAO;AAAA,EACnB,CAAC;AAED,QAAM,WAAW,MAAM,GAAG,YAAY;AACtC,MAAI,SAAS,WAAW,GAAG;AACvB,WAAO,EAAE,SAAS,CAAC,GAAG,UAAU,KAAK;AAAA,EACzC;AAEA,QAAM,iBAAiB,cAAc,CAAC,GAAG,QAAQ,EAAE,QAAQ,IAAI,CAAC,SAAS,SAAS,SAAS,CAAC,CAAC;AAC7F,QAAM,YAAY,CAAC;AACnB,aAAW,WAAW,gBAAgB;AAClC,UAAM,EAAE,SAAS,IAAI,IAAI,MAAM,kBAAkB,IAAI,SAAS,OAAO,QAAQ,SAAS;AACtF,gBAAY,WAAW,GAAG;AAC1B,QAAI,CAAC,YAAa;AAClB,QAAI,QAAQ;AACR,UAAI,QAAQ;AACZ,iBAAW,KAAK,KAAK;AACjB,cAAM,KAAK,OAAO,GAAG,OAAO,WAAW,EAAE,KAAK;AAC9C,YAAI,OAAO,CAAC,SAAS,KAAK,OAAQ,SAAQ;AAAA,MAC9C;AACA,UAAI,SAAS,SAAS,OAAQ;AAAA,IAClC;AAAA,EACJ;AAEA,QAAM,WAAW,oBAAoB,WAAW;AAAA,IAC5C,SAAS,QAAQ;AAAA,IACjB;AAAA,IACA;AAAA,IACA,QAAQ,QAAQ;AAAA,EACpB,CAAC;AACD,WAAS,KAAK,CAAC,GAAG,MAAM,OAAO,GAAG,MAAM,EAAE,EAAE,cAAc,OAAO,GAAG,MAAM,EAAE,CAAC,CAAC;AAG9E,QAAM,WAAW,kBAAkB,QAAQ;AAE3C,QAAM,cAAc,CAAC,EAAE,QAAQ,WAAW,OAAO,QAAQ,OAAO,EAAE,KAAK;AAEvE,QAAM,YAAY,eAAe,cAAc,MAAS;AACxD,QAAM,SAAS,SAAS,SAAS,YAAY,SAAS,MAAM,CAAC,SAAS,IAAI;AAE1E,SAAO,EAAE,SAAS,QAAQ,SAAS;AACvC;AAUO,SAAS,sBAAsB,SAAS,QAAQ;AACnD,QAAM,SAAS;AACf,QAAM,WAAW,OAAO,aAAa,OAAO,QAAQ,MAAM,mBAAmB,KAAK;AAClF,QAAM,YAAY,OAAO,cAAc,OAAO,QAAQ,MAAM,oBAAoB,KAAK;AACrF,QAAM,WAAW,OAAO,UAAU,MAAM,GAAG,EAAE,OAAO,OAAO;AAC3D,SAAO,iBAAAE,QAAK,QAAQ,UAAU,WAAW,GAAG,QAAQ;AACxD;AAWA,SAAS,sBAAsB,SAAS,QAAQ;AAC5C,QAAM,SAAS;AACf,QAAM,aAAa,OAAO,QAAQ,MAAM,kBAAkB;AAC1D,QAAM,UAAU,eAAe,SAAY,OAAO,CAAC,CAAC;AACpD,MAAI,CAAC,QAAS,QAAO;AAErB,MAAI,CAAC,OAAO,wBAAyB,QAAO,0BAA0B,oBAAI,IAAI;AAC9E,QAAM,MAAM,OAAO;AACnB,QAAM,MAAM,gBAAgB,MAAM;AAClC,MAAI,IAAI,IAAI,GAAG,EAAG,QAAO,IAAI,IAAI,GAAG;AAEpC,QAAM,WAAW,OAAO,aAAa,OAAO,QAAQ,MAAM,mBAAmB,KAAK;AAClF,QAAM,YAAY,OAAO,cAAc,OAAO,QAAQ,MAAM,oBAAoB,KAAK;AACrF,QAAM,iBAAiB,OAAO,OAAO,QAAQ,MAAM,sBAAsB,CAAC;AAC1E,QAAM,cAAc,OAAO,OAAO,QAAQ,MAAM,mBAAmB,CAAC;AAEpE,QAAM,KAAK,IAAI,aAAa;AAAA,IACxB;AAAA,IACA;AAAA,IACA,WAAW,OAAO;AAAA,IAClB,WAAW;AAAA,IACX,aAAa;AAAA,IACb,aAAa,OAAO,SAAS,cAAc,KAAK,iBAAiB,IAAI,iBAAiB;AAAA,IACtF,UAAU,OAAO,SAAS,WAAW,KAAK,cAAc,IAAI,cAAc;AAAA,IAC1E,QAAQ,OAAO;AAAA,EACnB,CAAC;AACD,QAAM,QAAQ;AAAA,IACV;AAAA,IACA,SAAS;AAAA,IACT,OAAO,QAAQ,QAAQ;AAAA,IACvB,aAAa;AAAA,IACb,kBAAkB;AAAA,EACtB;AACA,MAAI,IAAI,KAAK,KAAK;AAClB,SAAO;AACX;AAWA,SAAS,eAAe,SAAS;AAC7B,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,OAAO,YAAY,UAAU;AAC7B,UAAM,QAAQ,OAAO,QAAQ,UAAU,WAAW,QAAQ,MAAM,YAAY,IAAI;AAChF,QAAI,UAAU,WAAW,UAAU,QAAS,QAAO;AACnD,QAAI,OAAO,QAAQ,YAAY,YAAY,aAAa,KAAK,QAAQ,OAAO,EAAG,QAAO;AACtF,WAAO;AAAA,EACX;AACA,MAAI,OAAO,YAAY,UAAU;AAC7B,WAAO,aAAa,KAAK,OAAO;AAAA,EACpC;AACA,SAAO;AACX;AAUA,SAAS,eAAe,MAAM,SAAS;AACnC,QAAM,SAAS,KAAK,UAAU,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS,CAAC;AAC/E,SAAO;AAAA,IACH,KAAI,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC3B,MAAM,KAAK,QAAQ;AAAA,IACnB,QAAQ,KAAK;AAAA,IACb,UAAU,KAAK;AAAA,IACf,QAAQ,KAAK;AAAA,IACb,QAAQ,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS;AAAA,IAC5D,UAAU,OAAO,OAAO,aAAa,WAAW,OAAO,WAAW;AAAA,IAClE;AAAA,EACJ;AACJ;AAiBO,SAAS,iBAAiB,SAAS,MAAM,SAAS,QAAQ;AAC7D,MAAI,QAAQ;AACR,UAAMC,SAAQ,sBAAsB,SAAS,MAAM;AACnD,QAAI,CAACA,QAAO,GAAI;AAChB,UAAMC,UAAS,eAAe,MAAM,OAAO;AAC3C,IAAAD,OAAM,QAAQA,OAAM,MACf,KAAK,YAAY;AACd,YAAMA,OAAM,GAAG,MAAM,CAACC,OAAM,GAAG,EAAE,iBAAiB,CAACD,OAAM,YAAY,CAAC;AACtE,MAAAA,OAAM,cAAc;AAAA,IACxB,CAAC,EACA,MAAM,CAAC,UAAU;AACd,cAAQ,OAAO,OAAO,uDAAuD,KAAK;AAAA,IACtF,CAAC;AACL;AAAA,EACJ;AAEA,QAAM,QAAQ,aAAa,OAAO;AAClC,MAAI,CAAC,MAAM,MAAM,CAAC,MAAM,QAAS;AAEjC,QAAM,SAAS,eAAe,MAAM,OAAO;AAC3C,QAAM,QAAQ,MAAM,MACf,KAAK,YAAY;AACd,QAAI,MAAM,IAAI;AACV,YAAM,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,EAAE,iBAAiB,CAAC,MAAM,YAAY,CAAC;AACtE,YAAM,cAAc;AAAA,IACxB;AACA,QAAI,MAAM,WAAW,eAAe,OAAO,GAAG;AAC1C,YAAM,MAAM,QAAQ,MAAM,CAAC,MAAM,GAAG,EAAE,iBAAiB,CAAC,MAAM,iBAAiB,CAAC;AAChF,YAAM,mBAAmB;AAAA,IAC7B;AAAA,EACJ,CAAC,EACA,MAAM,CAAC,UAAU;AACd,YAAQ,OAAO,OAAO,4CAA4C,KAAK;AAAA,EAC3E,CAAC;AACT;AASA,eAAsB,iBAAiB,SAAS;AAC5C,QAAM,SAAS;AACf,QAAM,WAAW,CAAC;AAClB,MAAI,OAAO,kBAAkB,MAAO,UAAS,KAAK,OAAO,iBAAiB,KAAK;AAC/E,QAAM,MAAM,OAAO;AACnB,MAAI,KAAK;AACL,eAAW,KAAK,IAAI,OAAO,GAAG;AAC1B,UAAI,EAAE,MAAO,UAAS,KAAK,EAAE,KAAK;AAAA,IACtC;AAAA,EACJ;AACA,QAAM,QAAQ,IAAI,QAAQ;AAC9B;AAEO,SAAS,cAAc,SAAS;AACnC,QAAM,SAAS,WAAW,CAAC;AAC3B,QAAM,WAAW,OAAO,QAAQ,MAAM,mBAAmB,KAAK;AAC9D,QAAM,YAAY,OAAO,QAAQ,MAAM,oBAAoB,KAAK;AAChE,SAAO,iBAAAD,QAAK,QAAQ,UAAU,SAAS;AAC3C;AAOO,SAAS,YAAY,QAAQ,OAAO;AACvC,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,IAAK,QAAO,KAAK,MAAM,CAAC,CAAC;AAC3D,SAAO;AACX;AAOO,SAAS,gBAAgB,UAAU,QAAQ;AAC9C,QAAM,MAAM,OAAO,MAAM;AACzB,QAAM,OAAO,CAAC;AACd,QAAM,iBAAiB,CAAC;AACxB,MAAI,UAAU;AACd,MAAI,eAAe;AACnB,aAAW,EAAE,SAAS,SAAS,cAAc,KAAK,YAAY,CAAC,GAAG;AAC9D,UAAM,MAAM,MAAM,QAAQ,OAAO,IAAI,UAAU,CAAC;AAChD,UAAM,OAAO,IAAI,OAAO,CAAC,MAAM,OAAO,GAAG,OAAO,YAAY,EAAE,MAAM,GAAG;AACvE,eAAW,IAAI,SAAS,KAAK;AAC7B,gBAAY,MAAM,IAAI;AACtB,QAAI,KAAK,WAAW,EAAG,gBAAe,KAAK,OAAO;AAAA,aACzC,KAAK,SAAS,IAAI,UAAU,OAAO,aAAa,IAAI,EAAG,gBAAe;AAAA,EACnF;AACA,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,WAAW,KAAK,WAAW,MAAM,UAAU,UAAU,KAAK;AAAA,EAC9D;AACJ;AAEA,eAAe,qBAAqB,MAAM;AACtC,QAAM,SAAS,CAAC;AAChB,QAAM,OAAO,OAAO,KAAK,WAAW;AAChC,QAAI;AACJ,QAAI;AACA,gBAAU,MAAM,gBAAAG,QAAG,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IAC3D,QAAQ;AACJ;AAAA,IACJ;AACA,UAAM,cAAc,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,KAAK,kBAAkB,EAAE,IAAI,CAAC;AACtF,QAAI,YAAY,UAAU,QAAQ;AAC9B,aAAO,KAAK,MAAM;AAClB;AAAA,IACJ;AACA,eAAW,KAAK,SAAS;AACrB,UAAI,CAAC,EAAE,YAAY,KAAK,kBAAkB,EAAE,IAAI,EAAG;AACnD,YAAM,OAAO,SAAS,GAAG,MAAM,IAAI,EAAE,IAAI,KAAK,EAAE;AAChD,YAAM,KAAK,iBAAAH,QAAK,KAAK,KAAK,EAAE,IAAI,GAAG,IAAI;AAAA,IAC3C;AAAA,EACJ;AACA,QAAM,KAAK,MAAM,EAAE;AACnB,SAAO;AACX;AAEA,eAAe,iBAAiB,UAAU,SAAS;AAC/C,QAAM,gBAAAG,QAAG,GAAG,iBAAAH,QAAK,KAAK,UAAU,OAAO,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC9E;AAGA,IAAM,8BAA8B;AAEpC,SAAS,qBAAqB,SAAS;AACnC,QAAM,IAAI,OAAO,WAAW,EAAE,EAAE,MAAM,+BAA+B;AACrE,QAAM,OAAO,IAAI,CAAC,GAAG,KAAK,KAAK;AAC/B,MAAI,CAAC,QAAQ,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,IAAI,EAAG,QAAO;AACtF,SAAO;AACX;AAMA,eAAe,uBAAuB,IAAI,SAAS,SAAS;AACxD,QAAM,OAAO,GAAG,mBAAmB,OAAO;AAC1C,QAAM,WAAW,qBAAqB,OAAO;AAC7C,QAAM,SAAS,WAAW,iBAAAA,QAAK,KAAK,MAAM,QAAQ,IAAI;AACtD,MAAI;AACA,UAAM,KAAK,MAAM,gBAAAG,QAAG,KAAK,MAAM;AAC/B,QAAI,KAAK,IAAI,IAAI,OAAO,GAAG,OAAO,IAAI,4BAA6B,QAAO;AAAA,EAC9E,QAAQ;AACJ,WAAO;AAAA,EACX;AACA,MAAI,UAAU;AACV,UAAM,gBAAAA,QAAG,GAAG,QAAQ,EAAE,OAAO,KAAK,CAAC;AACnC,QAAI,WAAW,CAAC;AAChB,QAAI;AACA,kBAAY,MAAM,gBAAAA,QAAG,QAAQ,IAAI,GAAG,OAAO,CAAC,MAAM,MAAM,mBAAmB,CAAC,EAAE,WAAW,GAAG,CAAC;AAAA,IACjG,QAAQ;AACJ,iBAAW,CAAC;AAAA,IAChB;AACA,QAAI,SAAS,WAAW,GAAG;AACvB,YAAM,gBAAAA,QAAG,GAAG,MAAM,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAClD,aAAO,GAAG,OAAO,IAAI,QAAQ;AAAA,IACjC;AACA,WAAO;AAAA,EACX;AACA,QAAM,gBAAAA,QAAG,GAAG,MAAM,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAClD,SAAO;AACX;AAEA,eAAe,kBAAkB,IAAI,SAAS,QAAQ,WAAW;AAC7D,MAAI;AACA,OAAG,uBAAuB,CAAC;AAC3B,UAAM,MAAM,MAAM,GAAG,KAAK,EAAE,QAAQ,CAAC;AACrC,UAAM,gBAAgB,MAAM,QAAQ,GAAG,oBAAoB,IAAI,GAAG,qBAAqB,SAAS;AAChG,WAAO,EAAE,SAAS,SAAS,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,GAAG,cAAc;AAAA,EAC5E,SAAS,KAAK;AACV,UAAM,MAAM,KAAK,WAAW,OAAO,GAAG;AACtC,QAAI,UAAU;AACd,QAAI;AACA,gBAAU,MAAM,uBAAuB,IAAI,SAAS,GAAG;AAAA,IAC3D,QAAQ;AAAA,IAER;AACA,YAAQ;AAAA,MACJ,gBAAgB,UAAU,YAAY,UAAU,uBAAuB,SAAS,IAAI,OAAO,KAAK,GAAG;AAAA,IACvG;AACA,WAAO,EAAE,SAAS,SAAS,CAAC,GAAG,eAAe,EAAE;AAAA,EACpD;AACJ;AAEA,eAAe,mBAAmB,SAAS,WAAW,QAAQ;AAC1D,QAAM,SAAS;AACf,QAAM,WAAW,OAAO,QAAQ,MAAM,mBAAmB,KAAK;AAC9D,QAAM,YAAY,OAAO,QAAQ,MAAM,oBAAoB,KAAK;AAChE,QAAM,KAAK,IAAI,aAAa;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,aAAa;AAAA,IACb,aAAa;AAAA,IACb,UAAU;AAAA,IACV,QAAQ,OAAO;AAAA,EACnB,CAAC;AACD,QAAM,WAAW,MAAM,GAAG,YAAY;AACtC,MAAI,SAAS,WAAW,EAAG,QAAO,EAAE,OAAO,WAAW,SAAS,GAAG,iBAAiB,EAAE;AAErF,QAAM,SAAS,CAAC;AAChB,aAAW,WAAW,UAAU;AAC5B,WAAO,KAAK,MAAM,kBAAkB,IAAI,SAAS,OAAO,QAAQ,SAAS,CAAC;AAAA,EAC9E;AACA,QAAM,OAAO,gBAAgB,QAAQ,MAAM;AAC3C,QAAM,WAAW,sBAAsB,SAAS,EAAE,WAAW,UAAU,UAAU,CAAC;AAElF,MAAI,KAAK,WAAW;AAChB,eAAW,WAAW,SAAU,OAAM,iBAAiB,UAAU,OAAO;AACxE,WAAO,EAAE,OAAO,WAAW,SAAS,KAAK,SAAS,iBAAiB,SAAS,OAAO;AAAA,EACvF;AAEA,MAAI,KAAK,SAAS;AACd,UAAM,GAAG,MAAM,KAAK,MAAM,EAAE,iBAAiB,KAAK,CAAC;AACnD,UAAM,OAAO,GAAG;AAChB,eAAW,WAAW,MAAM,GAAG,YAAY,GAAG;AAC1C,UAAI,YAAY,KAAM,OAAM,iBAAiB,UAAU,OAAO;AAAA,IAClE;AACA,WAAO,EAAE,OAAO,WAAW,SAAS,KAAK,SAAS,iBAAiB,SAAS,QAAQ,WAAW,KAAK;AAAA,EACxG;AAEA,aAAW,WAAW,KAAK,eAAgB,OAAM,iBAAiB,UAAU,OAAO;AACnF,SAAO,EAAE,OAAO,WAAW,SAAS,KAAK,SAAS,iBAAiB,KAAK,eAAe,OAAO;AAClG;AAEA,SAAS,uBAAuB,SAAS,WAAW;AAChD,QAAM,SAAS;AACf,SAAO,yBAAyB,OAAO,gBAAgB,EAAE,UAAU,CAAC,CAAC;AACrE,QAAM,eAAe,OAAO,QAAQ,MAAM,gBAAgB,KAAK;AAC/D,MAAI,cAAc,aAAc,QAAO,mBAAmB;AAC9D;AAEA,SAAS,kBAAkB,SAAS,WAAW,MAAM;AACjD,QAAM,QAAQ,sBAAsB,SAAS,EAAE,UAAU,CAAC;AAC1D,MAAI,CAAC,MAAO,QAAO,KAAK;AACxB,QAAM,OAAO,MAAM,MAAM,KAAK,MAAM,IAAI;AACxC,QAAM,QAAQ,KAAK,MAAM,MAAM;AAAA,EAAC,CAAC;AACjC,SAAO;AACX;AAUA,eAAsB,sBAAsB,SAAS,QAAQ,OAAO,CAAC,GAAG;AACpE,QAAM,SAAS,OAAO,KAAK,WAAW,aAAa,KAAK,SAAS,MAAM;AACvE,QAAM,OAAO,cAAc,OAAO;AAClC,QAAM,SAAS,MAAM,qBAAqB,IAAI;AAC9C,QAAM,UAAU,CAAC;AACjB,MAAI,UAAU;AACd,aAAW,aAAa,QAAQ;AAC5B,QAAI,OAAO,EAAG;AACd,QAAI;AACA,YAAM,MAAM,MAAM;AAAA,QAAkB;AAAA,QAAS;AAAA,QAAW,MACpD,mBAAmB,SAAS,WAAW,MAAM;AAAA,MACjD;AACA,6BAAuB,SAAS,SAAS;AACzC,cAAQ,KAAK,GAAG;AAChB,iBAAW,OAAO,KAAK,OAAO,KAAK;AAAA,IACvC,SAAS,KAAK;AACV,eAAS,QAAQ;AAAA,QACb,iCAAiC,SAAS,YAAY,KAAK,WAAW,GAAG;AAAA,MAC7E;AACA,cAAQ,KAAK,EAAE,OAAO,WAAW,SAAS,GAAG,OAAO,KAAK,WAAW,OAAO,GAAG,EAAE,CAAC;AAAA,IACrF;AAAA,EACJ;AACA,SAAO,EAAE,QAAQ,QAAQ,QAAQ,SAAS,QAAQ;AACtD;;;AI/jBO,IAAM,eAAN,MAAM,cAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQtB,OAAO,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA,EAM9B,YAAY,SAAS,MAAM;AACvB,SAAK,UAAU;AACf,SAAK,OAAO;AAEZ,SAAK,iBAAiB;AAEtB,SAAK,kBAAkB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB;AACZ,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,cAAc;AACtB,SAAK,iBAAiB;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,aAAa,cAAc;AACvB,SAAK,kBAAkB;AAAA,EAC3B;AAAA;AAAA,EAGA,kBAAkB;AACd,WAAO,KAAK,mBAAmB;AAAA,EACnC;AAAA;AAAA,EAGA,mBAAmB;AACf,WAAO,KAAK,oBAAoB;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,IAAI,iBAAiB;AACvB,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,aAAa,cAAc,SAAS,YAAY,CAAC,GAAG;AAChD,UAAM,OAAO,cAAa,mBAAmB,SAAS,SAAS;AAC/D,UAAM,SAAS,MAAM,KAAK,oBAAoB,SAAS,SAAS;AAChE,WAAO,EAAE,GAAG,MAAM,OAAO;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,aAAa,oBAAoB,SAAS,YAAY,CAAC,GAAG;AACtD,WAAO,cAAa,mBAAmB,SAAS,SAAS;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,mBAAmB,SAAS,YAAY,CAAC,GAAG;AAC/C,UAAM,OAAO;AAAA,MACT,WAAW;AAAA,MACX,UAAU;AAAA,MACV,cAAc;AAAA,MACd,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,UAAU;AAAA,IACd;AACA,UAAM,MAAM,QAAQ,OAAO,gBAAgB,iBAAiB,IAAI;AAEhE,UAAM,OAAO,aAAa,UAAU,IAAI,KAAK,aAAa,QAAQ,OAAO,IAAI,QAAQ,QAAQ,CAAC;AAC9F,QAAI,CAAC,MAAM;AACP,YAAM,IAAI,WAAW,yDAAyD;AAAA,IAClF;AAEA,QAAI;AACJ,UAAM,cAAc,UAAU,kBAAkB,IAAI;AACpD,QAAI,gBAAgB,UAAa,gBAAgB,QAAQ,OAAO,WAAW,EAAE,KAAK,MAAM,IAAI;AACxF,YAAM,IAAI,OAAO,WAAW;AAC5B,UAAI,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,GAAG;AACtD,cAAM,IAAI,WAAW,sDAAsD;AAAA,MAC/E;AACA,uBAAiB;AAAA,IACrB,OAAO;AACH,uBAAiB;AAAA,IACrB;AAEA,UAAM,cAAc,UAAU,YAAY,IAAI,YAAY;AAC1D,UAAM,WAAW,OAAO,WAAW;AACnC,QAAI,CAAC,OAAO,SAAS,QAAQ,GAAG;AAC5B,YAAM,IAAI,WAAW,oCAAoC,KAAK,UAAU,WAAW,CAAC,GAAG;AAAA,IAC3F;AAEA,WAAO;AAAA,MACH;AAAA,MACA,WAAW,UAAU,aAAa,aAAa,IAAI,SAAS,KAAK;AAAA,MACjE;AAAA,MACA,cAAc,aAAa,UAAU,YAAY,KAAK,aAAa,IAAI,YAAY,KAAK;AAAA,MACxF,aAAa,aAAa,UAAU,WAAW,KAAK,aAAa,IAAI,WAAW,KAAK;AAAA,MACrF;AAAA,MACA,YAAY,aAAa,UAAU,UAAU,KAAK,aAAa,IAAI,UAAU,KAAK;AAAA,MAClF,MAAM,aAAa,UAAU,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK;AAAA,MAChE,UAAU,aAAa,UAAU,QAAQ,KAAK,aAAa,IAAI,QAAQ,KAAK;AAAA,MAC5E,WAAW,UAAU,aAAa;AAAA,IACtC;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,mBAAmB,SAAS,YAAY,CAAC,GAAG;AAC/C,UAAM,MAAM,QAAQ,OAAO,gBAAgB,eAAe,EAAE,YAAY,SAAS,CAAC;AAClF,UAAM,WAAW,gBAAgB,IAAI,UAAU;AAC/C,UAAM,eAAe,iBAAiB,SAAS;AAC/C,QAAI,CAAC,YAAY,CAAC,aAAc,QAAO;AACvC,WAAO,EAAE,GAAI,YAAY,CAAC,GAAI,GAAI,gBAAgB,CAAC,EAAG;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,OAAO,kBAAkB,SAAS,YAAY,MAAM,YAAY,CAAC,GAAG;AAChE,UAAM,WAAW,EAAE,GAAG,MAAM,YAAY,SAAS;AACjD,UAAM,SAAS,QAAQ,OAAO,gBAAgB,YAAY,QAAQ;AAClE,UAAM,WAAW,gBAAgB,OAAO,UAAU,KAAK,CAAC;AACxD,UAAM,UAAU,CAAC;AACjB,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,GAAG;AACzC,UAAI,MAAM,aAAc;AACxB,UAAI,MAAM,UAAa,MAAM,KAAM,SAAQ,CAAC,IAAI;AAAA,IACpD;AACA,UAAM,eAAe,iBAAiB,SAAS,KAAK,CAAC;AACrD,WAAO,EAAE,GAAG,SAAS,GAAG,UAAU,GAAG,aAAa;AAAA,EACtD;AACJ;AAGA,SAAS,aAAa,GAAG;AACrB,MAAI,MAAM,UAAa,MAAM,KAAM,QAAO;AAC1C,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,QAAM,IAAI,EAAE,KAAK;AACjB,SAAO,EAAE,SAAS,IAAI;AAC1B;AASA,SAAS,gBAAgB,KAAK;AAC1B,MAAI,OAAO,KAAM,QAAO;AACxB,QAAM,IAAI,OAAO,GAAG,EAAE,KAAK;AAC3B,MAAI,CAAC,EAAG,QAAO;AACf,MAAI;AACJ,MAAI;AACA,aAAS,KAAK,MAAM,CAAC;AAAA,EACzB,SAAS,GAAG;AACR,UAAM,IAAI,WAAW,iCAAiC,GAAG,WAAW,OAAO,CAAC,CAAC,EAAE;AAAA,EACnF;AACA,MAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AACxE,UAAM,IAAI,WAAW,oCAAoC;AAAA,EAC7D;AACA,SAAO;AACX;AAGA,SAAS,iBAAiB,WAAW;AACjC,QAAM,IAAI,WAAW;AACrB,MAAI,KAAK,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,CAAC,EAAG,QAAO;AAC5D,SAAO;AACX;;;ACjSO,IAAM,WAAN,cAAuB,aAAa;AAAA;AAAA,EAEvC,OAAO,uBAAuB;AAAA;AAAA,EAG9B,aAAa,sBAAsB;AAC/B,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM;AACR,SAAK,QAAQ,OAAO,OAAO,oBAAoB,KAAK,KAAK,EAAE,GAAG;AAC9D,WAAO,EAAE,SAAS,MAAM,SAAS,OAAO;AAAA,EAC5C;AACJ;;;ACXO,IAAM,oBAAN,cAAgC,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhD,aAAa,oBAAoB,SAAS,YAAY,CAAC,GAAG;AACtD,UAAM,SAAS,aAAa,kBAAkB,SAAS,uBAAuB;AAAA,MAC1E,OAAO;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,IACV,GAAG,SAAS;AACZ,UAAM,QAAQ,OAAO,OAAO,KAAK;AACjC,UAAM,QAAQ,OAAO,OAAO,KAAK;AACjC,QAAI,CAAC,OAAO,UAAU,KAAK,KAAK,SAAS,GAAG;AACxC,YAAM,IAAI,WAAW,gEAAgE,KAAK,UAAU,OAAO,KAAK,CAAC,GAAG;AAAA,IACxH;AACA,QAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GAAG;AACvC,YAAM,IAAI,WAAW,6DAA6D,KAAK,UAAU,OAAO,KAAK,CAAC,GAAG;AAAA,IACrH;AACA,UAAM,MAAM,EAAE,OAAO,MAAM;AAC3B,QAAI,OAAO,OAAO,SAAS,YAAY,OAAO,KAAK,KAAK,GAAG;AACvD,UAAI,OAAO,OAAO,KAAK,KAAK;AAAA,IAChC;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,SAAS,MAAM;AACvB,UAAM,SAAS,IAAI;AACnB,SAAK,gBAAgB;AACrB,SAAK,kBAAkB;AACvB,SAAK,qBAAqB;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,aAAa;AACrB,SAAK,gBAAgB;AACrB,SAAK,kBAAkB,OAAO,SAAS,WAAW,KAAK,cAAc,IAAI,cAAc;AACvF,SAAK,QAAQ,OAAO;AAAA,MAChB,6CAA6C,KAAK,KAAK,EAAE,kBAAkB,KAAK,eAAe;AAAA,IACnG;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,IAAI,gBAAgB;AACtB,UAAM,WAAW,KAAK,MAAM,QAAQ,SAAS;AAC7C,UAAM,WAAW,KAAK,MAAM,QAAQ,SAAS;AAC7C,UAAM,UAAU,KAAK,MAAM,QAAQ;AAEnC,UAAM,QAAQ,OAAO,QAAQ;AAC7B,UAAM,QAAQ,OAAO,QAAQ;AAC7B,UAAM,OAAO,OAAO,YAAY,YAAY,QAAQ,KAAK,IAAI,QAAQ,KAAK,IAAI;AAE9E,UAAM,SAAS,CAAC;AAChB,QAAI,CAAC,OAAO,UAAU,KAAK,KAAK,SAAS,GAAG;AACxC,aAAO,KAAK,0CAA0C;AAAA,IAC1D;AACA,QAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GAAG;AACvC,aAAO,KAAK,uCAAuC;AAAA,IACvD;AAEA,QAAI,OAAO,SAAS,GAAG;AACnB,aAAO;AAAA,QACH,SAAS;AAAA,QACT,SAAS;AAAA,UACL,OAAO,sBAAsB,OAAO,KAAK,IAAI,CAAC;AAAA,UAC9C,UAAU,EAAE,OAAO,UAAU,OAAO,UAAU,MAAM,QAAQ;AAAA,QAChE;AAAA,MACJ;AAAA,IACJ;AAEA,UAAM,YAAY,KAAK,IAAI;AAC3B,aAAS,IAAI,GAAG,KAAK,OAAO,KAAK,GAAG;AAChC,UAAI,KAAK,eAAe;AACpB,cAAM,cAAc,KAAK,IAAI,IAAI,QAAQ,IAAI,KAAK,KAAK;AACvD,YAAI,eAAe,KAAK,iBAAiB;AACrC,cAAI,CAAC,KAAK,oBAAoB;AAC1B,iBAAK,qBAAqB;AAC1B,iBAAK,QAAQ,OAAO;AAAA,cAChB,2CAA2C,KAAK,KAAK,EAAE,kBAAkB,WAAW,mBAAmB,KAAK,eAAe;AAAA,YAC/H;AAAA,UACJ;AAAA,QACJ,OAAO;AACH,eAAK,QAAQ,OAAO;AAAA,YAChB,wDAAwD,CAAC,IAAI,KAAK,KAAK,KAAK,KAAK,EAAE,kBAAkB,WAAW,kBAAkB,KAAK,eAAe;AAAA,UAC1J;AACA,iBAAO;AAAA,YACH,SAAS;AAAA,YACT,SAAS;AAAA,cACL,SAAS,0CAA0C,CAAC,IAAI,KAAK;AAAA,cAC7D,WAAW,IAAI;AAAA,cACf;AAAA,cACA;AAAA,cACA;AAAA,cACA,aAAa,KAAK;AAAA,YACtB;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAEA,YAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,YAAM,YAAY,KAAK,IAAI,IAAI,QAAQ,KAAK,KAAK;AACjD,YAAM,WAAW;AAAA,QACb;AAAA,QACA,OAAO;AAAA,QACP;AAAA,QACA,WAAW;AAAA,QACX,aAAa;AAAA,QACb,QAAQ,WAAW,IAAI,KAAK,CAAC,IAAI,KAAK;AAAA,MAC1C;AAEA,WAAK,QAAQ,OAAO,SAAS,WAAW;AAAA,QACpC,QAAQ;AAAA,QACR,OAAO;AAAA,QACP;AAAA,MACJ,CAAC;AACD,YAAM,eAAe,QAAQ;AAC7B,YAAM,QAAQ,KAAK;AAAA,IACvB;AAEA,WAAO;AAAA,MACH,SAAS;AAAA,MACT,SAAS;AAAA,QACL,SAAS,aAAa,KAAK;AAAA,QAC3B;AAAA,QACA;AAAA,QACA;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;;;AC9JA,gCAAsB;AAatB,SAAS,gBAAgB,SAAS,KAAK;AACnC,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACpC,UAAM,YAAQ,iCAAM,SAAS;AAAA,MACzB,OAAO;AAAA,MACP,KAAK,OAAO,QAAQ,IAAI;AAAA,MACxB,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,IACpC,CAAC;AAED,QAAI,SAAS;AACb,QAAI,SAAS;AAEb,UAAM,OAAO,GAAG,QAAQ,CAAC,UAAU;AAC/B,gBAAU,OAAO,KAAK;AAAA,IAC1B,CAAC;AACD,UAAM,OAAO,GAAG,QAAQ,CAAC,UAAU;AAC/B,gBAAU,OAAO,KAAK;AAAA,IAC1B,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,UAAU;AACzB,aAAO,KAAK;AAAA,IAChB,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,UAAU,WAAW;AACpC,cAAQ;AAAA,QACJ;AAAA,QACA,QAAQ,OAAO,KAAK;AAAA,QACpB,QAAQ,OAAO,KAAK;AAAA,QACpB;AAAA,MACJ,CAAC;AAAA,IACL,CAAC;AAAA,EACL,CAAC;AACL;AAWO,IAAM,mBAAN,cAA+B,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM/C,aAAa,oBAAoB,SAAS,YAAY,CAAC,GAAG;AACtD,UAAM,SAAS,aAAa,kBAAkB,SAAS,cAAc;AAAA,MACjE,SAAS;AAAA,MACT,KAAK;AAAA,IACT,GAAG,SAAS;AACZ,UAAM,UAAU,OAAO,OAAO,YAAY,WAAW,OAAO,QAAQ,KAAK,IAAI;AAC7E,QAAI,CAAC,SAAS;AACV,YAAM,IAAI,WAAW,0DAA0D;AAAA,IACnF;AACA,UAAM,MAAM,OAAO,OAAO,QAAQ,YAAY,OAAO,IAAI,KAAK,IAAI,OAAO,IAAI,KAAK,IAAI;AACtF,WAAO,MAAM,EAAE,SAAS,IAAI,IAAI,EAAE,QAAQ;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM;AACR,UAAM,SAAS,KAAK,MAAM;AAC1B,UAAM,aAAa,OAAO,WAAW,WAAW,SAAS,QAAQ;AACjE,UAAM,SAAS,OAAO,WAAW,WAAW,SAAY,QAAQ;AAChE,UAAM,UAAU,OAAO,eAAe,WAAW,WAAW,KAAK,IAAI;AACrE,UAAM,MAAM,OAAO,WAAW,YAAY,OAAO,KAAK,IAAI,OAAO,KAAK,IAAI;AAE1E,QAAI,CAAC,SAAS;AACV,aAAO;AAAA,QACH,SAAS;AAAA,QACT,SAAS;AAAA,UACL,OAAO;AAAA,UACP,UAAU,KAAK,MAAM,UAAU;AAAA,QACnC;AAAA,MACJ;AAAA,IACJ;AAEA,QAAI;AACA,YAAM,SAAS,MAAM,gBAAgB,SAAS,GAAG;AACjD,YAAM,UAAU,OAAO,aAAa;AAEpC,WAAK,QAAQ,OAAO;AAAA,QAChB,+BAA+B,OAAO,cAAc,OAAO,OAAO,QAAQ,CAAC,KAAK,KAAK,KAAK,EAAE;AAAA,MAChG;AAEA,aAAO;AAAA,QACH;AAAA,QACA,SAAS;AAAA,UACL;AAAA,UACA,KAAK,OAAO,QAAQ,IAAI;AAAA,UACxB,QAAQ,OAAO;AAAA,UACf,QAAQ,OAAO;AAAA,UACf,UAAU,OAAO;AAAA,UACjB,QAAQ,OAAO;AAAA,QACnB;AAAA,MACJ;AAAA,IACJ,SAAS,OAAO;AACZ,aAAO;AAAA,QACH,SAAS;AAAA,QACT,SAAS;AAAA,UACL;AAAA,UACA,KAAK,OAAO,QAAQ,IAAI;AAAA,UACxB,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,OAAO,OAAO,WAAW,OAAO,KAAK;AAAA,QACzC;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;;;AC/HA,IAAAC,kBAAe;AACf,IAAAC,mBAAe;AASf,SAAS,KAAK,YAAY;AACtB,SAAO,IAAI,aAAc,QAAQ,GAAI,QAAQ,CAAC,CAAC;AACnD;AAQA,SAAS,KAAK,YAAY;AACtB,SAAO,IAAI,aAAc,QAAQ,GAAI,QAAQ,CAAC,CAAC;AACnD;AAQA,eAAe,eAAe;AAE1B,QAAM,QAAQ,MAAM,iBAAAC,QAAG,OAAO,GAAG;AACjC,QAAM,QAAQ,OAAO,MAAM,KAAK,IAAI,OAAO,MAAM,MAAM;AACvD,QAAM,OAAO,OAAO,MAAM,KAAK,IAAI,OAAO,MAAM,MAAM;AACtD,QAAM,OAAO,QAAQ;AACrB,SAAO;AAAA,IACH,OAAO,KAAK,KAAK;AAAA,IACjB,MAAM,KAAK,IAAI;AAAA,IACf,MAAM,KAAK,IAAI;AAAA,EACnB;AACJ;AAMO,IAAM,iBAAN,cAA6B,aAAa;AAAA;AAAA,EAE7C,OAAO,uBAAuB;AAAA;AAAA,EAG9B,aAAa,sBAAsB;AAC/B,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM;AACR,QAAI;AACA,YAAM,cAAc,gBAAAC,QAAG,SAAS;AAChC,YAAM,aAAa,gBAAAA,QAAG,QAAQ;AAC9B,YAAM,aAAa,cAAc;AAEjC,YAAM,OAAO,gBAAAA,QAAG,KAAK;AACrB,YAAM,iBAAiB,KAAK,IAAI,CAAC,QAAQ;AACrC,cAAM,QAAQ,OAAO,OAAO,IAAI,KAAK,EAAE,OAAO,CAAC,KAAK,SAAS,MAAM,MAAM,CAAC;AAC1E,cAAM,SAAU,QAAQ,IAAI,MAAM,QAAQ,QAAS;AACnD,eAAO,OAAO,MAAM,QAAQ,CAAC,CAAC;AAAA,MAClC,CAAC;AAED,YAAM,gBAAgB,QAAQ,YAAY;AAC1C,YAAM,OAAO,MAAM,aAAa;AAEhC,YAAM,UAAU;AAAA,QACZ,QAAQ;AAAA,UACJ,OAAO,KAAK,WAAW;AAAA,UACvB,MAAM,KAAK,UAAU;AAAA,UACrB,MAAM,KAAK,UAAU;AAAA,QACzB;AAAA,QACA,eAAe;AAAA,UACX,KAAK,KAAK,cAAc,GAAG;AAAA,UAC3B,WAAW,KAAK,cAAc,SAAS;AAAA,UACvC,UAAU,KAAK,cAAc,QAAQ;AAAA,UACrC,UAAU,KAAK,cAAc,QAAQ;AAAA,QACzC;AAAA,QACA;AAAA,QACA,KAAK;AAAA,UACD,OAAO,eAAe;AAAA,UACtB,aAAa;AAAA,QACjB;AAAA,QACA,SAAS;AAAA,UACL,UAAU,gBAAAA,QAAG,SAAS;AAAA,UACtB,MAAM,gBAAAA,QAAG,KAAK;AAAA,UACd,WAAW,gBAAAA,QAAG,OAAO;AAAA,UACrB,UAAU,gBAAAA,QAAG,SAAS;AAAA,QAC1B;AAAA,MACJ;AAEA,WAAK,QAAQ,OAAO,OAAO,8CAA8C,KAAK,KAAK,EAAE,GAAG;AACxF,aAAO,EAAE,SAAS,MAAM,QAAQ;AAAA,IACpC,SAAS,OAAO;AACZ,aAAO;AAAA,QACH,SAAS;AAAA,QACT,SAAS;AAAA,UACL,OAAO;AAAA,UACP,SAAS,OAAO,WAAW,OAAO,KAAK;AAAA,QAC3C;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;;;ACxGO,IAAM,YAAN,cAAwB,aAAa;AAAA;AAAA,EAExC,OAAO,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO9B,aAAa,oBAAoB,SAAS,YAAY,CAAC,GAAG;AACtD,UAAM,SAAS,aAAa,kBAAkB,SAAS,cAAc;AAAA,MACjE,GAAG;AAAA,MACH,GAAG;AAAA,IACP,GAAG,SAAS;AACZ,QAAI,OAAO,OAAO,MAAM,YAAY,OAAO,MAAM,OAAO,CAAC,GAAG;AACxD,YAAM,IAAI,WAAW,oDAAoD,KAAK,UAAU,OAAO,CAAC,CAAC,GAAG;AAAA,IACxG;AACA,QAAI,OAAO,OAAO,MAAM,YAAY,OAAO,MAAM,OAAO,CAAC,GAAG;AACxD,YAAM,IAAI,WAAW,oDAAoD,KAAK,UAAU,OAAO,CAAC,CAAC,GAAG;AAAA,IACxG;AACA,WAAO,EAAE,GAAG,OAAO,GAAG,GAAG,OAAO,EAAE;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM;AACR,UAAM,IAAI,KAAK,MAAM,QAAQ;AAC7B,UAAM,IAAI,KAAK,MAAM,QAAQ;AAE7B,QAAI,OAAO,MAAM,YAAY,OAAO,MAAM,CAAC,GAAG;AAC1C,aAAO;AAAA,QACH,SAAS;AAAA,QACT,SAAS;AAAA,UACL,OAAO;AAAA,UACP,UAAU,EAAE,GAAG,EAAE;AAAA,QACrB;AAAA,MACJ;AAAA,IACJ;AAEA,QAAI,OAAO,MAAM,YAAY,OAAO,MAAM,CAAC,GAAG;AAC1C,aAAO;AAAA,QACH,SAAS;AAAA,QACT,SAAS;AAAA,UACL,OAAO;AAAA,UACP,UAAU,EAAE,GAAG,EAAE;AAAA,QACrB;AAAA,MACJ;AAAA,IACJ;AAEA,UAAM,MAAM,IAAI;AAChB,SAAK,QAAQ,OAAO,OAAO,eAAe,CAAC,MAAM,CAAC,MAAM,GAAG,KAAK,KAAK,KAAK,EAAE,GAAG;AAC/E,WAAO;AAAA,MACH,SAAS;AAAA,MACT,SAAS,EAAE,GAAG,GAAG,IAAI;AAAA,IACzB;AAAA,EACJ;AACJ;;;ACtDO,IAAM,iBAAN,cAA6B,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAU7C,aAAa,cAAc,SAAS,YAAY,CAAC,GAAG;AAChD,UAAM,OAAO,MAAM,MAAM,cAAc,SAAS,SAAS;AACzD,QAAI,CAAC,KAAK,aAAa;AACnB,YAAM,IAAI;AAAA,QACN;AAAA,MACJ;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,oBAAoB,SAAS,YAAY,CAAC,GAAG;AACtD,UAAM,SAAS,aAAa,kBAAkB,SAAS,aAAa;AAAA,MAChE,aAAa;AAAA,IACjB,GAAG,SAAS;AACZ,UAAM,cAAc,OAAO,OAAO,WAAW;AAC7C,QAAI,CAAC,OAAO,SAAS,WAAW,KAAK,cAAc,GAAG;AAClD,YAAM,IAAI;AAAA,QACN,8DAA8D,KAAK,UAAU,OAAO,WAAW,CAAC;AAAA,MACpG;AAAA,IACJ;AACA,WAAO,EAAE,YAAY;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM;AACR,UAAM,cAAc,OAAO,KAAK,MAAM,QAAQ,eAAe,GAAM;AACnE,SAAK,QAAQ,OAAO,OAAO,gDAAgD,WAAW,GAAG;AACzF,WAAO;AAAA,MACH,SAAS;AAAA,MACT,SAAS;AAAA,QACL,YAAY;AAAA,QACZ;AAAA,QACA,SAAS;AAAA,MACb;AAAA,IACJ;AAAA,EACJ;AACJ;;;AC5DO,IAAM,oBAAoB,CAAC,eAAe,UAAU,iBAAiB,WAAW;AAGhF,IAAM,sBAAsB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ;AAeO,IAAM,8BAA8B;AAAA,EACvC;AAAA,IACI,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,IACI,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,IACI,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,IACI,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,IACI,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,IACI,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,IACI,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,IACI,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,IACI,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,IACI,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACjB;AACJ;AAQO,SAAS,uBAAuB,OAAO;AAC1C,QAAM,QAAQ,IAAI,IAAI,4BAA4B,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;AAC/E,MAAI,MAAM,QAAQ,KAAK,GAAG;AACtB,eAAW,OAAO,OAAO;AACrB,UAAI,CAAC,OAAO,OAAO,QAAQ,SAAU;AACrC,YAAM,MAAM,OAAO,IAAI,OAAO,EAAE,EAAE,KAAK;AACvC,UAAI,CAAC,IAAK;AACV,YAAM,OAAO,MAAM,IAAI,GAAG,KAAK,CAAC;AAChC,YAAM,OAAO,CAAC,UAAU,WAAW,QAAQ,EAAE,SAAS,IAAI,IAAI,IAAI,IAAI,OAAO,KAAK,QAAQ;AAC1F,YAAM,IAAI,KAAK;AAAA,QACX;AAAA,QACA;AAAA,QACA,OAAO,OAAO,IAAI,SAAS,KAAK,SAAS,GAAG;AAAA,QAC5C,aACI,IAAI,eAAe,OACb,OAAO,IAAI,WAAW,IACtB,KAAK,eAAe,OAClB,OAAO,KAAK,WAAW,IACvB;AAAA,MAChB,CAAC;AAAA,IACL;AAAA,EACJ;AACA,SAAO,MAAM,KAAK,MAAM,OAAO,CAAC;AACpC;AASO,SAAS,sBAAsB,SAAS,QAAQ,6BAA6B;AAChF,QAAM,KAAK,mBAAmB,OAAO;AACrC,QAAM,MAAM,CAAC;AACb,aAAW,KAAK,OAAO;AACnB,QAAI,GAAG,EAAE,GAAG,MAAM,OAAW,KAAI,EAAE,GAAG,IAAI,GAAG,EAAE,GAAG;AAAA,EACtD;AACA,SAAO;AACX;AAQO,SAAS,8BAA8B,UAAU;AACpD,QAAM,OAAO,YAAY,OAAO,aAAa,WAAW,WAAW;AACnE,QAAM,MAAM,MAAM;AAClB,MAAI,CAAC,MAAM,QAAQ,GAAG,KAAK,IAAI,WAAW,GAAG;AACzC,WAAO,uBAAuB;AAAA,EAClC;AACA,SAAO,uBAAuB,GAAG;AACrC;AAEA,IAAM,0BAA0B;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ;AAUO,SAAS,qBAAqB,OAAO;AACxC,QAAM,QAAQ,CAAC,GAAG,uBAAuB;AACzC,MAAI,SAAS,QAAQ,UAAU,GAAI,QAAO;AAC1C,QAAM,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,OAAO,KAAK,EAAE,MAAM,GAAG;AACnE,QAAM,OAAO,IAAI,IAAI,KAAK;AAC1B,aAAW,OAAO,MAAM;AACpB,UAAM,IAAI,OAAO,OAAO,EAAE,EAAE,KAAK;AACjC,QAAI,CAAC,KAAK,KAAK,IAAI,CAAC,EAAG;AACvB,SAAK,IAAI,CAAC;AACV,UAAM,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACX;AAOA,SAAS,cAAc,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG;AACjD,QAAM,IAAI,OAAO,KAAK;AACtB,MAAI,CAAC,OAAO,SAAS,CAAC,KAAK,IAAI,KAAK;AAChC,UAAM,IAAI;AAAA,MACN,oBAAoB,GAAG,wBAAwB,GAAG,SAAS,KAAK,UAAU,KAAK,CAAC;AAAA,IACpF;AAAA,EACJ;AACA,SAAO,KAAK,MAAM,CAAC;AACvB;AAUO,SAAS,mBAAmB,KAAK,OAAO;AAC3C,UAAQ,KAAK;AAAA,IACT,KAAK;AACD,aAAO,cAAc,OAAO,KAAK,EAAE,KAAK,EAAE,CAAC;AAAA,IAC/C,KAAK;AACD,aAAO,cAAc,OAAO,KAAK,EAAE,KAAK,GAAG,CAAC;AAAA,IAChD,KAAK;AACD,aAAO,cAAc,OAAO,KAAK,EAAE,KAAK,EAAE,CAAC;AAAA,IAC/C,KAAK;AACD,aAAO,cAAc,OAAO,KAAK,EAAE,KAAK,EAAE,CAAC;AAAA,IAC/C,KAAK;AACD,aAAO,cAAc,OAAO,KAAK,EAAE,KAAK,EAAE,CAAC;AAAA,IAC/C,KAAK;AACD,aAAO,cAAc,OAAO,KAAK,EAAE,KAAK,IAAO,CAAC;AAAA,IACpD,KAAK;AACD,aAAO,cAAc,OAAO,KAAK,EAAE,KAAK,EAAE,CAAC;AAAA,IAC/C,KAAK,8BAA8B;AAC/B,YAAM,IAAI,OAAO,KAAK;AACtB,UAAI,CAAC,OAAO,SAAS,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG;AACzC,cAAM,IAAI;AAAA,UACN,oBAAoB,GAAG,0CAA0C,KAAK,UAAU,KAAK,CAAC;AAAA,QAC1F;AAAA,MACJ;AACA,aAAO;AAAA,IACX;AAAA,IACA,KAAK;AACD,UAAI,OAAO,UAAU,UAAW,QAAO;AACvC,UAAI,UAAU,UAAU,UAAU,IAAK,QAAO;AAC9C,UAAI,UAAU,WAAW,UAAU,IAAK,QAAO;AAC/C,YAAM,IAAI;AAAA,QACN,oBAAoB,GAAG,yBAAyB,KAAK,UAAU,KAAK,CAAC;AAAA,MACzE;AAAA,IACJ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACD,UAAI,OAAO,UAAU,UAAW,QAAO;AACvC,UAAI,UAAU,UAAU,UAAU,IAAK,QAAO;AAC9C,UAAI,UAAU,WAAW,UAAU,IAAK,QAAO;AAC/C,YAAM,IAAI;AAAA,QACN,oBAAoB,GAAG,yBAAyB,KAAK,UAAU,KAAK,CAAC;AAAA,MACzE;AAAA,IACJ,KAAK;AACD,aAAO,cAAc,OAAO,KAAK,EAAE,KAAK,EAAE,CAAC;AAAA,IAC/C,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACD,aAAO;AAAA,IACX;AACI,aAAO;AAAA,EACf;AACJ;AASO,SAAS,mBAAmB,SAAS,OAAO,CAAC,GAAG;AACnD,MAAI,CAAC,QAAQ,gBAAgB,OAAO,QAAQ,iBAAiB,UAAU;AACnE,YAAQ,eAAe,CAAC;AAAA,EAC5B;AACA,QAAM,KAAK,QAAQ;AACnB,MAAI,GAAG,gBAAgB,OAAW,IAAG,cAAc,KAAK,eAAe;AACvE,MAAI,GAAG,WAAW,OAAW,IAAG,SAAS,KAAK,UAAU;AACxD,MAAI,GAAG,kBAAkB,OAAW,IAAG,gBAAgB,KAAK,iBAAiB;AAC7E,MAAI,GAAG,cAAc,OAAW,IAAG,YAAY,KAAK,aAAa;AACjE,MAAI,GAAG,WAAW,OAAW,IAAG,SAAS,KAAK,WAAW;AACzD,SAAO;AACX;AAWA,eAAsB,kBAAkB,SAAS,KAAK,OAAO;AACzD,QAAM,IAAI,OAAO,OAAO,EAAE,EAAE,KAAK;AACjC,MAAI,CAAC,EAAG,OAAM,IAAI,WAAW,kCAAkC;AAE/D,QAAM,UAAU,mBAAmB,OAAO;AAC1C,QAAM,OAAO,mBAAmB,GAAG,KAAK;AACxC,QAAM,WAAW,QAAQ,CAAC;AAC1B,QAAM,UAAU,CAAC;AAEjB,UAAQ,CAAC,IAAI;AACb,UAAQ,KAAK,cAAc;AAE3B,MAAI,oBAAoB,SAAS,CAAC,KAAK,QAAQ,QAAQ,WAAW;AAC9D,YAAQ,OAAO,UAAU,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC;AACtC,YAAQ,KAAK,QAAQ;AAAA,EACzB;AAEA,QAAM,OAAO,QAAQ;AACrB,MAAI,OAAO,SAAS,YAAY;AAC5B,UAAM,KAAK,GAAG,MAAM,SAAS,OAAO;AACpC,YAAQ,KAAK,gBAAgB;AAAA,EACjC;AAEA,QAAM,MAAM,QAAQ;AACpB,MAAI,KAAK,SAAS,KAAK,eAAe;AAClC,QAAI;AAEA,YAAM,QAAQ,MAAM,QAAQ,QAAQ,sBAAsB,IACpD,QAAQ,yBACR;AACN,YAAM,kBAAkB,sBAAsB,SAAS,KAAK;AAC5D,iBAAW,MAAM,mBAAmB;AAChC,YAAI,QAAQ,EAAE,MAAM,UAAa,gBAAgB,EAAE,MAAM,QAAW;AAChE,0BAAgB,EAAE,IAAI,QAAQ,EAAE;AAAA,QACpC;AAAA,MACJ;AACA,YAAM,+BAA+B,SAAS,KAAK;AAAA,QAC/C,SAAS;AAAA,QACT,mBAAkB,oBAAI,KAAK,GAAE,YAAY;AAAA,MAC7C,CAAC;AACD,cAAQ,KAAK,kBAAkB;AAAA,IACnC,SAAS,KAAK;AACV,cAAQ,QAAQ;AAAA,QACZ,sDAAsD,KAAK,WAAW,OAAO,GAAG,CAAC;AAAA,MACrF;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO,EAAE,KAAK,GAAG,UAAU,MAAM,QAAQ;AAC7C;AASA,eAAsB,kBAAkB,SAAS,OAAO;AACpD,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC7D,UAAM,IAAI,WAAW,+CAA+C;AAAA,EACxE;AACA,QAAM,UAAU,OAAO,QAAQ,KAAK;AACpC,MAAI,QAAQ,WAAW,GAAG;AACtB,UAAM,IAAI,WAAW,iCAAiC;AAAA,EAC1D;AACA,QAAM,MAAM,CAAC;AACb,aAAW,CAAC,KAAK,KAAK,KAAK,SAAS;AAChC,QAAI,KAAK,MAAM,kBAAkB,SAAS,KAAK,KAAK,CAAC;AAAA,EACzD;AACA,SAAO;AACX;AAQO,SAAS,gBAAgB,SAAS;AACrC,QAAM,KAAK,mBAAmB,OAAO;AACrC,SAAO;AAAA,IACH,aAAa,KAAK,IAAI,GAAG,OAAO,GAAG,WAAW,KAAK,CAAC;AAAA,IACpD,QAAQ,KAAK,IAAI,IAAI,OAAO,GAAG,MAAM,KAAK,GAAI;AAAA,IAC9C,eAAe,KAAK,IAAI,GAAG,OAAO,GAAG,aAAa,KAAK,CAAC;AAAA,IACxD,WAAW,KAAK,IAAI,GAAG,OAAO,GAAG,SAAS,KAAK,GAAG;AAAA,EACtD;AACJ;;;AC7WA,eAAsB,kBAAkB,SAAS,QAAQ;AACrD,QAAM,UAAU,mBAAmB,OAAO;AAC1C,QAAM,MAAM,QAAQ,WAAW;AAC/B,UAAQ,SAAS,WAAW;AAE5B,QAAM,WAAW,QAAQ;AACzB,MAAI,YAAY,OAAO,aAAa,UAAU;AAC1C,UAAM,+BAA+B,SAAS,UAAU;AAAA,MACpD,QAAQ,QAAQ;AAAA,MAChB,UAAU,QAAQ,UAAS,oBAAI,KAAK,GAAE,YAAY,IAAI;AAAA,IAC1D,CAAC;AAAA,EACL;AAEA,QAAM,UAAU,QAAQ,SAClB,MACI,iDACA,gFACJ,MACE,kDACA;AAER,UAAQ,QAAQ;AAAA,IACZ,QAAQ,SAAS,qBAAqB,OAAO,KAAK,uBAAuB,OAAO;AAAA,EACpF;AAEA,SAAO;AAAA,IACH,SAAS;AAAA,IACT,SAAS;AAAA,MACL,QAAQ,QAAQ;AAAA,MAChB;AAAA,IACJ;AAAA,EACJ;AACJ;AAKO,IAAM,kBAAN,cAA8B,aAAa;AAAA,EAC9C,OAAO,WAAW;AAAA,EAClB,OAAO,cACH;AAAA,EACJ,OAAO,UAAU,CAAC,OAAO;AAAA,EACzB,OAAO,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO9B,aAAa,cAAc,SAAS,YAAY,CAAC,GAAG;AAChD,UAAM,OAAO,MAAM,MAAM,cAAc,SAAS,SAAS;AACzD,QAAI,CAAC,KAAK,aAAa;AACnB,YAAM,IAAI;AAAA,QACN;AAAA,MACJ;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AAAA,EAEA,MAAM,MAAM;AACR,WAAO,kBAAkB,KAAK,SAAS,IAAI;AAAA,EAC/C;AACJ;AAKO,IAAM,oBAAN,cAAgC,aAAa;AAAA,EAChD,OAAO,WAAW;AAAA,EAClB,OAAO,cAAc;AAAA,EACrB,OAAO,UAAU,CAAC,SAAS;AAAA,EAC3B,OAAO,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO9B,aAAa,cAAc,SAAS,YAAY,CAAC,GAAG;AAChD,UAAM,OAAO,MAAM,MAAM,cAAc,SAAS,SAAS;AACzD,QAAI,CAAC,KAAK,aAAa;AACnB,YAAM,IAAI;AAAA,QACN;AAAA,MACJ;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AAAA,EAEA,MAAM,MAAM;AACR,WAAO,kBAAkB,KAAK,SAAS,KAAK;AAAA,EAChD;AACJ;;;ACtFA,SAAS,oBAAoB,UAAU;AACnC,MAAI,YAAY,QAAQ,aAAa,GAAI,QAAO,CAAC;AACjD,MAAI,OAAO,aAAa,YAAY,CAAC,MAAM,QAAQ,QAAQ,GAAG;AAC1D,WAAO,EAAE,GAAG,SAAS;AAAA,EACzB;AACA,MAAI,OAAO,aAAa,UAAU;AAC9B,UAAM,IAAI,SAAS,KAAK;AACxB,QAAI,EAAE,WAAW,GAAG,KAAK,EAAE,WAAW,GAAG,GAAG;AACxC,UAAI;AACA,cAAM,SAAS,KAAK,MAAM,CAAC;AAC3B,YAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,EAAG,QAAO,EAAE,GAAG,OAAO;AAAA,MAC3F,QAAQ;AAAA,MAER;AAAA,IACJ;AACA,WAAO,EAAE,SAAS,SAAS;AAAA,EAC/B;AACA,SAAO,EAAE,SAAS,OAAO,QAAQ,EAAE;AACvC;AAOA,eAAsB,eAAe,SAAS,QAAQ;AAClD,QAAM,KAAK,QAAQ;AACnB,MAAI,CAAC,GAAI,OAAM,IAAI,MAAM,mCAAmC;AAC5D,QAAM,KAAK,OAAO,UAAU,EAAE,EAAE,KAAK;AACrC,MAAI,CAAC,GAAI,OAAM,IAAI,WAAW,uCAAuC;AAErE,QAAM,EAAE,WAAW,IAAI,kBAAkB,QAAQ,kBAAkB,OAAO;AAC1E,QAAM,MAAM,MAAM,GAAG,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AACrD,MAAI,CAAC,KAAK;AACN,WAAO,EAAE,SAAS,OAAO,SAAS,EAAE,OAAO,QAAQ,EAAE,cAAc,QAAQ,GAAG,EAAE;AAAA,EACpF;AAEA,MAAI,IAAI,WAAW,UAAU;AACzB,WAAO;AAAA,MACH,SAAS;AAAA,MACT,SAAS,EAAE,QAAQ,IAAI,QAAQ,UAAU,SAAS,sBAAsB;AAAA,IAC5E;AAAA,EACJ;AAEA,MAAI,IAAI,WAAW,QAAQ;AACvB,UAAM,WAAW,oBAAoB,IAAI,QAAQ;AACjD,aAAS,iBAAiB;AAC1B,aAAS,YAAW,oBAAI,KAAK,GAAE,YAAY;AAC3C,UAAM,GAAG,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO;AAAA,MACtC,QAAQ;AAAA,MACR,mBAAmB,GAAG,GAAG,IAAI;AAAA,MAC7B,UAAU,aAAa,QAAQ;AAAA,IACnC,CAAC;AACD,YAAQ,QAAQ,OAAO,yBAAyB,EAAE,KAAK,IAAI,IAAI,iBAAY;AAC3E,WAAO;AAAA,MACH,SAAS;AAAA,MACT,SAAS,EAAE,QAAQ,IAAI,QAAQ,UAAU,SAAS,mBAAmB;AAAA,IACzE;AAAA,EACJ;AAEA,MAAI,IAAI,WAAW,WAAW;AAC1B,UAAM,WAAW,oBAAoB,IAAI,QAAQ;AACjD,aAAS,iBAAiB;AAC1B,aAAS,oBAAmB,oBAAI,KAAK,GAAE,YAAY;AACnD,UAAM,GAAG,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO;AAAA,MACtC,UAAU,aAAa,QAAQ;AAAA,IACnC,CAAC;AAED,UAAM,OAAO,QAAQ,sBAAsB,MAAM,EAAE;AACnD,QAAI,QAAQ,OAAO,KAAK,iBAAiB,YAAY;AACjD,YAAM,KAAK,aAAa;AACxB,cAAQ,QAAQ;AAAA,QACZ,qCAAqC,EAAE,KAAK,IAAI,IAAI;AAAA,MACxD;AACA,aAAO;AAAA,QACH,SAAS;AAAA,QACT,SAAS;AAAA,UACL,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,SAAS;AAAA,QACb;AAAA,MACJ;AAAA,IACJ;AAEA,YAAQ,QAAQ;AAAA,MACZ,yCAAyC,EAAE,KAAK,IAAI,IAAI;AAAA,IAC5D;AACA,WAAO;AAAA,MACH,SAAS;AAAA,MACT,SAAS;AAAA,QACL,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,SACI;AAAA,MACR;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO;AAAA,IACH,SAAS;AAAA,IACT,SAAS;AAAA,MACL,OAAO,gCAAgC,IAAI,MAAM;AAAA,MACjD,QAAQ;AAAA,MACR,QAAQ,IAAI;AAAA,IAChB;AAAA,EACJ;AACJ;AAOA,eAAsB,gBAAgB,SAAS,QAAQ;AACnD,QAAM,KAAK,QAAQ;AACnB,MAAI,CAAC,GAAI,OAAM,IAAI,MAAM,oCAAoC;AAC7D,QAAM,KAAK,OAAO,UAAU,EAAE,EAAE,KAAK;AACrC,MAAI,CAAC,GAAI,OAAM,IAAI,WAAW,wCAAwC;AAEtE,QAAM,EAAE,WAAW,IAAI,kBAAkB,QAAQ,kBAAkB,OAAO;AAC1E,QAAM,MAAM,MAAM,GAAG,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;AACrD,MAAI,CAAC,KAAK;AACN,WAAO,EAAE,SAAS,OAAO,SAAS,EAAE,OAAO,QAAQ,EAAE,cAAc,QAAQ,GAAG,EAAE;AAAA,EACpF;AAEA,MAAI,IAAI,WAAW,QAAQ;AACvB,WAAO;AAAA,MACH,SAAS;AAAA,MACT,SAAS,EAAE,QAAQ,IAAI,QAAQ,QAAQ,SAAS,+BAA+B;AAAA,IACnF;AAAA,EACJ;AAEA,MAAI,IAAI,WAAW,UAAU;AACzB,WAAO;AAAA,MACH,SAAS;AAAA,MACT,SAAS;AAAA,QACL,OAAO,iCAAiC,IAAI,MAAM;AAAA,QAClD,QAAQ;AAAA,QACR,QAAQ,IAAI;AAAA,MAChB;AAAA,IACJ;AAAA,EACJ;AAEA,QAAM,WAAW,oBAAoB,IAAI,QAAQ;AACjD,SAAO,SAAS;AAChB,SAAO,SAAS;AAChB,SAAO,SAAS;AAChB,WAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAE5C,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,GAAG,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO;AAAA,IACtC,QAAQ;AAAA,IACR,mBAAmB,GAAG,GAAG,IAAI;AAAA,IAC7B,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,SAAS;AAAA,IACT,UAAU,aAAa,QAAQ;AAAA;AAAA,IAE/B,cAAc;AAAA,IACd,aAAa;AAAA,IACb,iBAAiB;AAAA;AAAA,IAEjB,aAAa;AAAA,IACb,UAAU;AAAA,EACd,CAAC;AAED,UAAQ,QAAQ,OAAO,4BAA4B,EAAE,KAAK,IAAI,IAAI,yBAAoB;AACtF,SAAO;AAAA,IACH,SAAS;AAAA,IACT,SAAS,EAAE,QAAQ,IAAI,QAAQ,QAAQ,SAAS,2CAA2C;AAAA,EAC/F;AACJ;AAEO,IAAM,gBAAN,cAA4B,aAAa;AAAA,EAC5C,OAAO,WAAW;AAAA,EAClB,OAAO,cAAc;AAAA,EACrB,OAAO,uBAAuB;AAAA,EAE9B,aAAa,oBAAoB,SAAS,YAAY,CAAC,GAAG;AACtD,UAAM,SAAS,aAAa;AAAA,MACxB;AAAA,MACA;AAAA,MACA,EAAE,QAAQ,SAAS;AAAA,MACnB;AAAA,IACJ;AACA,UAAM,SAAS,OAAO,OAAO,WAAW,WAAW,OAAO,OAAO,KAAK,IAAI;AAC1E,QAAI,CAAC,OAAQ,OAAM,IAAI,WAAW,uCAAuC;AACzE,WAAO,EAAE,OAAO;AAAA,EACpB;AAAA,EAEA,MAAM,MAAM;AACR,WAAO,eAAe,KAAK,SAAS,KAAK,MAAM,QAAQ,MAAM;AAAA,EACjE;AACJ;AAEO,IAAM,iBAAN,cAA6B,aAAa;AAAA,EAC7C,OAAO,WAAW;AAAA,EAClB,OAAO,cAAc;AAAA,EACrB,OAAO,uBAAuB;AAAA,EAE9B,aAAa,oBAAoB,SAAS,YAAY,CAAC,GAAG;AACtD,UAAM,SAAS,aAAa;AAAA,MACxB;AAAA,MACA;AAAA,MACA,EAAE,QAAQ,SAAS;AAAA,MACnB;AAAA,IACJ;AACA,UAAM,SAAS,OAAO,OAAO,WAAW,WAAW,OAAO,OAAO,KAAK,IAAI;AAC1E,QAAI,CAAC,OAAQ,OAAM,IAAI,WAAW,wCAAwC;AAC1E,WAAO,EAAE,OAAO;AAAA,EACpB;AAAA,EAEA,MAAM,MAAM;AACR,WAAO,gBAAgB,KAAK,SAAS,KAAK,MAAM,QAAQ,MAAM;AAAA,EAClE;AACJ;;;ACpOO,IAAM,cAAN,cAA0B,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1C,aAAa,oBAAoB,SAAS,YAAY,CAAC,GAAG;AACtD,UAAM,SAAS,aAAa,kBAAkB,SAAS,iBAAiB;AAAA,MACpE,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,MAAM;AAAA,MACN,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,QAAQ;AAAA,IACZ,GAAG,SAAS;AACZ,UAAM,SAAS,OAAO,OAAO,WAAW,WAAW,OAAO,OAAO,KAAK,IAAI;AAC1E,UAAM,WAAW,OAAO,OAAO,aAAa,WAAW,OAAO,SAAS,KAAK,IAAI;AAChF,QAAI,CAAC,OAAQ,OAAM,IAAI,WAAW,qCAAqC;AACvE,QAAI,CAAC,SAAU,OAAM,IAAI,WAAW,uCAAuC;AAC3E,QAAI,OAAO,OAAO,OAAO,IAAI;AAC7B,QAAI,CAAC,OAAO,SAAS,IAAI,KAAK,OAAO,EAAG,QAAO;AAC/C,WAAO,KAAK,IAAI,KAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,CAAC,CAAC;AACrD,UAAM,MAAM,EAAE,QAAQ,UAAU,KAAK;AACrC,QAAI,OAAO,OAAO,YAAY,YAAY,OAAO,QAAQ,KAAK,GAAG;AAC7D,UAAI,UAAU,OAAO,QAAQ,KAAK;AAAA,IACtC;AACA,QAAI,OAAO,OAAO,WAAW,YAAY,OAAO,OAAO,KAAK,GAAG;AAC3D,UAAI,SAAS,OAAO,OAAO,KAAK;AAAA,IACpC;AACA,QAAI,OAAO,OAAO,SAAS,YAAY,OAAO,KAAK,KAAK,GAAG;AACvD,UAAI,OAAO,OAAO,KAAK,KAAK;AAAA,IAChC;AACA,QAAI,OAAO,OAAO,WAAW,YAAY,OAAO,OAAO,KAAK,GAAG;AAC3D,UAAI,SAAS,OAAO,OAAO,KAAK;AAAA,IACpC;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,IAAI,iBAAiB;AACvB,UAAM,IAAI,KAAK,KAAK,UAAU,CAAC;AAC/B,UAAM,SAAS,OAAO,EAAE,UAAU,EAAE,EAAE,KAAK;AAC3C,UAAM,WAAW,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK;AAC/C,UAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,KAAQ,OAAO,EAAE,IAAI,IAAI,IAAI,OAAO,EAAE,IAAI,IAAI,GAAG,CAAC;AACpF,UAAM,UAAU,EAAE,WAAW,QAAQ,OAAO,EAAE,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,OAAO,EAAE,KAAK,IAAI;AAC3F,UAAM,SAAS,EAAE,UAAU,QAAQ,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI;AACvF,UAAM,OAAO,EAAE,QAAQ,QAAQ,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI;AAC/E,UAAM,SAAS,EAAE,UAAU,QAAQ,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI;AAEvF,QAAI,CAAC,UAAU,CAAC,UAAU;AACtB,aAAO;AAAA,QACH,SAAS;AAAA,QACT,SAAS,EAAE,OAAO,kDAAkD;AAAA,MACxE;AAAA,IACJ;AAEA,QAAI;AACA,YAAM,EAAE,SAAS,SAAS,IAAI,MAAM,wBAAwB,KAAK,SAAS;AAAA,QACtE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACJ,CAAC;AACD,aAAO;AAAA,QACH,SAAS;AAAA,QACT,SAAS,EAAE,SAAS,UAAU,QAAQ,SAAS;AAAA,MACnD;AAAA,IACJ,SAAS,GAAG;AACR,aAAO;AAAA,QACH,SAAS;AAAA,QACT,SAAS,EAAE,OAAO,GAAG,WAAW,OAAO,CAAC,EAAE;AAAA,MAC9C;AAAA,IACJ;AAAA,EACJ;AACJ;;;AC3EO,IAAM,sBAAN,cAAkC,aAAa;AAAA,EAClD,OAAO,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO9B,aAAa,cAAc,SAAS,YAAY,CAAC,GAAG;AAChD,UAAM,OAAO,MAAM,MAAM,cAAc,SAAS,SAAS;AACzD,QAAI,CAAC,KAAK,eAAe,CAAC,KAAK,cAAc;AACzC,YAAM,IAAI;AAAA,QACN;AAAA,MACJ;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,oBAAoB,SAAS,YAAY,CAAC,GAAG;AACtD,UAAM,SAAS,aAAa;AAAA,MACxB;AAAA,MACA;AAAA,MACA;AAAA,QACI,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,KAAK;AAAA,QACL,OAAO;AAAA,MACX;AAAA,MACA;AAAA,IACJ;AAEA,QAAI,OAAO,SAAS,OAAO,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,OAAO,KAAK,GAAG;AAClF,UAAI,OAAO,KAAK,OAAO,KAAK,EAAE,WAAW,GAAG;AACxC,cAAM,IAAI,WAAW,iCAAiC;AAAA,MAC1D;AACA,aAAO,EAAE,OAAO,EAAE,GAAG,OAAO,MAAM,EAAE;AAAA,IACxC;AAEA,UAAM,MAAM,OAAO,YAAY,OAAO;AACtC,UAAM,QAAQ,OAAO,eAAe,SAAY,OAAO,aAAa,OAAO;AAE3E,QAAI,CAAC,KAAK;AACN,YAAM,IAAI;AAAA,QACN;AAAA,MACJ;AAAA,IACJ;AAGA,QAAI,SAAS;AACb,QAAI,OAAO,UAAU,UAAU;AAC3B,YAAM,IAAI,MAAM,KAAK;AACrB,UAAI,MAAM,OAAQ,UAAS;AAAA,eAClB,MAAM,QAAS,UAAS;AAAA,eACxB,MAAM,MAAM,CAAC,OAAO,MAAM,OAAO,CAAC,CAAC,KAAK,kBAAkB,KAAK,CAAC,GAAG;AACxE,iBAAS,OAAO,CAAC;AAAA,MACrB,WACK,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,KACnC,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,KACnC,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,GACtC;AACE,YAAI;AACA,mBAAS,KAAK,MAAM,CAAC;AAAA,QACzB,QAAQ;AACJ,mBAAS;AAAA,QACb;AAAA,MACJ;AAAA,IACJ;AAEA,WAAO,EAAE,KAAK,OAAO,GAAG,GAAG,OAAO,OAAO;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,aAAa,QAAQ,SAAS,YAAY,CAAC,GAAG;AAC1C,UAAM,UAAU,MAAM,KAAK,cAAc,SAAS,EAAE,GAAG,WAAW,MAAM,kBAAkB,CAAC;AAC3F,UAAM,YAAY,QAAQ,aAAa;AAEvC,QAAI,QAAQ,aAAa;AACrB,YAAM,KAAK,MAAM,YAAY,SAAS,OAAO;AAC7C,aAAO,EAAE,KAAK,CAAC,EAAE,GAAG,SAAS,CAAC,QAAQ,WAAW,EAAE;AAAA,IACvD;AAEA,UAAM,QAAQ,OAAO,QAAQ,gBAAgB,EAAE,EAAE,KAAK;AACtD,QAAI,CAAC,OAAO;AACR,YAAM,IAAI,WAAW,8DAA8D;AAAA,IACvF;AAEA,UAAM,QAAQ,MAAM,qBAAqB,SAAS;AAAA,MAC9C;AAAA,MACA,cAAc;AAAA,MACd,SAAS,UAAU,WAAW;AAAA,IAClC,CAAC;AACD,QAAI,CAAC,MAAM,QAAQ;AACf,YAAM,IAAI;AAAA,QACN,gDAAgD,KAAK,YAAY,SAAS;AAAA,MAC9E;AAAA,IACJ;AAEA,UAAM,MAAM,CAAC;AACb,UAAM,UAAU,CAAC;AACjB,eAAW,OAAO,OAAO;AACrB,YAAM,KAAK,MAAM,YAAY,SAAS;AAAA,QAClC,GAAG;AAAA,QACH,cAAc;AAAA,QACd,aAAa,IAAI;AAAA,QACjB,YAAY,IAAI,eAAe;AAAA,QAC/B,gBAAgB,IAAI,mBAAmB;AAAA,MAC3C,CAAC;AACD,UAAI,KAAK,EAAE;AACX,cAAQ,KAAK,IAAI,YAAY;AAAA,IACjC;AACA,YAAQ,QAAQ;AAAA,MACZ,kCAAkC,QAAQ,MAAM,yBAAyB,KAAK,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA,IACzG;AACA,WAAO,EAAE,KAAK,QAAQ;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM;AACR,UAAM,SAAS,KAAK,MAAM,UAAU,CAAC;AACrC,QAAI;AACJ,QAAI,OAAO,SAAS,OAAO,OAAO,UAAU,UAAU;AAClD,gBAAU,MAAM,kBAAkB,KAAK,SAAS,OAAO,KAAK;AAAA,IAChE,OAAO;AACH,gBAAU,CAAC,MAAM,kBAAkB,KAAK,SAAS,OAAO,KAAK,OAAO,KAAK,CAAC;AAAA,IAC9E;AAEA,UAAM,UAAU,QAAQ,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,KAAK,KAAK,UAAU,EAAE,QAAQ,CAAC,WAAM,KAAK,UAAU,EAAE,IAAI,CAAC,EAAE;AACxG,SAAK,QAAQ,OAAO;AAAA,MAChB,oCAAoC,KAAK,QAAQ,kBAAkB,eAAe,QAAQ,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA,IACrH;AAEA,WAAO;AAAA,MACH,SAAS;AAAA,MACT,SAAS;AAAA,QACL,qBAAqB;AAAA,QACrB;AAAA,QACA,SAAS,EAAE,GAAI,KAAK,QAAQ,gBAAgB,CAAC,EAAG;AAAA,MACpD;AAAA,IACJ;AAAA,EACJ;AACJ;;;AC1KA,IAAI,mBAAmB;AAKhB,SAAS,kCAAkC,KAAK;AACnD,MAAI,OAAO,MAAM;AACb,uBAAmB;AACnB;AAAA,EACJ;AACA,qBAAmB,EAAE,GAAG,IAAI;AAChC;AAMO,SAAS,2BAA2B,KAAK;AAC5C,MAAI,OAAO,QAAQ,QAAQ,GAAI,QAAO,CAAC;AACvC,MAAI,MAAM;AACV,MAAI,OAAO,QAAQ,UAAU;AACzB,UAAM,IAAI,IAAI,KAAK;AACnB,QAAI,CAAC,EAAG,QAAO,CAAC;AAChB,QAAI;AACA,YAAM,KAAK,MAAM,CAAC;AAAA,IACtB,QAAQ;AACJ,aAAO,CAAC;AAAA,IACZ;AAAA,EACJ;AACA,MAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,EAAG,QAAO,CAAC;AACnE,QAAM,MAAM,CAAC;AACb,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC7C,UAAM,IAAI,OAAO,KAAK;AACtB,QAAI,OAAO,QAAQ,EAAE,EAAE,KAAK,KAAK,OAAO,SAAS,CAAC,KAAK,IAAI,GAAG;AAC1D,UAAI,OAAO,IAAI,EAAE,KAAK,CAAC,IAAI;AAAA,IAC/B;AAAA,EACJ;AACA,SAAO;AACX;AAQO,SAAS,0BAA0B,UAAU,CAAC,GAAG;AACpD,QAAM,SAAS,EAAE,GAAI,oBAAoB,CAAC,GAAI,GAAG,2BAA2B,QAAQ,uBAAuB,EAAE;AAC7G,SAAO,OAAO,QAAQ,MAAM,EACvB,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,EAAE,MAAM,OAAO,OAAO,KAAK,EAAE,EAAE,EACvD,OAAO,CAAC,MAAM,EAAE,QAAQ,OAAO,SAAS,EAAE,KAAK,KAAK,EAAE,QAAQ,CAAC,EAC/D,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AACpD;;;ACvCO,IAAM,sBAAsB;AAE5B,IAAM,yBAAyB;AAC/B,IAAM,gCAAgC,KAAK,KAAK;AAChD,IAAM,yBAAyB;AAC/B,IAAM,8BAA8B;AAE3C,IAAM,uBAAuB;AAAA,EACzB,uBAAuB;AAAA,EACvB,oBAAoB;AAAA,EACpB,0BAA0B;AAAA,EAC1B,4BAA4B;AAAA,EAC5B,wBAAwB;AAAA,EACxB,yBAAyB;AAC7B;AAQO,SAAS,yBAAyB,SAAS;AAC9C,QAAM,aACF,OAAO,QAAQ,QAAQ,oBAAoB,aACrC,QAAQ,OAAO,gBAAgB,mBAAmB,oBAAoB,IACtE,CAAC;AACX,QAAM,KAAK,mBAAmB,OAAO;AACrC,MAAI,GAAG,0BAA0B,QAAW;AACxC,OAAG,wBAAwB,WAAW,0BAA0B;AAAA,EACpE;AACA,MAAI,GAAG,uBAAuB,QAAW;AACrC,OAAG,qBAAqB,OAAO,WAAW,sBAAsB,sBAAsB;AAAA,EAC1F;AACA,MAAI,GAAG,6BAA6B,QAAW;AAC3C,OAAG,2BAA2B;AAAA,MAC1B,WAAW,4BAA4B;AAAA,IAC3C;AAAA,EACJ;AACA,MAAI,GAAG,+BAA+B,QAAW;AAC7C,OAAG,6BAA6B;AAAA,MAC5B,WAAW,8BAA8B;AAAA,IAC7C;AAAA,EACJ;AACA,MAAI,GAAG,2BAA2B,QAAW;AACzC,OAAG,yBAAyB,OAAO,WAAW,0BAA0B,2BAA2B;AAAA,EACvG;AACA,MAAI,GAAG,4BAA4B,UAAa,WAAW,2BAA2B,MAAM;AACxF,OAAG,0BAA0B,WAAW;AAAA,EAC5C;AACA,SAAO;AACX;AAYO,SAAS,oBAAoB,UAAU,CAAC,GAAG;AAC9C,QAAM,OAAO,OAAO,QAAQ,kBAAkB;AAC9C,QAAM,aAAa,OAAO,QAAQ,wBAAwB;AAC1D,QAAM,eAAe,OAAO,QAAQ,0BAA0B;AAC9D,QAAM,WAAW,OAAO,QAAQ,sBAAsB;AACtD,SAAO;AAAA,IACH,SAAS,QAAQ,0BAA0B,SAAS,OAAO,SAAS,IAAI,KAAK,OAAO;AAAA,IACpF,MAAM,OAAO,SAAS,IAAI,KAAK,OAAO,IAAI,OAAO;AAAA,IACjD,YAAY,OAAO,SAAS,UAAU,KAAK,cAAc,MAAS,aAAa;AAAA,IAC/E,cACI,OAAO,SAAS,YAAY,KAAK,eAAe,KAAK,eAAe,IAC9D,eACA;AAAA,IACV,UAAU,OAAO,SAAS,QAAQ,KAAK,YAAY,IAAI,WAAW;AAAA,EACtE;AACJ;AAUO,SAAS,uBAAuB,KAAK,MAAM;AAC9C,QAAM,UAAU,IAAI,WAAW;AAC/B,MAAI,CAAC,QAAQ,CAAC,OAAO,SAAS,KAAK,SAAS,KAAK,KAAK,aAAa,IAAI,cAAc;AACjF,WAAO,EAAE,MAAM,IAAI,MAAM,cAAc,OAAO,WAAW,MAAM,aAAa,KAAK;AAAA,EACrF;AACA,QAAM,SAAS,IAAI,QAAQ,KAAK,YAAY,IAAI;AAChD,QAAM,OAAO,KAAK,IAAI,SAAS,MAAM;AACrC,SAAO,EAAE,MAAM,cAAc,MAAM,WAAW,KAAK,UAAU;AACjE;AAOO,SAAS,mBAAmB,MAAM,MAAM,oBAAI,KAAK,GAAG;AACvD,QAAM,KAAK,KAAK,IAAI,GAAG,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,KAAK;AAC3D,SAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,EAAE,EAAE,YAAY;AACpD;AAOO,SAAS,yBAAyB,OAAO,MAAM,oBAAI,KAAK,GAAG;AAC9D,QAAM,KAAK,KAAK,IAAI,GAAG,OAAO,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK;AACvD,SAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,EAAE,EAAE,YAAY;AACpD;AAeA,eAAsB,uBAAuB,IAAI,cAAc,QAAQ,OAAO,CAAC,GAAG;AAC9E,QAAM,YAAY,KAAK,IAAI,GAAG,OAAO,KAAK,SAAS,KAAK,mBAAmB;AAC3E,QAAM,SAAS,OAAO,KAAK,WAAW,aAAa,KAAK,SAAS,MAAM;AACvE,QAAM,OACF,KAAK,QAAQ,QAAQ,OAAO,KAAK,IAAI,EAAE,KAAK,IAAI,OAAO,KAAK,IAAI,EAAE,KAAK,IAAI;AAC/E,MAAI,QAAQ;AACZ,aAAS;AACL,QAAI,OAAO,EAAG;AACd,QAAI,IAAI,GAAG,YAAY,EAAE,MAAM,gBAAgB,KAAK,MAAM;AAC1D,QAAI,KAAM,KAAI,EAAE,MAAM,EAAE,KAAK,CAAC;AAC9B,UAAM,OAAO,MAAM,EAAE,OAAO,IAAI,EAAE,MAAM,SAAS;AACjD,QAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,KAAK,WAAW,EAAG;AAC/C,UAAM,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,OAAO,OAAO;AAChD,QAAI,CAAC,IAAI,OAAQ;AACjB,UAAM,UAAU,MAAM,GAAG,YAAY,EAAE,QAAQ,MAAM,GAAG,EAAE,OAAO;AACjE,aAAS,OAAO,OAAO,KAAK,IAAI;AAChC,QAAI,KAAK,SAAS,UAAW;AAAA,EACjC;AACA,SAAO;AACX;AAgBA,eAAsB,mBAAmB,SAAS,UAAU,CAAC,GAAG;AAC5D,2BAAyB,OAAO;AAChC,QAAM,MAAM,oBAAoB,QAAQ,YAAY;AACpD,MAAI,CAAC,IAAI,SAAS;AACd,WAAO,EAAE,SAAS,MAAM,QAAQ,WAAW;AAAA,EAC/C;AAEA,QAAM,YAAY,QAAQ,aAAa,QAAQ,kBAAkB;AACjE,QAAM,eAAe,QAAQ,gBAAgB,kBAAkB,SAAS,EAAE;AAC1E,QAAM,MAAM,QAAQ,OAAO,oBAAI,KAAK;AACpC,QAAM,WAAW,cAAc,OAAO;AACtC,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,OAAO,MAAM,SAAS,QAAQ;AACpC,QAAM,YAAY,uBAAuB,KAAK,IAAI;AAClD,QAAM,SAAS,mBAAmB,UAAU,MAAM,GAAG;AAErD,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,OAAO,MAAM,UAAU,SAAS,QAAQ;AAAA,IAC1C,QAAQ,MAAM,QAAQ,SAAS,MAAM;AAAA,EACzC,CAAC;AAED,MAAI,iBAAiB;AACrB,MAAI,QAAQ,MAAM,OAAO,QAAQ,OAAO,YAAY;AAChD,qBAAiB,MAAM,uBAAuB,QAAQ,IAAI,cAAc,QAAQ;AAAA,MAC5E,QAAQ,MAAM,QAAQ,SAAS,MAAM;AAAA,IACzC,CAAC;AAAA,EACL;AAEA,QAAM,YAAY,0BAA0B,QAAQ,YAAY;AAChE,QAAM,kBAAkB,CAAC;AACzB,MAAI,QAAQ,MAAM,OAAO,QAAQ,OAAO,YAAY;AAChD,eAAW,QAAQ,WAAW;AAC1B,YAAM,aAAa,yBAAyB,KAAK,OAAO,GAAG;AAC3D,YAAM,UAAU,MAAM,uBAAuB,QAAQ,IAAI,cAAc,YAAY;AAAA,QAC/E,MAAM,KAAK;AAAA,QACX,QAAQ,MAAM,QAAQ,SAAS,MAAM;AAAA,MACzC,CAAC;AACD,UAAI,UAAU,GAAG;AACb,wBAAgB,KAAK,EAAE,MAAM,KAAK,MAAM,OAAO,KAAK,OAAO,QAAQ,YAAY,QAAQ,CAAC;AAAA,MAC5F;AACA,wBAAkB;AAAA,IACtB;AAAA,EACJ;AAEA,QAAM,UAAU;AAAA,IACZ,SAAS;AAAA,IACT;AAAA,IACA,MAAM,UAAU;AAAA,IAChB,gBAAgB,IAAI;AAAA,IACpB,cAAc,UAAU;AAAA,IACxB,WAAW,UAAU;AAAA,IACrB;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX;AAAA,EACJ;AACA,UAAQ,QAAQ;AAAA,IACZ,4BAA4B,MAAM,SAAS,UAAU,KAAK,QAAQ,CAAC,CAAC,GAC7D,UAAU,eAAe,WAAW,UAAU,YAAY,KAAK,QAAQ,CAAC,CAAC,YAAY,EAAE,YAC9E,cAAc,MACzB,gBAAgB,SACX,cAAc,gBAAgB,IAAI,CAAC,MAAM,GAAG,EAAE,IAAI,IAAI,EAAE,OAAO,IAAI,EAAE,KAAK,GAAG,EAAE,KAAK,GAAG,CAAC,KACxF,MACN,cAAc,MAAM,UAAU,CAAC,eAAe,MAAM,WAAW,CAAC;AAAA,EACxE;AACA,SAAO;AACX;AASA,eAAsB,wBAAwB,SAAS,UAAU,CAAC,GAAG;AACjE,2BAAyB,OAAO;AAChC,QAAM,MAAM,oBAAoB,QAAQ,YAAY;AACpD,MAAI,CAAC,IAAI,QAAS,QAAO;AAEzB,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,OAAO,OAAO,QAAQ,sBAAsB,KAAK;AACvD,MAAI,CAAC,QAAQ,SAAS,QAAQ,MAAM,OAAO,IAAI,WAAY,QAAO;AAClE,MAAI,QAAQ,yBAA0B,QAAO;AAE7C,UAAQ,yBAAyB;AACjC,UAAQ,2BAA2B;AACnC,MAAI;AACA,WAAO,MAAM,mBAAmB,SAAS,OAAO;AAAA,EACpD,SAAS,KAAK;AACV,YAAQ,QAAQ,OAAO,mCAAmC,KAAK,WAAW,OAAO,GAAG,CAAC,EAAE;AACvF,WAAO,EAAE,SAAS,MAAM,QAAQ,SAAS,OAAO,KAAK,WAAW,OAAO,GAAG,EAAE;AAAA,EAChF,UAAE;AACE,YAAQ,2BAA2B;AAAA,EACvC;AACJ;;;AClRO,IAAM,yBAAN,cAAqC,aAAa;AAAA,EACrD,OAAO,uBAAuB;AAAA;AAAA;AAAA;AAAA,EAK9B,MAAM,MAAM;AACR,6BAAyB,KAAK,OAAO;AACrC,UAAM,UAAU,MAAM,mBAAmB,KAAK,SAAS,EAAE,OAAO,KAAK,CAAC;AACtE,WAAO,EAAE,SAAS,MAAM,QAAQ;AAAA,EACpC;AACJ;;;ACEO,IAAM,gBAAN,MAAM,eAAc;AAAA;AAAA;AAAA;AAAA,EAIvB,YAAY,SAAS;AACjB,SAAK,MAAM,CAAC;AACZ,QAAI,SAAS;AACT,WAAK,QAAQ,OAAO;AAAA,IACxB;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,gBAAgB;AACnB,WAAO,IAAI,eAAc,EACpB,IAAI,QAAQ,QAAQ,EACpB,IAAI,iBAAiB,iBAAiB,EACtC,IAAI,gBAAgB,gBAAgB,EACpC,IAAI,cAAc,cAAc,EAChC,IAAI,QAAQ,cAAc,EAC1B,IAAI,aAAa,SAAS,EAC1B,IAAI,cAAc,cAAc,EAEhC,IAAI,QAAQ,cAAc,EAC1B,IAAI,eAAe,eAAe,EAClC,IAAI,SAAS,eAAe,EAC5B,IAAI,iBAAiB,iBAAiB,EACtC,IAAI,WAAW,iBAAiB,EAChC,IAAI,aAAa,aAAa,EAC9B,IAAI,cAAc,cAAc,EAChC,IAAI,WAAW,WAAW,EAC1B,IAAI,mBAAmB,mBAAmB,EAC1C,IAAI,kBAAkB,mBAAmB,EACzC,IAAI,sBAAsB,sBAAsB;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAI,UAAU,WAAW;AACrB,SAAK,IAAI,QAAQ,IAAI;AACrB,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAQ,SAAS;AACb,eAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AACjD,WAAK,IAAI,MAAM,KAAK;AAAA,IACxB;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAI,UAAU;AACV,WAAO,KAAK,IAAI,QAAQ;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,aAAa,UAAU;AACnB,UAAM,YAAY,WAAW,KAAK,IAAI,QAAQ,IAAI;AAClD,QAAI,CAAC,WAAW;AACZ,YAAM,YAAY,KAAK,mBAAmB,EAAE,KAAK,IAAI,KAAK;AAC1D,YAAM,IAAI;AAAA,QACN,iBAAiB,YAAY,EAAE,kCAAkC,SAAS;AAAA,MAC9E;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,kBAAkB,SAAS,YAAY,CAAC,GAAG;AAC7C,UAAM,eAAe,OAAO,UAAU,SAAS,WAAW,UAAU,KAAK,KAAK,IAAI,UAAU;AAC5F,UAAM,UAAU,QAAQ,OAAO,IAAI,QAAQ,QAAQ;AACnD,UAAM,UAAU,OAAO,YAAY,WAAW,QAAQ,KAAK,IAAI;AAC/D,UAAM,OAAO,gBAAgB;AAC7B,QAAI,CAAC,MAAM;AACP,YAAM,IAAI,WAAW,yDAAyD;AAAA,IAClF;AACA,UAAM,YAAY,KAAK,aAAa,IAAI;AACxC,WAAO,UAAU,cAAc,SAAS,EAAE,GAAG,WAAW,KAAK,CAAC;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,qBAAqB;AACjB,WAAO,OAAO,KAAK,KAAK,GAAG,EAAE,KAAK;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW;AACP,WAAO,EAAE,GAAG,KAAK,IAAI;AAAA,EACzB;AACJ;;;ACxJO,IAAM,qBAAqB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ;AAaO,SAAS,sBAAsB,OAAO;AACzC,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,MAAM,QAAQ,KAAK,GAAG;AACtB,UAAMC,OAAM,MAAM,IAAI,CAAC,MAAM,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO;AAC7D,WAAOA,KAAI,SAASA,OAAM;AAAA,EAC9B;AACA,QAAM,MAAM,OAAO,KAAK,EACnB,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,OAAO;AACnB,SAAO,IAAI,SAAS,MAAM;AAC9B;AASO,SAAS,kCAAkC,OAAO;AACrD,QAAM,MAAM,oBAAI,IAAI,CAAC,GAAG,oBAAoB,GAAI,SAAS,CAAC,CAAE,CAAC;AAC7D,SAAO,MAAM,KAAK,GAAG,EAAE,KAAK;AAChC;;;AChDA,SAAS,KAAK,OAAO;AACjB,MAAI,SAAS,QAAQ,UAAU,GAAI,QAAO;AAC1C,QAAM,IAAI,iBAAiB,OAAO,MAAM,QAAQ,IAAI,IAAI,KAAK,KAAK,EAAE,QAAQ;AAC5E,SAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AACpC;AAGO,SAAS,kBAAkB,KAAK;AACnC,QAAM,UAAU,KAAK,KAAK,WAAW;AACrC,QAAM,UAAU,KAAK,KAAK,QAAQ;AAClC,MAAI,WAAW,KAAM,QAAO;AAC5B,MAAI,WAAW,KAAM,QAAO;AAC5B,SAAO,KAAK,IAAI,SAAS,OAAO;AACpC;AAEO,SAAS,WAAW,KAAK;AAC5B,SAAO,kBAAkB,GAAG,KAAK;AACrC;AASO,SAAS,uBAAuB,GAAG,GAAG;AACzC,QAAM,OAAO,kBAAkB,CAAC;AAChC,QAAM,OAAO,kBAAkB,CAAC;AAChC,QAAM,OAAO,QAAQ;AACrB,QAAM,OAAO,QAAQ;AACrB,MAAI,SAAS,KAAM,QAAO,OAAO,KAAK;AACtC,MAAI,QAAQ,SAAS,KAAM,QAAO,OAAO;AAEzC,QAAM,OAAO,OAAO,GAAG,QAAQ;AAC/B,QAAM,OAAO,OAAO,GAAG,QAAQ;AAC/B,QAAM,KAAK,OAAO,SAAS,IAAI,IAAI,OAAO;AAC1C,QAAM,KAAK,OAAO,SAAS,IAAI,IAAI,OAAO;AAC1C,MAAI,OAAO,GAAI,QAAO,KAAK;AAE3B,QAAM,QAAQ,KAAK,GAAG,YAAY;AAClC,QAAM,QAAQ,KAAK,GAAG,YAAY;AAClC,MAAK,SAAS,UAAW,SAAS,MAAO,QAAO,SAAS,OAAO,KAAK;AACrE,MAAI,SAAS,QAAQ,SAAS,QAAQ,UAAU,MAAO,QAAO,QAAQ;AAEtE,QAAM,WAAW,KAAK,GAAG,UAAU,KAAK;AACxC,QAAM,WAAW,KAAK,GAAG,UAAU,KAAK;AACxC,MAAI,aAAa,SAAU,QAAO,WAAW;AAC7C,SAAO;AACX;AASO,SAAS,gBAAgB,OAAO;AACnC,SAAO,MACF;AAAA,IACG;AAAA,EACJ,EACC;AAAA,IACG;AAAA,EACJ,EACC,QAAQ,CAAC,EAAE,QAAQ,YAAY,OAAO,MAAM,CAAC,CAAC,EAC9C,WAAW,sDAAsD,EACjE,QAAQ,CAAC,EAAE,QAAQ,gBAAgB,OAAO,MAAM,GAAG,EAAE,QAAQ,cAAc,OAAO,MAAM,CAAC,CAAC;AACnG;;;AClFA,IAAAC,6BAAsB;AAQtB,IAAM,wBAAwB;AAQ9B,SAAS,UAAU,OAAO,CAAC,GAAG;AAC1B,SAAO,KAAK,OAAO,CAAC,MAAM,OAAO,MAAM,YAAY,EAAE,SAAS,CAAC;AACnE;AAQA,SAAS,qBAAqB,MAAM;AAChC,SAAO,GAAG,KAAK,IAAI,IAAI,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,KAAK,IAAI,KAAK,EAAE;AACjF;AASA,SAAS,kBAAkB,SAAS;AAChC,MAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,MAAI,QAAQ,UAAU,WAAY,QAAO;AACzC,QAAM,QAAQ,OAAO,QAAQ,KAAK;AAClC,QAAM,QAAQ,OAAO,QAAQ,KAAK;AAClC,SAAO,OAAO,SAAS,KAAK,KAAK,OAAO,SAAS,KAAK,KAAK,QAAQ;AACvE;AASA,SAAS,mBAAmB,SAAS,gBAAgB;AACjD,QAAM,MAAM,QAAQ,SAAS,GAAG,QAAQ,MAAM,MAAO,iBAAiB,GAAG,cAAc,MAAM;AAC7F,QAAM,QAAQ,OAAO,QAAQ,YAAY,YAAY,QAAQ,UAAU,GAAG,QAAQ,OAAO,MAAM;AAC/F,SAAO,GAAG,GAAG,GAAG,KAAK,GAAG,QAAQ,KAAK,IAAI,QAAQ,KAAK;AAC1D;AAYA,SAAS,wBAAwB,SAAS,QAAQ,SAAS;AACvD,MAAI,CAAC,WAAW,OAAO,YAAY,SAAU;AAC7C,QAAM,OAAO,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU;AACrE,MAAI,CAAC,KAAM;AACX,QAAM,QAAQ,OAAO,QAAQ,UAAU,WAAW,QAAQ,MAAM,YAAY,IAAI;AAChF,QAAM,OAAO,UAAU,MAAM,KAAK,IAAI;AACtC,QAAM,SAAS,QAAQ;AACvB,UAAQ,OAAO;AAAA,IACX,KAAK;AAAA,IACL,KAAK;AACD,aAAO,QAAQ,IAAI;AACnB;AAAA,IACJ,KAAK;AAAA,IACL,KAAK;AACD,aAAO,OAAO,IAAI;AAClB;AAAA,IACJ,KAAK;AACD,aAAO,QAAQ,IAAI;AACnB;AAAA,IACJ,KAAK;AAAA,IACL;AACI,aAAO,OAAO,IAAI;AAAA,EAC1B;AACJ;AAWA,SAAS,cAAc,YAAY,SAAS;AACxC,QAAM,oBAAoB,MAAM,QAAQ,QAAQ,QAAQ,IAAI,CAAC,GAAG,QAAQ,QAAQ,IAAI,CAAC;AACrF,SAAO,CAAC,GAAG,mBAAmB,YAAY,GAAG,OAAO;AACxD;AAQA,SAAS,sBAAsB,SAAS;AACpC,SAAO,QAAQ,kBAAkB,QAAQ,QAAQ,MAAM,OAAO,KAAK;AACvE;AAUA,SAAS,0BAA0B,SAAS,SAAS;AACjD,MAAI,CAAC,QAAQ,YAAa;AAC1B,QAAM,UAAU,sBAAsB,SAAS,QAAQ,WAAW;AAClE,QAAM,aAAa,QAAQ,QAAQ,MAAM,kBAAkB;AAC3D,QAAM,cAAc,eAAe,SAAY,OAAO,CAAC,CAAC;AACxD,UAAQ,OAAO;AAAA,IACX,0BAA0B,OAAO,MAC5B,cAAc,KAAK;AAAA,EAC5B;AACJ;AASA,SAAS,wBAAwB;AAC7B,MAAI,QAAQ,QAAQ,QAAQ;AAC5B,SAAO;AAAA,IACH,KAAK,IAAI;AACL,cAAQ,MAAM,KAAK,IAAI,MAAM;AAAA,MAAC,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAC/C,aAAO;AAAA,IACX;AAAA,IACA,QAAQ;AACJ,aAAO,MAAM,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC/B;AAAA,EACJ;AACJ;AAmCA,eAAsB,kBAAkB,SAAS,SAAS;AACtD,QAAM,UAAU,UAAU,CAAC,eAAe,eAAe,GAAI,QAAQ,QAAQ,CAAC,CAAE,CAAC;AACjF,QAAM,WAAW,cAAc,QAAQ,YAAY,OAAO;AAC1D,QAAM,YAAQ,kCAAM,QAAQ,UAAU,UAAU;AAAA,IAC5C,KAAK,QAAQ,OAAO,QAAQ,IAAI;AAAA,IAChC,OAAO,CAAC,UAAU,QAAQ,QAAQ,KAAK;AAAA,IACvC,KAAK;AAAA,MACD,GAAG,QAAQ;AAAA,MACX,SAAS,QAAQ,KAAK;AAAA,MACtB,WAAW,QAAQ,KAAK;AAAA,MACxB,WAAW,QAAQ,KAAK,QAAQ;AAAA,IACpC;AAAA,EACJ,CAAC;AAED,4BAA0B,SAAS,OAAO;AAE1C,QAAM,SAAS,qBAAqB,QAAQ,IAAI;AAChD,QAAM,aAAa,sBAAsB,OAAO;AAChD,QAAM,gBAAgB,sBAAsB;AAE5C,QAAM,QAAQ;AAAA,IACV,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,iBAAiB;AAAA,EACrB;AAQA,QAAM,gBAAgB,CAAC,SAAS;AAC5B,UAAM,UAAU,OAAO,SAAS,WAAW,KAAK,MAAM,GAAG,qBAAqB,IAAI;AAClF,QAAI,CAAC,QAAS;AACd,kBAAc,KAAK,YAAY;AAC3B,YAAM,KAAK,QAAQ;AACnB,UAAI,IAAI;AACJ,YAAI;AACA,gBAAM,GAAG,UAAU,EAAE,MAAM,EAAE,IAAI,QAAQ,KAAK,GAAG,CAAC,EAAE,OAAO,EAAE,UAAU,QAAQ,CAAC;AAAA,QACpF,SAAS,OAAO;AACZ,kBAAQ,OAAO;AAAA,YACX,8CAA8C,QAAQ,KAAK,EAAE,KAAK,OAAO,WAAW,OAAO,KAAK,CAAC;AAAA,UACrG;AAAA,QACJ;AAAA,MACJ;AACA,UAAI,QAAQ,YAAY;AACpB,YAAI;AACA,gBAAM,QAAQ,WAAW,OAAO;AAAA,QACpC,SAAS,OAAO;AACZ,kBAAQ,OAAO;AAAA,YACX,mDAAmD,QAAQ,KAAK,EAAE,KAAK,OAAO,WAAW,OAAO,KAAK,CAAC;AAAA,UAC1G;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ,CAAC;AAAA,EACL;AAEA,QAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AAChC,UAAM,OAAO,OAAO,KAAK;AACzB,UAAM,UAAU;AAChB,QAAI,KAAK,KAAK,GAAG;AACb,cAAQ,OAAO,OAAO,UAAU,MAAM,KAAK,KAAK,QAAQ,CAAC,EAAE;AAAA,IAC/D;AAAA,EACJ,CAAC;AACD,QAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AAChC,UAAM,OAAO,OAAO,KAAK;AACzB,UAAM,UAAU;AAChB,QAAI,KAAK,KAAK,GAAG;AACb,cAAQ,OAAO,OAAO,UAAU,MAAM,KAAK,KAAK,QAAQ,CAAC,EAAE;AAAA,IAC/D;AAAA,EACJ,CAAC;AAED,QAAM,GAAG,WAAW,CAAC,YAAY;AAC7B,QAAI,WAAW,OAAO,YAAY,YAAY,wBAAwB,SAAS;AAC3E,YAAM,eAAe,QAAQ;AAC7B;AAAA,IACJ;AAEA,QAAI,WAAW,OAAO,YAAY,UAAU;AACxC,YAAM,QAAQ,OAAO,QAAQ,UAAU,WAAW,QAAQ,MAAM,YAAY,IAAI;AAChF,UAAI,UAAU,WAAW,UAAU,SAAS;AACxC,cAAM,kBAAkB;AAAA,MAC5B;AAAA,IACJ;AAEA,qBAAiB,SAAS,QAAQ,MAAM,SAAS,QAAQ,WAAW;AAEpE,QAAI;AACA,cAAQ,oBAAoB,OAAO;AAAA,IACvC,SAAS,GAAG;AACR,cAAQ,OAAO,OAAO,qCAAqC,GAAG,WAAW,OAAO,CAAC,CAAC,EAAE;AAAA,IACxF;AAEA,QAAI,kBAAkB,OAAO,GAAG;AAC5B,cAAQ,OAAO,SAAS,QAAQ,WAAW,YAAY;AAAA,QACnD,QAAQ,QAAQ,UAAU;AAAA,QAC1B,OAAO,OAAO,QAAQ,KAAK;AAAA,QAC3B,OAAO,OAAO,QAAQ,KAAK;AAAA,MAC/B,CAAC;AACD,oBAAc,mBAAmB,SAAS,MAAM,CAAC;AACjD;AAAA,IACJ;AAEA,4BAAwB,SAAS,QAAQ,OAAO;AAAA,EACpD,CAAC;AAED,SAAO,MAAM,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC1C,UAAM,GAAG,SAAS,CAAC,UAAU,OAAO,KAAK,CAAC;AAC1C,UAAM,GAAG,SAAS,CAAC,UAAU,WAAW;AACpC,YAAM,YAAY;AACd,cAAM,iBAAiB,OAAO;AAC9B,cAAM,cAAc,MAAM;AAC1B,gBAAQ;AAAA,UACJ;AAAA,UACA;AAAA,UACA,QAAQ,MAAM,OAAO,KAAK;AAAA,UAC1B,QAAQ,MAAM,OAAO,KAAK;AAAA,UAC1B,cAAc,MAAM;AAAA,UACpB,iBAAiB,MAAM;AAAA,QAC3B,CAAC;AAAA,MACL,GAAG;AAAA,IACP,CAAC;AAAA,EACL,CAAC;AACL;;;AhCnRA,IAAM,0BAA0B;AAWzB,SAAS,4BAA4B,SAAS;AACjD,MAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,QAAM,OAAO,QAAQ;AACrB,SAAO,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,IAAI,IAAI,OAAO;AAC7E;AAyGO,IAAM,uBAAuB,cAAc,cAAc;AAQhE,SAASC,OAAM,SAAS;AACpB,QAAM,KAAK,QAAQ;AACnB,MAAI,CAAC,IAAI;AACL,UAAM,IAAI,MAAM,iFAAiF;AAAA,EACrG;AACA,SAAO;AACX;AAYA,SAAS,kBAAkB,UAAU;AACjC,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,oBAAoB,cAAe,QAAO;AAC9C,SAAO,IAAI,cAAc,EAAE,QAAQ,QAAQ;AAC/C;AAaA,eAAsB,gBAAgB,SAAS,cAAc,YAAY,SAAS,cAAc,KAAQ;AACpG,SAAO,YAAY,SAAS;AAAA,IACxB;AAAA,IACA,MAAM;AAAA,IACN,QAAQ,EAAE,YAAY;AAAA,IACtB,UAAU;AAAA,IACV;AAAA,EACJ,CAAC;AACL;AAqBA,eAAsB,8BAA8B,SAAS,YAAY,sBAAsB;AAC3F,MAAI,CAAC,sBAAsB,KAAM;AACjC,QAAM,KAAK,SAAS;AACpB,MAAI,CAAC,GAAI;AACT,QAAM,MAAM,CAAC,GAAG,qBAAqB,KAAK,CAAC;AAC3C,MAAI;AACJ,MAAI;AACA,UAAM,OAAO,MAAM,GAAG,UAAU,EAAE,QAAQ,MAAM,GAAG,EAAE,OAAO,IAAI;AAChE,YAAQ,IAAI,KAAK,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAAA,EACtE,QAAQ;AACJ;AAAA,EACJ;AACA,aAAW,CAAC,IAAI,IAAI,KAAK,sBAAsB;AAC3C,QAAI,MAAM,IAAI,EAAE,EAAG;AACnB,YAAQ,QAAQ,OAAO,qBAAqB,EAAE,iCAA4B;AAC1E,QAAI,OAAO,KAAK,gBAAgB,YAAY;AACxC,UAAI;AACA,cAAM,KAAK,YAAY,CAAC;AAAA,MAC5B,SAAS,OAAO;AACZ,gBAAQ,QAAQ,OAAO,oCAAoC,KAAK;AAAA,MACpE;AAAA,IACJ;AAAA,EACJ;AACJ;AAEA,eAAe,uBAAuB,SAAS,sBAAsB,aAAa;AAC9E,UAAQ,OAAO,OAAO,qBAAqB,qBAAqB,IAAI,0BAA0B;AAC9F,aAAW,CAAC,EAAE,YAAY,KAAK,sBAAsB;AACjD,QAAI,OAAO,aAAa,gBAAgB,YAAY;AAChD,UAAI;AACA,cAAM,aAAa,YAAY,WAAW;AAAA,MAC9C,SAAS,OAAO;AACZ,gBAAQ,OAAO,OAAO,oCAAoC,KAAK;AAAA,MACnE;AAAA,IACJ;AAAA,EACJ;AACA,UAAQ,QAAQ,KAAK,QAAQ,WAAW;AAC5C;AAmBA,eAAe,mBAAmB,SAAS,YAAY,cAAc,KAAK,UAAU,sBAAsB;AACtG,QAAM,KAAKA,OAAM,OAAO;AACxB,QAAM,WAAW,IAAI;AACrB,QAAM,YAAY,SAAS,IAAI,QAAQ;AACvC,MAAI,CAAC,WAAW;AACZ,UAAM,MAAM,EAAE,SAAS,iBAAiB,QAAQ,IAAI;AACpD,UAAM,GAAG,YAAY,EAAE;AAAA,MACnB,8BAA8B,KAAK;AAAA,QAC/B,cAAc,oBAAI,KAAK;AAAA,QACvB,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,mBAAmB,GAAG,GAAG,IAAI;AAAA,QAC7B,QAAQ,aAAa,IAAI,MAAM;AAAA,QAC/B,SAAS,aAAa,GAAG;AAAA,MAC7B,CAAC;AAAA,IACL;AACA,QAAI,IAAI,UAAU;AACd,YAAM,GAAG,UAAU,EAAE,MAAM,EAAE,IAAI,IAAI,GAAG,CAAC,EAAE,OAAO;AAAA,QAC9C,YAAY;AAAA,QACZ,cAAc,oBAAI,KAAK;AAAA,QACvB,SAAS;AAAA,QACT,SAAS,aAAa,GAAG;AAAA,QACzB,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,mBAAmB,GAAG,GAAG,IAAI;AAAA,QAC7B,UAAU;AAAA,MACd,CAAC;AAAA,IACL,OAAO;AACH,YAAM,GAAG,UAAU,EAAE,MAAM,EAAE,IAAI,IAAI,GAAG,CAAC,EAAE,OAAO;AAAA,IACtD;AACA,WAAO,EAAE,qBAAqB,OAAO,iBAAiB,EAAE;AAAA,EAC5D;AAEA,MAAI,UAAU;AACd,MAAI,UAAU;AACd,MAAI,eAAe;AACnB,MAAI;AACA,UAAM,aACF,OAAO,QAAQ,QAAQ,UAAU,aAC3B,QAAQ,OAAO,MAAM,gBAAgB,GAAG,CAAC,IACzC,QAAQ;AAClB,UAAM,cACF,cAAc,eAAe,QAAQ,SAAS,EAAE,GAAG,SAAS,QAAQ,WAAW,IAAI;AACvF,mBAAe,IAAI,UAAU,aAAa,GAAG;AAC7C,yBAAqB,IAAI,IAAI,IAAI,YAAY;AAC7C,UAAM,iBAAiB,2BAA2B,aAAa,YAAY,IAAI,EAAE;AACjF,UAAM,YAAY,MAAM,aAAa,IAAI,cAAc;AACvD,cAAU,CAAC,CAAC,WAAW;AACvB,cAAU,WAAW,WAAW;AAAA,EACpC,SAAS,OAAO;AACZ,cAAU;AACV,cAAU;AAAA,MACN,SAAS,OAAO,WAAW,OAAO,KAAK;AAAA,MACvC,MAAM,OAAO,QAAQ;AAAA,MACrB,OAAO,OAAO,SAAS;AAAA,IAC3B;AAAA,EACJ,UAAE;AACE,yBAAqB,OAAO,IAAI,EAAE;AAAA,EACtC;AAEA,QAAM,aACF,WAAW,WAAW,OAAO,YAAY,YAAY,QAAQ,eAAe;AAEhF,QAAM,GAAG,YAAY,EAAE;AAAA,IACnB,8BAA8B,KAAK;AAAA,MAC/B,cAAc,oBAAI,KAAK;AAAA,MACvB;AAAA,MACA,QAAQ,aAAa,WAAW,UAAU,cAAc;AAAA,MACxD,mBAAmB,GAAG,GAAG,IAAI;AAAA,MAC7B,QAAQ,aAAa,IAAI,MAAM;AAAA,MAC/B,SAAS,aAAa,OAAO;AAAA,IACjC,CAAC;AAAA,EACL;AACA,MAAI,CAAC,SAAS;AACV,UAAM,SAAS,OAAO,SAAS,QAAQ,MAAM,QAAQ,KAAK,OAAO;AACjE,UAAM,YAAY,OAAO,SAAS,QAAQ,MAAM,OAAO,KAAK,OAAO;AACnE,UAAM,yBAAyB;AAAA,MAC3B;AAAA,MACA;AAAA,MACA,aAAa,OAAO,QAAQ,MAAM,OAAO,CAAC;AAAA,MAC1C,YAAY,UAAU,QAAQ,MAAM,OAAO,CAAC;AAAA,MAC5C,SAAS,OAAO,IAAI,EAAE,EAAE,QAAQ,MAAM,OAAO,CAAC;AAAA,IAClD,EAAE,KAAK,GAAG;AACV,UAAM,eAAe,WAAW,OAAO,YAAY,YAAY,QAAQ,eACjE,QAAQ,eACR;AACN,qBAAiB,SAAS,KAAK;AAAA,MAC3B,OAAO;AAAA,MACP,SAAS,wBAAwB,IAAI,IAAI,OAAO,IAAI,EAAE,oCAAoC,YAAY;AAAA,MACtG,SAAS;AAAA,IACb,CAAC;AAAA,EACL;AAIA,MAAI,YAAY;AACZ,UAAM,mBAAmB,4BAA4B,OAAO,KAAK,IAAI;AACrE,UAAM,kBACF,QAAQ,YAAY,OACd,QAAQ,WACR,EAAE,QAAQ,MAAM,WAAU,oBAAI,KAAK,GAAE,YAAY,GAAG,SAAS,SAAS;AAChF,UAAM,GAAG,UAAU,EAAE,MAAM,EAAE,IAAI,IAAI,GAAG,CAAC,EAAE,OAAO;AAAA,MAC9C,YAAY;AAAA,MACZ,cAAc,oBAAI,KAAK;AAAA,MACvB,SAAS;AAAA,MACT,SAAS,aAAa,OAAO;AAAA,MAC7B,QAAQ,aAAa,gBAAgB;AAAA,MACrC,UAAU,aAAa,eAAe;AAAA,MACtC,QAAQ;AAAA,MACR,mBAAmB,GAAG,GAAG,IAAI;AAAA,MAC7B,UAAU;AAAA,MACV,cAAc;AAAA,MACd,aAAa;AAAA,MACb,iBAAiB;AAAA,IACrB,CAAC;AAAA,EACL,WAAW,IAAI,UAAU;AACrB,QAAI,SAAS;AACT,UAAI,YAAY;AAChB,UAAI;AACA,oBAAY,cAAc,IAAI,UAAU,oBAAI,KAAK,CAAC;AAAA,MACtD,SAAS,GAAG;AACR,gBAAQ,QAAQ,OAAO,gDAAgD,IAAI,EAAE,KAAK,GAAG,WAAW,OAAO,CAAC,CAAC,EAAE;AAAA,MAC/G;AACA,YAAM,mBAAmB,4BAA4B,OAAO;AAC5D,YAAM,GAAG,UAAU,EAAE,MAAM,EAAE,IAAI,IAAI,GAAG,CAAC,EAAE,OAAO;AAAA,QAC9C,YAAY;AAAA,QACZ,cAAc,oBAAI,KAAK;AAAA,QACvB;AAAA,QACA,SAAS,aAAa,OAAO;AAAA,QAC7B,UAAU;AAAA,QACV,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,mBAAmB,GAAG,GAAG,IAAI;AAAA,QAC7B,aAAa;AAAA,QACb,GAAI,mBAAmB,EAAE,QAAQ,aAAa,gBAAgB,EAAE,IAAI,CAAC;AAAA;AAAA,QAErE,cAAc;AAAA,QACd,aAAa;AAAA,QACb,iBAAiB;AAAA,MACrB,CAAC;AAAA,IACL,OAAO;AACH,YAAM,GAAG,UAAU,EAAE,MAAM,EAAE,IAAI,IAAI,GAAG,CAAC,EAAE,OAAO;AAAA,QAC9C,YAAY;AAAA,QACZ,cAAc,oBAAI,KAAK;AAAA,QACvB;AAAA,QACA,SAAS,aAAa,OAAO;AAAA,QAC7B,QAAQ;AAAA,QACR,mBAAmB,GAAG,GAAG,IAAI;AAAA,QAC7B,UAAU;AAAA,QACV,UAAU;AAAA,MACd,CAAC;AAAA,IACL;AAAA,EACJ,OAAO;AACH,UAAM,GAAG,UAAU,EAAE,MAAM,EAAE,IAAI,IAAI,GAAG,CAAC,EAAE,OAAO;AAAA,EACtD;AAEA,QAAM,sBAAsB,CAAC,EAAE,WAAW,OAAO,YAAY,YAAY,QAAQ,eAAe;AAChG,QAAM,kBAAkB,sBAAsB,OAAO,QAAQ,eAAe,GAAM,IAAI;AACtF,4BAA0B,SAAS,YAAY;AAC/C,SAAO,EAAE,qBAAqB,gBAAgB;AAClD;AAEA,SAAS,0BAA0B,SAAS,cAAc;AACtD,OAAK,wBAAwB,SAAS;AAAA,IAClC;AAAA,IACA,WAAW,QAAQ;AAAA,EACvB,CAAC,EAAE,MAAM,CAAC,QAAQ;AACd,YAAQ,QAAQ,OAAO,qBAAqB,KAAK,WAAW,OAAO,GAAG,CAAC,EAAE;AAAA,EAC7E,CAAC;AACL;AAqBA,eAAe,sBACX,SACA,YACA,cACA,UACA,WACA,WACA,gBACF;AACE,QAAM,KAAKA,OAAM,OAAO;AAIxB,MAAI,QAAQ,GAAG,UAAU,EACpB,MAAM,EAAE,QAAQ,OAAO,CAAC,EACxB,MAAM,WAAY;AACf,SAAK,UAAU,eAAe,EAAE,QAAQ,EAAE,eAAe,aAAa,CAAC;AAAA,EAC3E,CAAC,EAKA,MAAM,WAAY;AACf,SAAK,UAAU,aAAa,EAAE,QAAQ,eAAe,MAAM,GAAG,GAAG,IAAI,CAAC;AAAA,EAC1E,CAAC;AACL,UAAQ,gBAAgB,KAAK,EAAE,MAAM,SAAS;AAC9C,MAAI,aAAa,UAAU,SAAS,GAAG;AACnC,YAAQ,MAAM,QAAQ,QAAQ,SAAS;AAAA,EAC3C;AACA,MAAI,gBAAgB;AAChB,YAAQ,MACH,MAAM,WAAY;AACf,WAAK,UAAU,cAAc,EAAE,QAAQ,EAAE,cAAc,eAAe,aAAa,CAAC;AAAA,IACxF,CAAC,EACA,MAAM,WAAY;AACf,WAAK,UAAU,iBAAiB,EAAE,QAAQ,EAAE,iBAAiB,eAAe,gBAAgB,CAAC;AAAA,IACjG,CAAC,EACA,MAAM,WAAY;AACf,WAAK,UAAU,aAAa,EAAE,QAAQ,EAAE,aAAa,eAAe,YAAY,CAAC;AAAA,IACrF,CAAC;AAAA,EACT,OAAO;AAEH,YAAQ,MACH,UAAU,cAAc,EACxB,UAAU,iBAAiB,EAC3B,UAAU,aAAa;AAAA,EAChC;AACA,QAAM,aAAa,MAAM;AACzB,aAAW,KAAK,sBAAsB;AAEtC,aAAW,OAAO,YAAY;AAC1B,QAAI,CAAC,IAAI,YAAY,IAAI,YAAY,CAAC,YAAY,IAAI,QAAQ,GAAG;AAC7D;AAAA,IACJ;AAEA,UAAM,YAAY,SAAS,IAAI,IAAI,IAAI;AACvC,QAAI,CAAC,WAAW;AAEZ;AAAA,IACJ;AAEA,UAAM,eAAe,IAAI,UAAU,SAAS,GAAG;AAC/C,UAAM,SAAS,aAAa,gBAAgB,MAAM,aAAa,cAAc,IAAI;AACjF,QAAI,QAAQ;AACR,UAAI,CAAC,IAAI,UAAU;AACf,cAAM,GAAG,UAAU,EAAE,MAAM,EAAE,IAAI,IAAI,GAAG,CAAC,EAAE,OAAO;AAAA,UAC9C,UAAU,GAAG,GAAG,IAAI;AAAA,UACpB,UAAU,OAAO,MAAM;AAAA,QAC3B,CAAC;AAAA,MACL;AACA;AAAA,IACJ;AAEA,UAAM,aAAa;AAAA,MACf,YAAY,GAAG,GAAG,IAAI;AAAA,MACtB,QAAQ;AAAA,MACR,mBAAmB,GAAG,GAAG,IAAI;AAAA,IACjC;AACA,QAAI,gBAAgB;AAChB,iBAAW,eAAe,eAAe;AACzC,iBAAW,cAAc,eAAe;AACxC,iBAAW,kBAAkB,eAAe;AAAA,IAChD;AAEA,UAAM,UAAU,MAAM,GAAG,UAAU,EAC9B,MAAM,EAAE,IAAI,IAAI,IAAI,QAAQ,OAAO,CAAC,EACpC,OAAO,UAAU,EACjB,UAAU,GAAG;AAElB,UAAM,UAAU,MAAM,QAAQ,OAAO,IAAI,QAAQ,CAAC,IAAI;AACtD,QAAI,QAAS,QAAO;AAAA,EACxB;AAEA,SAAO;AACX;AA2CA,eAAsB,aAAa,SAAS,SAAS;AACjD,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,SAAS,QAAQ;AACvB,QAAM,eAAe,sBAAsB,QAAQ,YAAY;AAC/D,QAAM,mBAAmB,qBAAqB,QAAQ,gBAAgB;AACtE,QAAM,WAAW,kBAAkB,QAAQ,QAAQ;AACnD,QAAM,EAAE,YAAY,aAAa,IAAI,kBAAkB,SAAS;AAEhE,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,kCAAkC;AAE/D,UAAQ,iBAAiB;AACzB,qBAAmB,SAAS;AAAA,IACxB,aAAa,QAAQ,eAAe;AAAA,IACpC,QAAQ,QAAQ,UAAU;AAAA,IAC1B,eAAe,QAAQ,iBAAiB;AAAA,IACxC,WAAW,QAAQ,aAAa;AAAA,EACpC,CAAC;AACD,2BAAyB,OAAO;AAChC,MAAI,OAAO,QAAQ,mBAAmB,YAAY;AAC9C,YAAQ,sBAAsB,QAAQ;AAAA,EAC1C;AAEA,QAAM,kBAAkB,oBAAI,IAAI;AAChC,QAAM,uBAAuB,oBAAI,IAAI;AAErC,UAAQ,uBAAuB;AAC/B,MAAI,wBAAwB;AAC5B,MAAI,gBAAgB;AACpB,MAAI,kBAAkB,OAAO,QAAQ,eAAe,IAAI,IAAI,OAAO,QAAQ,eAAe,IAAI;AAC9F,UAAQ,kBAAkB;AAE1B,MAAI,cAAc;AAClB,MAAI,mBAAmB;AACvB,MAAI,iBAAiB;AACrB,QAAM,UAAU,QAAQ,oBAAoB,KAAK;AACjD,MAAI,SAAS;AACT,UAAM,eAAe,QAAQ,6BAA6B;AAC1D,UAAM,UAAU,QAAQ,0BAA0B;AAClD,UAAM,oBAAoB,uBAAuB,QAAQ,mBAAmB;AAC5E,YAAQ,yBAAyB;AACjC,UAAM,cAAc;AAAA,MAChB,WAAW;AAAA,MACX,cAAc,cAAc,SAAS,aAAa,KAAK,GAAG,IAAI;AAAA,MAC9D,QAAQ;AAAA,MACR,eAAe;AAAA,MACf,SAAS,sBAAsB,SAAS,iBAAiB;AAAA,IAC7D;AACA,UAAM,WAAW;AAAA,MACb,GAAG;AAAA,MACH,GAAI,QAAQ,kBAAkB,OAAO,QAAQ,mBAAmB,WAC1D,QAAQ,iBACR,CAAC;AAAA,IACX;AACA,QAAI,CAAC,MAAM,QAAQ,SAAS,aAAa,KAAK,SAAS,cAAc,WAAW,GAAG;AAC/E,eAAS,gBAAgB,YAAY;AAAA,IACzC;AACA,QAAI,CAAC,SAAS,WAAW,OAAO,SAAS,YAAY,UAAU;AAC3D,eAAS,UAAU,YAAY;AAAA,IACnC;AACA,kBAAc,MAAM,2BAA2B,SAAS;AAAA,MACpD;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,aAAa,QAAQ;AAAA,MACrB,gBAAgB,QAAQ;AAAA,MACxB;AAAA,MACA,mBAAmB,QAAQ;AAAA,MAC3B,qBAAqB,QAAQ,6BAA6B;AAAA,MAC1D;AAAA,IACJ,CAAC;AAED,YAAQ,mBAAmB;AAC3B,qBAAiB;AAAA,MACb,cAAc,YAAY;AAAA,MAC1B,aAAa,gBAAAC,QAAG,SAAS;AAAA,MACzB,iBAAiB,YAAY;AAAA,IACjC;AACA,uBAAmB,YAAY,MAAM;AACjC,WAAK,sBAAsB,SAAS,WAAW,EAAE,MAAM,CAAC,QAAQ;AAC5D,gBAAQ,OAAO,OAAO,qCAAqC,KAAK,WAAW,OAAO,GAAG,CAAC,EAAE;AAAA,MAC5F,CAAC;AAAA,IACL,GAAG,YAAY;AAAA,EACnB;AAEA,MAAI;AACA,WAAO,CAAC,QAAQ,OAAO,KAAK,CAAC,iBAAiB,QAAQ,oBAAoB,MAAM;AAC5E,YAAM,EAAE,aAAa,QAAQ,eAAe,UAAU,IAAI,gBAAgB,OAAO;AACjF,YAAM,8BAA8B,SAAS,YAAY,oBAAoB;AAG7E,UAAI,CAAC,uBAAuB;AACxB,cAAM,qBAAqB,MAAM;AAAA,UAC7B;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACJ;AACA,YAAI,oBAAoB;AACpB,kCAAwB;AAAA,YACpB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACJ,EACK,KAAK,OAAO,YAAY;AACrB,gBAAI,QAAQ,uBAAuB,CAAC,eAAe;AAC/C,8BAAgB;AAChB,gCAAkB,QAAQ,mBAAmB;AAC7C,sBAAQ,kBAAkB;AAC1B,oBAAM,uBAAuB,SAAS,sBAAsB,eAAe;AAAA,YAC/E;AAAA,UACJ,CAAC,EACA,QAAQ,MAAM;AACX,oCAAwB;AAAA,UAC5B,CAAC;AAAA,QACT;AAAA,MACJ;AAEA,UAAI,gBAAgB,GAAG;AACnB,cAAM,QAAQ,KAAK,MAAM,KAAK,OAAO,KAAK,gBAAgB,EAAE,CAAC;AAAA,MACjE;AAGA,YAAM,SAAS,QAAQ,cAAc,WAAW;AAChD,UAAI,CAAC,QAAQ;AACT,eAAO,gBAAgB,OAAO,aAAa;AACvC,gBAAM,UAAU,MAAM;AAAA,YAClB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACJ;AACA,cAAI,CAAC,QAAS;AAEd,gBAAM,IAAI;AAAA,YACN;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACJ,EACK,KAAK,OAAO,YAAY;AACrB,gBAAI,QAAQ,uBAAuB,CAAC,eAAe;AAC/C,8BAAgB;AAChB,gCAAkB,QAAQ,mBAAmB;AAC7C,sBAAQ,kBAAkB;AAC1B,oBAAM,uBAAuB,SAAS,sBAAsB,eAAe;AAAA,YAC/E;AAAA,UACJ,CAAC,EACA,QAAQ,MAAM;AACX,4BAAgB,OAAO,CAAC;AAAA,UAC5B,CAAC;AACL,0BAAgB,IAAI,CAAC;AAAA,QACzB;AAAA,MACJ;AAEA,YAAM,eAAe,CAAC,GAAG,eAAe;AACxC,UAAI,uBAAuB;AACvB,qBAAa,KAAK,qBAAqB;AAAA,MAC3C;AACA,UAAI,aAAa,WAAW,GAAG;AAC3B,kCAA0B,SAAS,YAAY;AAC/C,cAAM,QAAQ,MAAM;AAAA,MACxB,OAAO;AACH,cAAM,OAAO,aAAa,IAAI,CAAC,MAAM,EAAE,MAAM,MAAM,MAAS,CAAC;AAC7D,cAAM,QAAQ,KAAK,CAAC,QAAQ,MAAM,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC;AAAA,MAC5D;AAAA,IACJ;AAEA,QAAI,QAAQ,OAAO,KAAK,CAAC,eAAe;AACpC,sBAAgB;AAChB,wBAAkB,OAAO,QAAQ,eAAe,IAAI,IAC9C,OAAO,QAAQ,eAAe,IAC9B;AACN,YAAM,uBAAuB,SAAS,sBAAsB,eAAe;AAAA,IAC/E;AAEA,QAAI,gBAAgB,OAAO,GAAG;AAC1B,UAAI,eAAe;AACf,cAAM,QAAQ,KAAK;AAAA,UACf,QAAQ,WAAW,MAAM,KAAK,eAAe,CAAC;AAAA,UAC9C,QAAQ,eAAe,EAAE,KAAK,MAAM;AAChC,oBAAQ,OAAO;AAAA,cACX,2BAA2B,eAAe,gBAAgB,gBAAgB,IAAI;AAAA,YAClF;AAAA,UACJ,CAAC;AAAA,QACL,CAAC;AAAA,MACL,OAAO;AACH,cAAM,QAAQ,WAAW,MAAM,KAAK,eAAe,CAAC;AAAA,MACxD;AAAA,IACJ;AAAA,EACJ,UAAE;AACE,QAAI,kBAAkB;AAClB,oBAAc,gBAAgB;AAC9B,yBAAmB;AAAA,IACvB;AACA,QAAI,aAAa;AACb,YAAM,2BAA2B,SAAS,WAAW,EAAE,MAAM,CAAC,QAAQ;AAClE,gBAAQ,OAAO,OAAO,0CAA0C,KAAK,WAAW,OAAO,GAAG,CAAC,EAAE;AAAA,MACjG,CAAC;AACD,oBAAc;AACd,aAAO,QAAQ;AACf,aAAO,QAAQ;AAAA,IACnB;AAAA,EACJ;AACJ;AA4BA,eAAsB,kBAAkB,SAAS,QAAQ,UAAU,CAAC,GAAG;AACnE,QAAM,KAAKD,OAAM,OAAO;AACxB,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,EAAE,YAAY,aAAa,IAAI,kBAAkB,SAAS;AAChE,QAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,QAAM,gBAAgB,IAAI,KAAK,KAAK,IAAI,IAAI,GAAK;AACjD,MAAI,iBACA,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,IAAI,EAAE,KAAK,MAAM,KAClD;AAAA,IACI,MAAM,OAAO,QAAQ,IAAI,EAAE,KAAK;AAAA,IAChC,MAAM,QAAQ,SAAS,SAAY,QAAQ,OAAO;AAAA,EACtD,IACA;AAOV,iBAAe,YAAY,MAAM,MAAM;AACnC,UAAM,OAAO,MACT,GAAG,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,gBAAgB,MAAM,aAAa;AAE9E,QAAI,QAAQ,QAAQ,OAAO,IAAI,EAAE,KAAK,MAAM,IAAI;AAC5C,YAAM,SAAS,MAAM,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,QAAQ,gBAAgB,MAAM,EAAE,MAAM;AAClF,UAAI,OAAQ,QAAO;AAAA,IACvB;AAGA,UAAM,YAAY,MAAM,KAAK,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,EAAE,QAAQ,gBAAgB,MAAM,EAAE,MAAM;AAC7F,QAAI,UAAW,QAAO;AAGtB,UAAM,eAAe,MAAM,GAAG,YAAY,EACrC,MAAM,EAAE,MAAM,MAAM,OAAO,CAAC,EAC5B,QAAQ,gBAAgB,MAAM,EAC9B,MAAM;AACX,QAAI,aAAc,QAAO;AAEzB,QAAI,QAAQ,QAAQ,SAAS,IAAI;AAC7B,YAAM,SAAS,MAAM,KAAK,EAAE,UAAU,MAAM,EAAE,QAAQ,gBAAgB,MAAM,EAAE,MAAM;AACpF,UAAI,OAAQ,QAAO;AAAA,IACvB;AAEA,WAAO;AAAA,EACX;AAEA,SAAO,KAAK,IAAI,KAAK,UAAU;AAC3B,UAAM,SAAS,MAAM,GAAG,YAAY,EAAE,MAAM,EAAE,IAAI,OAAO,CAAC,EAAE,QAAQ,cAAc,MAAM,EAAE,MAAM;AAChG,QAAI,QAAQ;AACR,aAAO;AAAA,IACX;AAEA,UAAM,UAAU,MAAM,GAAG,UAAU,EAAE,MAAM,EAAE,IAAI,OAAO,CAAC,EAAE,MAAM;AACjE,QAAI,SAAS;AACT,uBAAiB,EAAE,MAAM,QAAQ,MAAM,MAAM,QAAQ,KAAK;AAAA,IAC9D;AAEA,QAAI,gBAAgB;AAChB,YAAM,OAAO,MAAM,YAAY,eAAe,MAAM,eAAe,IAAI;AACvE,UAAI,MAAM;AACN,eAAO;AAAA,MACX;AAAA,IACJ,OAAO;AAEH,YAAM,YAAY,MAAM,GAAG,YAAY,EAClC,MAAM,EAAE,MAAM,OAAO,CAAC,EACtB,QAAQ,gBAAgB,MAAM,EAC9B,MAAM;AACX,UAAI,WAAW;AACX,eAAO;AAAA,MACX;AAAA,IACJ;AAEA,UAAM,QAAQ,MAAM;AAAA,EACxB;AACA,SAAO;AACX;AAUO,IAAM,eAAN,MAAM,cAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBtB,YAAY,SAAS,UAAU,CAAC,GAAG;AAC/B,SAAK,UAAU;AACf,SAAK,YAAY,QAAQ,aAAa;AACtC,SAAK,SAAS,QAAQ,UAAU;AAChC,SAAK,qBAAqB,QAAQ,sBAAsB;AACxD,SAAK,SAAS,QAAQ,UAAU;AAChC,SAAK,gBAAgB,QAAQ,iBAAiB;AAC9C,SAAK,cAAc,QAAQ,eAAe;AAC1C,SAAK,YAAY,QAAQ,aAAa;AACtC,SAAK,eAAe,sBAAsB,QAAQ,YAAY;AAC9D,SAAK,WAAW,kBAAkB,QAAQ,QAAQ;AAClD,SAAK,qBAAqB,QAAQ;AAClC,SAAK,oBAAoB,QAAQ;AACjC,SAAK,uBAAuB,QAAQ;AACpC,SAAK,4BAA4B,QAAQ;AACzC,SAAK,yBAAyB,QAAQ;AACtC,SAAK,0BAA0B,QAAQ;AACvC,SAAK,4BAA4B,QAAQ;AACzC,SAAK,iBAAiB,QAAQ;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,KAAK,SAAS,UAAU,CAAC,GAAG;AAC/B,UAAM,OAAO;AAAA,MACT,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,oBAAoB;AAAA,MACpB,QAAQ;AAAA,MACR,eAAe;AAAA,MACf,aAAa;AAAA,MACb,WAAW;AAAA,MACX,cAAc;AAAA,MACd,oBAAoB;AAAA,MACpB,mBAAmB;AAAA,MACnB,sBAAsB;AAAA,MACtB,2BAA2B;AAAA,MAC3B,wBAAwB;AAAA,MACxB,yBAAyB;AAAA,MACzB,2BAA2B;AAAA,IAC/B;AAEA,UAAM,aAAa,QAAQ,OAAO,gBAAgB,SAAS,IAAI;AAC/D,UAAM,WAAW;AAAA,MACb,WAAW,WAAW;AAAA,MACtB,QAAQ,WAAW;AAAA,MACnB,oBAAoB,WAAW;AAAA,MAC/B,QAAQ,WAAW;AAAA,MACnB,eAAe,WAAW;AAAA,MAC1B,aAAa,WAAW;AAAA,MACxB,WAAW,WAAW;AAAA,MACtB,cAAc,WAAW;AAAA,MACzB,oBAAoB,WAAW;AAAA,MAC/B,mBAAmB,WAAW;AAAA,MAC9B,sBAAsB,WAAW;AAAA,MACjC,2BAA2B,WAAW;AAAA,MACtC,wBAAwB,WAAW;AAAA,MACnC,yBAAyB,WAAW;AAAA,MACpC,2BAA2B,WAAW;AAAA,MACtC,GAAG;AAAA,IACP;AACA,WAAO,IAAI,cAAa,SAAS,QAAQ;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,iBAAiB,UAAU,CAAC,GAAG;AACjC,UAAM,iBAAiB,KAAK,SAAS;AAAA,MACjC,WAAW,KAAK;AAAA,MAChB,UAAU,QAAQ,YAAY,KAAK;AAAA,IACvC,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,aAAa,UAAU,CAAC,GAAG;AAC7B,UAAM,aAAa,KAAK,SAAS;AAAA,MAC7B,WAAW,QAAQ,aAAa,KAAK;AAAA,MACrC,QAAQ,QAAQ,UAAU,KAAK;AAAA,MAC/B,QAAQ,QAAQ,UAAU,KAAK;AAAA,MAC/B,eAAe,QAAQ,iBAAiB,KAAK;AAAA,MAC7C,aAAa,QAAQ,eAAe,KAAK;AAAA,MACzC,WAAW,QAAQ,aAAa,KAAK;AAAA,MACrC,cAAc,QAAQ,gBAAgB,KAAK;AAAA,MAC3C,UAAU,QAAQ,YAAY,KAAK;AAAA,MACnC,oBAAoB,QAAQ,sBAAsB,KAAK;AAAA,MACvD,mBAAmB,QAAQ,qBAAqB,KAAK;AAAA,MACrD,sBAAsB,QAAQ,wBAAwB,KAAK;AAAA,MAC3D,2BAA2B,QAAQ,6BAA6B,KAAK;AAAA,MACrE,wBAAwB,QAAQ,0BAA0B,KAAK;AAAA,MAC/D,yBAAyB,QAAQ,2BAA2B,KAAK;AAAA,MACjE,2BAA2B,QAAQ,6BAA6B,KAAK;AAAA,MACrE,gBAAgB,QAAQ,kBAAkB,KAAK;AAAA,IACnD,CAAC;AAAA,EACL;AACJ;","names":["import_node_os","path","fs","import_fs","import_path","fs","path","sql","getDb","os","import_fs","import_path","path","fs","destPath","path","state","record","fs","import_node_os","import_promises","fs","os","out","import_node_child_process","getDb","os"]}