@camstack/addon-embedding-encoder 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +37 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +959 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +933 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/addon/index.ts","../src/catalogs/embedding-models.ts","../src/shared/noop-logger.ts","../src/shared/node-raw-tensor-engine.ts","../src/shared/engine-resolver.ts","../src/shared/image-utils.ts","../src/shared/node-engine.ts","../src/shared/python-engine.ts","../src/addon/clip-models.ts","../src/addon/clip-preprocessing.ts"],"sourcesContent":["export { default as EmbeddingEncoderAddon } from './addon/index.js'\nexport type { IEmbeddingEncoder, EmbeddingResult, EmbeddingInfo } from '@camstack/types'\n","import type {\n ProviderRegistration,\n IRawTensorEngine,\n IInferenceEngine,\n ModelCatalogEntry,\n IEmbeddingEncoder,\n EmbeddingResult,\n EmbeddingInfo,\n} from '@camstack/types'\nimport type { IAddonModelManager } from '@camstack/types'\nimport { BaseAddon, embeddingEncoderCapability } from '@camstack/types'\n// eslint-disable-next-line no-restricted-imports -- ModelDownloadService is a build-time dep, not a runtime addon coupling\nimport { ModelDownloadService } from '@camstack/core'\nimport { CLIP_IMAGE_MODELS, CLIP_TEXT_MODELS } from '../catalogs/embedding-models.js'\nimport { NodeRawTensorEngine } from '../shared/node-raw-tensor-engine.js'\nimport { resolveEngine } from '../shared/engine-resolver.js'\nimport { getModelMeta, DEFAULT_CLIP_MODEL } from './clip-models.js'\nimport { preprocessForClip, l2Normalize } from './clip-preprocessing.js'\n\n/**\n * Embedding encoder uses two separate engines (image + text) with custom\n * CLIP preprocessing — cannot use BaseVisionAddon which assumes single engine + JPEG input.\n *\n * Uses IRawTensorEngine for ONNX (custom tensor preprocessing) and\n * IInferenceEngine.infer() for Python path (sends JPEG/JSON via binary IPC).\n */\ninterface EmbeddingConfig {\n modelId: string\n runtime: string\n backend: string\n}\n\nexport default class EmbeddingEncoderAddon extends BaseAddon<EmbeddingConfig> implements IEmbeddingEncoder {\n private imageRawEngine: IRawTensorEngine | null = null\n private textRawEngine: IRawTensorEngine | null = null\n private imagePythonEngine: IInferenceEngine | null = null\n private textPythonEngine: IInferenceEngine | null = null\n\n private models: IAddonModelManager | null = null\n private isPython = false\n\n constructor() { super({ modelId: DEFAULT_CLIP_MODEL, runtime: 'auto', backend: 'cpu' }) }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const modelsDir = await this.ctx.api.storage.resolve.query({ location: 'models', relativePath: '' })\n .catch(() => 'camstack-data/models')\n this.models = new ModelDownloadService(modelsDir, [])\n return [{ capability: embeddingEncoderCapability, provider: this }]\n }\n\n async encode(crop: Buffer, width: number, height: number): Promise<EmbeddingResult> {\n await this.ensureImageEngine()\n const meta = getModelMeta(this.config.modelId)\n const start = Date.now()\n\n // Python engine path — send JPEG directly\n if (this.isPython && this.imagePythonEngine) {\n const result = await this.imagePythonEngine.infer({ kind: 'jpeg', data: crop })\n const rawEmbedding = result.structured?.['embedding'] as number[]\n const embedding = new Float32Array(rawEmbedding)\n return {\n embedding: l2Normalize(embedding),\n inferenceMs: result.inferenceMs ?? (Date.now() - start),\n }\n }\n\n // ONNX path — custom CLIP preprocessing + raw tensor engine\n const preprocessed = preprocessForClip(crop, width, height, meta.inputSize, meta.inputSize)\n const output = await this.imageRawEngine!.run(preprocessed, [1, 3, meta.inputSize, meta.inputSize])\n const sliced = output.length > meta.embeddingDim\n ? output.slice(0, meta.embeddingDim)\n : output\n\n return {\n embedding: l2Normalize(new Float32Array(sliced)),\n inferenceMs: Date.now() - start,\n }\n }\n\n async encodeText(text: string): Promise<EmbeddingResult> {\n await this.ensureTextEngine()\n const meta = getModelMeta(this.config.modelId)\n const start = Date.now()\n\n // Python engine path\n if (this.isPython && this.textPythonEngine) {\n const textBuffer = Buffer.from(JSON.stringify({ text }), 'utf-8')\n const result = await this.textPythonEngine.infer({ kind: 'jpeg', data: textBuffer })\n const rawEmbedding = result.structured?.['embedding'] as number[]\n const embedding = new Float32Array(rawEmbedding)\n return {\n embedding: l2Normalize(embedding),\n inferenceMs: result.inferenceMs ?? (Date.now() - start),\n }\n }\n\n // ONNX path — tokenize + raw tensor engine\n const tokenIds = clipTokenize(text)\n const inputTensor = new Float32Array(tokenIds)\n const output = await this.textRawEngine!.run(inputTensor, [1, tokenIds.length])\n const sliced = output.length > meta.embeddingDim\n ? output.slice(0, meta.embeddingDim)\n : output\n\n return {\n embedding: l2Normalize(new Float32Array(sliced)),\n inferenceMs: Date.now() - start,\n }\n }\n\n getInfo(): EmbeddingInfo {\n const meta = getModelMeta(this.config.modelId)\n return {\n modelId: this.config.modelId,\n embeddingDim: meta.embeddingDim,\n ready: this.imageRawEngine !== null || this.imagePythonEngine !== null,\n }\n }\n\n private async ensureImageEngine(): Promise<void> {\n if (this.imageRawEngine || this.imagePythonEngine) return\n\n const meta = getModelMeta(this.config.modelId)\n const imageEntry = CLIP_IMAGE_MODELS.find((m) => m.id === meta.imageModelId)\n if (!imageEntry) {\n throw new Error(`EmbeddingEncoderAddon: unknown image model \"${meta.imageModelId}\"`)\n }\n\n await this.resolveForEntry(imageEntry, 'image')\n }\n\n private async ensureTextEngine(): Promise<void> {\n if (this.textRawEngine || this.textPythonEngine) return\n\n const meta = getModelMeta(this.config.modelId)\n const textEntry = CLIP_TEXT_MODELS.find((m) => m.id === meta.textModelId)\n if (!textEntry) {\n throw new Error(`EmbeddingEncoderAddon: unknown text model \"${meta.textModelId}\"`)\n }\n\n await this.resolveForEntry(textEntry, 'text')\n }\n\n private async resolveForEntry(entry: ModelCatalogEntry, target: 'image' | 'text'): Promise<void> {\n const runtime = this.config.runtime === 'auto' ? 'auto' : (this.config.runtime === 'node' ? 'onnx' : this.config.runtime)\n const modelsDir = this.models!.getModelsDir()\n\n const engineLogger = this.ctx!.logger.withTags({\n modelId: entry.id,\n runtime: this.config.runtime,\n backend: this.config.backend,\n })\n\n await this.models!.ensure(entry.id, 'onnx')\n\n const resolved = await resolveEngine({\n runtime: runtime as 'auto',\n backend: this.config.backend,\n modelEntry: entry,\n modelsDir,\n models: this.models ?? undefined,\n logger: engineLogger,\n })\n\n // Check if the resolved engine is Python-based (has structured output)\n // by checking if the format is non-ONNX\n if (resolved.format !== 'onnx') {\n this.isPython = true\n if (target === 'image') {\n this.imagePythonEngine = resolved.engine\n } else {\n this.textPythonEngine = resolved.engine\n }\n } else {\n // ONNX — create a raw tensor engine for custom preprocessing\n const rawEngine = new NodeRawTensorEngine(resolved.modelPath, this.config.backend, engineLogger)\n await rawEngine.initialize()\n // Dispose the vision engine from resolveEngine (we don't need it)\n await resolved.engine.dispose()\n if (target === 'image') {\n this.imageRawEngine = rawEngine\n } else {\n this.textRawEngine = rawEngine\n }\n }\n }\n\n protected async onShutdown(): Promise<void> {\n await this.imageRawEngine?.dispose()\n await this.textRawEngine?.dispose()\n await this.imagePythonEngine?.dispose()\n await this.textPythonEngine?.dispose()\n }\n\n // ── Three-level settings API (Phase 3) ──────────────────────────────\n\n protected globalSettingsSchema() {\n return this.schema({\n sections: [\n {\n id: 'embedding-encoder-settings',\n title: 'Embedding Encoder',\n columns: 2,\n fields: [\n {\n type: 'text',\n key: 'modelId',\n label: 'Model ID',\n description: 'CLIP model identifier to use for image/text embedding',\n default: DEFAULT_CLIP_MODEL,\n },\n {\n type: 'select',\n key: 'runtime',\n label: 'Runtime',\n description: 'Inference runtime (auto selects the best available)',\n default: 'auto',\n options: [\n { label: 'Auto', value: 'auto' },\n { label: 'Node (ONNX)', value: 'node' },\n { label: 'Python', value: 'python' },\n ],\n },\n {\n type: 'select',\n key: 'backend',\n label: 'Backend',\n description: 'Hardware backend for inference acceleration',\n default: 'cpu',\n options: [\n { label: 'CPU', value: 'cpu' },\n { label: 'CUDA', value: 'cuda' },\n { label: 'CoreML', value: 'coreml' },\n ],\n },\n ],\n },\n ],\n })\n }\n\n protected async onConfigChanged(): Promise<void> {\n // Config already updated by BaseAddon.resolveConfig() — nothing extra needed.\n // If model changed, ensureImageEngine will pick it up on next call.\n }\n}\n\n/**\n * Minimal CLIP tokenizer — encodes ASCII text to token IDs.\n * Production implementations should use a proper BPE tokenizer;\n * this is a simplified placeholder that maps characters to IDs\n * with SOT/EOT tokens for basic functionality.\n */\nfunction clipTokenize(text: string, maxLength = 77): number[] {\n const SOT_TOKEN = 49406\n const EOT_TOKEN = 49407\n const tokens: number[] = [SOT_TOKEN]\n\n for (let i = 0; i < text.length && tokens.length < maxLength - 1; i++) {\n tokens.push(text.charCodeAt(i) + 256)\n }\n tokens.push(EOT_TOKEN)\n\n while (tokens.length < maxLength) {\n tokens.push(0)\n }\n\n return tokens\n}\n","import type { ModelCatalogEntry } from '@camstack/types'\n\nexport const CLIP_IMAGE_MODELS: readonly ModelCatalogEntry[] = [\n {\n id: 'clip-vit-b32',\n name: 'CLIP ViT-B/32',\n description: 'OpenAI CLIP ViT-B/32 — fast, 512-dim, int8 quantized (85 MB)',\n inputSize: { width: 224, height: 224 },\n labels: [],\n inputLayout: 'nchw',\n inputNormalization: 'none',\n formats: {\n onnx: {\n url: 'https://huggingface.co/Xenova/clip-vit-base-patch32/resolve/main/onnx/vision_model_quantized.onnx',\n sizeMB: 85,\n },\n },\n },\n {\n id: 'clip-vit-b16',\n name: 'CLIP ViT-B/16',\n description: 'OpenAI CLIP ViT-B/16 — higher accuracy, 512-dim, int8 quantized (83 MB)',\n inputSize: { width: 224, height: 224 },\n labels: [],\n inputLayout: 'nchw',\n inputNormalization: 'none',\n formats: {\n onnx: {\n url: 'https://huggingface.co/Xenova/clip-vit-base-patch16/resolve/main/onnx/vision_model_quantized.onnx',\n sizeMB: 83,\n },\n },\n },\n {\n id: 'siglip2-b16-256',\n name: 'SigLIP2 Base/16 256',\n description: 'Google SigLIP2 — superior scene understanding, 768-dim, int8 quantized (90 MB)',\n inputSize: { width: 256, height: 256 },\n labels: [],\n inputLayout: 'nchw',\n inputNormalization: 'none',\n formats: {\n onnx: {\n url: 'https://huggingface.co/onnx-community/siglip2-base-patch16-256-ONNX/resolve/main/onnx/vision_model_quantized.onnx',\n sizeMB: 90,\n },\n },\n },\n]\n\nexport const CLIP_TEXT_MODELS: readonly ModelCatalogEntry[] = [\n {\n id: 'clip-vit-b32-text',\n name: 'CLIP ViT-B/32 Text Encoder',\n description: 'Text encoder for CLIP ViT-B/32, int8 quantized (62 MB)',\n inputSize: { width: 0, height: 0 },\n labels: [],\n formats: {\n onnx: {\n url: 'https://huggingface.co/Xenova/clip-vit-base-patch32/resolve/main/onnx/text_model_quantized.onnx',\n sizeMB: 62,\n },\n },\n },\n {\n id: 'clip-vit-b16-text',\n name: 'CLIP ViT-B/16 Text Encoder',\n description: 'Text encoder for CLIP ViT-B/16, int8 quantized (62 MB)',\n inputSize: { width: 0, height: 0 },\n labels: [],\n formats: {\n onnx: {\n url: 'https://huggingface.co/Xenova/clip-vit-base-patch16/resolve/main/onnx/text_model_quantized.onnx',\n sizeMB: 62,\n },\n },\n },\n {\n id: 'siglip2-b16-256-text',\n name: 'SigLIP2 Base/16 256 Text Encoder',\n description: 'Text encoder for SigLIP2, int8 quantized (270 MB)',\n inputSize: { width: 0, height: 0 },\n labels: [],\n formats: {\n onnx: {\n url: 'https://huggingface.co/onnx-community/siglip2-base-patch16-256-ONNX/resolve/main/onnx/text_model_quantized.onnx',\n sizeMB: 270,\n },\n },\n },\n]\n","import type { IScopedLogger, LogTags } from '@camstack/types'\n\nconst noop = (): void => { /* intentional no-op */ }\n\nexport function createNoopLogger(): IScopedLogger {\n const logger: IScopedLogger = {\n debug: noop,\n info: noop,\n warn: noop,\n error: noop,\n child: () => logger,\n withTags: (_tags: LogTags) => logger,\n }\n return logger\n}\n","import type { IRawTensorEngine, DetectionRuntime, DetectionDevice, IScopedLogger } from '@camstack/types'\nimport type { InferenceSession } from 'onnxruntime-node'\nimport { createNoopLogger } from './noop-logger.js'\nimport * as path from 'node:path'\n\nconst BACKEND_TO_DEVICE: Readonly<Record<string, DetectionDevice>> = {\n cpu: 'cpu',\n coreml: 'gpu-mps',\n cuda: 'gpu-cuda',\n tensorrt: 'tensorrt',\n} as const\n\n/**\n * Raw tensor engine — runs ONNX inference on pre-processed Float32Array input.\n * Used by addons that handle their own preprocessing (e.g. CLIP embedding encoder).\n */\nexport class NodeRawTensorEngine implements IRawTensorEngine {\n readonly runtime: DetectionRuntime = 'onnx'\n readonly device: DetectionDevice\n private session: InferenceSession | null = null\n private readonly log: IScopedLogger\n\n constructor(\n private readonly modelPath: string,\n private readonly backend: string,\n logger?: IScopedLogger,\n ) {\n this.device = BACKEND_TO_DEVICE[backend] ?? 'cpu'\n this.log = logger ?? createNoopLogger()\n }\n\n async initialize(): Promise<void> {\n const ort = await import('onnxruntime-node')\n const provider = this.backend === 'coreml' ? 'coreml' : this.backend === 'cuda' ? 'cuda' : 'cpu'\n\n const absModelPath = path.isAbsolute(this.modelPath)\n ? this.modelPath\n : path.resolve(process.cwd(), this.modelPath)\n\n this.session = await ort.InferenceSession.create(absModelPath, {\n executionProviders: [provider],\n })\n this.log.info('ONNX session loaded', { meta: { modelPath: absModelPath, backend: this.backend, provider } })\n }\n\n async run(input: Float32Array, inputShape: readonly number[]): Promise<Float32Array> {\n if (!this.session) {\n throw new Error('NodeRawTensorEngine: not initialized — call initialize() first')\n }\n\n const ort = await import('onnxruntime-node')\n const sess = this.session\n\n const inputName: string = sess.inputNames[0]!\n const tensor = new ort.Tensor('float32', input, [...inputShape])\n const feeds: Record<string, InstanceType<typeof ort.Tensor>> = { [inputName]: tensor }\n\n const start = Date.now()\n let results: Record<string, InstanceType<typeof ort.Tensor>>\n try {\n results = await sess.run(feeds)\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err))\n this.log.error('Inference failed', { meta: { error: error.message } })\n throw error\n }\n\n const outputName: string = sess.outputNames[0]!\n this.log.debug('Inference complete', { meta: { durationMs: Date.now() - start, outputKeys: [outputName], preprocessMode: 'raw-tensor' } })\n return results[outputName]!.data\n }\n\n async dispose(): Promise<void> {\n this.session = null\n this.log.debug('Session disposed')\n }\n}\n","// Engine resolver has inherent branching for runtime × backend × format × device combinations\n// TODO: Wire PythonInferenceEngine for PyTorch/OpenVINO/TFLite runtimes\n// Currently falls back to ONNX CPU when non-ONNX runtime is requested.\n//\n// WHY THIS FILE USES RAW FILESYSTEM PATHS (modelsDir: string):\n//\n// Model files must be loaded via absolute filesystem paths because inference\n// engines (ONNX Runtime, CoreML, etc.) require direct file access -- they do\n// not accept Buffer or stream inputs. This is fundamentally different from\n// user data (recordings, media) where IAddonFileStorage abstraction makes\n// sense. Models are closer to binaries or compiled artifacts that must live\n// on the local filesystem at runtime.\n//\n// IAddonFileStorage.readFile() returns a Buffer, but onnxruntime-node's\n// InferenceSession.create() only accepts a file path string or a Uint8Array\n// loaded into memory. For large models (hundreds of MB), loading into a\n// Uint8Array is impractical. Therefore, modelsDir stays as a raw string path\n// and is intentionally NOT replaced with IAddonFileStorage here.\n\nimport type {\n IInferenceEngine,\n DetectionRuntime,\n ModelCatalogEntry,\n ModelFormat,\n IAddonModelManager,\n ModelInputMeta,\n IScopedLogger,\n} from '@camstack/types'\nimport { createNoopLogger } from './noop-logger.js'\nimport {\n BACKEND_TO_FORMAT as CANONICAL_BACKEND_TO_FORMAT,\n RUNTIME_TO_FORMAT as CANONICAL_RUNTIME_TO_FORMAT,\n PYTHON_SCRIPT as CANONICAL_PYTHON_SCRIPT,\n} from '@camstack/types'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { NodeInferenceEngine } from './node-engine.js'\nimport { PythonInferenceEngine } from './python-engine.js'\nimport type { SharedPythonPool } from './python-pool.js'\n\nexport interface EngineResolverOptions {\n readonly runtime: DetectionRuntime | 'auto'\n readonly backend: string\n readonly modelEntry: ModelCatalogEntry\n readonly modelsDir: string\n readonly pythonPath?: string\n /** Model service for downloading models. When provided, used instead of raw filesystem probing. */\n readonly models?: IAddonModelManager\n /** Optional logger — tagged with modelId, runtime, backend by the caller. */\n readonly logger?: IScopedLogger\n /** Shared CoreML pool — when provided, CoreML models use the pool instead of a dedicated Python process. */\n readonly coremlPool?: SharedPythonPool\n}\n\nexport interface ResolvedEngine {\n readonly engine: IInferenceEngine\n readonly format: ModelFormat\n readonly modelPath: string\n}\n\n/** Priority order for auto-selection of ONNX backends */\nconst AUTO_BACKEND_PRIORITY = ['coreml', 'cuda', 'tensorrt', 'cpu'] as const\n\n// Use canonical mappings from @camstack/types (single source of truth)\nconst BACKEND_TO_FORMAT = CANONICAL_BACKEND_TO_FORMAT\nconst RUNTIME_TO_FORMAT = CANONICAL_RUNTIME_TO_FORMAT\n\nfunction extractModelMeta(entry: ModelCatalogEntry): ModelInputMeta {\n return {\n inputSize: entry.inputSize,\n inputNormalization: entry.inputNormalization ?? 'zero-one',\n inputLayout: entry.inputLayout ?? 'nchw',\n preprocessMode: entry.preprocessMode ?? 'letterbox',\n }\n}\n\nfunction modelFilePath(modelsDir: string, modelEntry: ModelCatalogEntry, format: ModelFormat): string {\n const formatEntry = modelEntry.formats[format]\n if (!formatEntry) {\n throw new Error(`Model ${modelEntry.id} has no ${format} format`)\n }\n // Derive filename from URL\n const urlParts = formatEntry.url.split('/')\n const filename = urlParts[urlParts.length - 1] ?? `${modelEntry.id}.${format}`\n return path.join(modelsDir, filename)\n}\n\nfunction modelExists(filePath: string): boolean {\n try {\n return fs.existsSync(filePath)\n } catch {\n return false\n }\n}\n\nexport async function resolveEngine(options: EngineResolverOptions): Promise<ResolvedEngine> {\n const { runtime, backend, modelEntry, modelsDir, models } = options\n const log = options.logger ?? createNoopLogger()\n\n let selectedFormat: ModelFormat\n let selectedBackend: string\n\n if (runtime === 'auto') {\n // Probe available ONNX backends and pick best\n const available = await probeOnnxBackends()\n\n // Pick first priority backend that has a corresponding model format available\n let chosen: { backend: string; format: ModelFormat } | null = null\n\n for (const b of AUTO_BACKEND_PRIORITY) {\n if (!available.includes(b)) continue\n const fmt = BACKEND_TO_FORMAT[b]\n if (!fmt) continue\n if (!modelEntry.formats[fmt]) continue\n chosen = { backend: b, format: fmt }\n break\n }\n\n if (!chosen) {\n throw new Error(\n `resolveEngine: no compatible backend found for model ${modelEntry.id}. Available backends: ${available.join(', ')}`,\n )\n }\n\n selectedFormat = chosen.format\n selectedBackend = chosen.backend\n } else {\n // Explicit runtime requested\n const fmt = RUNTIME_TO_FORMAT[runtime]\n if (!fmt) {\n throw new Error(`resolveEngine: unsupported runtime \"${runtime}\"`)\n }\n if (!modelEntry.formats[fmt]) {\n // Fallback: if the requested format isn't available but ONNX is, use ONNX\n // (ONNX Runtime can use CoreML/CUDA execution providers automatically)\n if (fmt !== 'onnx' && modelEntry.formats['onnx']) {\n selectedFormat = 'onnx'\n selectedBackend = backend || 'cpu'\n } else {\n throw new Error(\n `resolveEngine: model ${modelEntry.id} has no ${fmt} format for runtime ${runtime}`,\n )\n }\n } else {\n selectedFormat = fmt\n // For onnx runtime, use the provided backend; otherwise use the runtime name\n selectedBackend = runtime === 'onnx' ? (backend || 'cpu') : runtime\n }\n }\n\n // Download model and extra files via the unified service\n let modelPath: string\n\n if (models) {\n // Use the unified ModelDownloadService\n modelPath = await models.ensure(modelEntry.id, selectedFormat)\n } else {\n // Fallback: direct filesystem check (no download capability)\n modelPath = modelFilePath(modelsDir, modelEntry, selectedFormat)\n if (!modelExists(modelPath)) {\n throw new Error(\n `resolveEngine: model file not found at ${modelPath} and no model service provided`,\n )\n }\n }\n\n log.info('Engine resolved', { meta: { format: selectedFormat, backend: selectedBackend, modelId: modelEntry.id } })\n\n // NodeInferenceEngine handles ONNX format only (with any ONNX backend including CoreML provider).\n // Native .mlpackage/.mlmodel files go to PythonInferenceEngine below.\n if (selectedFormat === 'onnx') {\n const engine = new NodeInferenceEngine(modelPath, selectedBackend, extractModelMeta(modelEntry), options.logger)\n await engine.initialize()\n return { engine, format: selectedFormat, modelPath }\n }\n\n // For non-ONNX formats, try PythonInferenceEngine\n const effectiveRuntime = runtime === 'auto' ? selectedBackend : runtime\n\n // Auto-discover python if not provided but needed\n let { pythonPath } = options\n if (!pythonPath) {\n const { execFileSync: efs } = await import('node:child_process')\n for (const cmd of ['python3', 'python']) {\n try { efs(cmd, ['--version'], { timeout: 3000, stdio: 'ignore' }); pythonPath = cmd; break } catch { /* not found */ }\n }\n }\n const scriptName = CANONICAL_PYTHON_SCRIPT[effectiveRuntime]\n\n if (scriptName && pythonPath) {\n // Resolve python script path -- search multiple locations:\n // - src/shared/ -> ../../python/ (source development)\n // - dist/shared/ -> ../../python/ (installed addon with python/ at package root)\n // - dist/ -> ../python/ (flat dist)\n const candidates = [\n path.join(__dirname, '../../python', scriptName),\n path.join(__dirname, '../python', scriptName),\n path.join(__dirname, '../../../python', scriptName),\n ]\n const scriptPath = candidates.find(p => fs.existsSync(p))\n if (!scriptPath) {\n throw new Error(\n `resolveEngine: Python script \"${scriptName}\" not found. Searched:\\n${candidates.join('\\n')}`,\n )\n }\n const inputSize = Math.max(modelEntry.inputSize.width, modelEntry.inputSize.height)\n const engine = new PythonInferenceEngine(pythonPath, scriptPath, effectiveRuntime as DetectionRuntime, modelPath, [\n `--input-size=${inputSize}`,\n `--confidence=0.25`,\n ], options.logger)\n await engine.initialize()\n return { engine, format: selectedFormat, modelPath }\n }\n\n // Final fallback: use ONNX CPU if available\n const fallbackPath = modelFilePath(modelsDir, modelEntry, 'onnx')\n if (modelEntry.formats['onnx'] && modelExists(fallbackPath)) {\n const engine = new NodeInferenceEngine(fallbackPath, 'cpu', extractModelMeta(modelEntry), options.logger)\n await engine.initialize()\n return { engine, format: 'onnx', modelPath: fallbackPath }\n }\n\n throw new Error(\n `resolveEngine: format ${selectedFormat} is not yet supported by NodeInferenceEngine, ` +\n `no Python runtime is available, and no ONNX fallback exists`,\n )\n}\n\n/** Probe which ONNX execution providers are available on this system */\nexport async function probeOnnxBackends(): Promise<string[]> {\n const available: string[] = ['cpu'] // CPU is always available\n\n try {\n const ort = await import('onnxruntime-node')\n const providers: string[] = ort.env?.webgl?.disabled !== undefined\n ? (ort.InferenceSession.getAvailableProviders?.() ?? [])\n : []\n\n for (const p of providers) {\n const normalized = p.toLowerCase().replace('executionprovider', '')\n if (normalized === 'coreml') available.push('coreml')\n else if (normalized === 'cuda') available.push('cuda')\n else if (normalized === 'tensorrt') available.push('tensorrt')\n }\n } catch {\n // onnxruntime-node may not be installed; CPU only\n }\n\n // Platform-specific hints when getAvailableProviders isn't exposed\n if (process.platform === 'darwin' && !available.includes('coreml')) {\n available.push('coreml')\n }\n\n return [...new Set(available)]\n}\n","import sharp from 'sharp'\nimport type { BoundingBox } from '@camstack/types'\n\n/** Decode JPEG to raw RGB pixels */\nexport async function jpegToRgb(\n jpeg: Buffer,\n): Promise<{ data: Buffer; width: number; height: number }> {\n const { data, info } = await sharp(jpeg)\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true })\n return { data, width: info.width, height: info.height }\n}\n\n/** Crop a region from a JPEG buffer */\nexport async function cropRegion(jpeg: Buffer, roi: BoundingBox): Promise<Buffer> {\n return sharp(jpeg)\n .extract({\n left: Math.round(roi.x),\n top: Math.round(roi.y),\n width: Math.round(roi.w),\n height: Math.round(roi.h),\n })\n .jpeg()\n .toBuffer()\n}\n\n/** Letterbox resize for YOLO: resize preserving aspect ratio, pad to square */\nexport async function letterbox(\n jpeg: Buffer,\n targetSize: number,\n): Promise<{\n data: Float32Array\n scale: number\n padX: number\n padY: number\n originalWidth: number\n originalHeight: number\n}> {\n const meta = await sharp(jpeg).metadata()\n const originalWidth = meta.width ?? 0\n const originalHeight = meta.height ?? 0\n\n const scale = Math.min(targetSize / originalWidth, targetSize / originalHeight)\n const scaledWidth = Math.round(originalWidth * scale)\n const scaledHeight = Math.round(originalHeight * scale)\n\n const padX = Math.floor((targetSize - scaledWidth) / 2)\n const padY = Math.floor((targetSize - scaledHeight) / 2)\n\n const { data } = await sharp(jpeg)\n .resize(scaledWidth, scaledHeight)\n .extend({\n top: padY,\n bottom: targetSize - scaledHeight - padY,\n left: padX,\n right: targetSize - scaledWidth - padX,\n background: { r: 114, g: 114, b: 114 },\n })\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true })\n\n // Convert HWC uint8 to CHW float [0,1]\n const numPixels = targetSize * targetSize\n const float32 = new Float32Array(3 * numPixels)\n for (let i = 0; i < numPixels; i++) {\n const srcBase = i * 3\n float32[0 * numPixels + i] = (data[srcBase]! / 255)\n float32[1 * numPixels + i] = (data[srcBase + 1]! / 255)\n float32[2 * numPixels + i] = (data[srcBase + 2]! / 255)\n }\n\n return { data: float32, scale, padX, padY, originalWidth, originalHeight }\n}\n\n/** Resize and normalize to Float32Array */\nexport async function resizeAndNormalize(\n jpeg: Buffer,\n targetWidth: number,\n targetHeight: number,\n normalization: 'zero-one' | 'imagenet' | 'none',\n layout: 'nchw' | 'nhwc',\n): Promise<Float32Array> {\n const { data } = await sharp(jpeg)\n .resize(targetWidth, targetHeight, { fit: 'fill' })\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true })\n\n const numPixels = targetWidth * targetHeight\n const float32 = new Float32Array(3 * numPixels)\n\n // ImageNet mean and std per channel\n const mean = [0.485, 0.456, 0.406]\n const std = [0.229, 0.224, 0.225]\n\n if (layout === 'nchw') {\n for (let i = 0; i < numPixels; i++) {\n const srcBase = i * 3\n for (let c = 0; c < 3; c++) {\n const raw = data[srcBase + c]! / 255\n let val: number\n if (normalization === 'zero-one') {\n val = raw\n } else if (normalization === 'imagenet') {\n val = (raw - mean[c]!) / std[c]!\n } else {\n val = data[srcBase + c]!\n }\n float32[c * numPixels + i] = val\n }\n }\n } else {\n // nhwc\n for (let i = 0; i < numPixels; i++) {\n const srcBase = i * 3\n for (let c = 0; c < 3; c++) {\n const raw = data[srcBase + c]! / 255\n let val: number\n if (normalization === 'zero-one') {\n val = raw\n } else if (normalization === 'imagenet') {\n val = (raw - mean[c]!) / std[c]!\n } else {\n val = data[srcBase + c]!\n }\n float32[i * 3 + c] = val\n }\n }\n }\n\n return float32\n}\n\n/** Convert raw RGB to grayscale Uint8Array */\nexport function rgbToGrayscale(rgb: Buffer, width: number, height: number): Uint8Array {\n const numPixels = width * height\n const gray = new Uint8Array(numPixels)\n for (let i = 0; i < numPixels; i++) {\n const r = rgb[i * 3]!\n const g = rgb[i * 3 + 1]!\n const b = rgb[i * 3 + 2]!\n // BT.601 luma\n gray[i] = Math.round(0.299 * r + 0.587 * g + 0.114 * b)\n }\n return gray\n}\n","import type { IInferenceEngine, InferenceInput, DetectionRuntime, DetectionDevice, EngineOutput, LetterboxMeta, ModelInputMeta, IScopedLogger } from '@camstack/types'\nimport type { InferenceSession } from 'onnxruntime-node'\nimport { letterbox, resizeAndNormalize } from './image-utils.js'\nimport { createNoopLogger } from './noop-logger.js'\nimport * as path from 'node:path'\n\nconst BACKEND_TO_PROVIDER: Readonly<Record<string, string>> = {\n cpu: 'cpu',\n coreml: 'coreml',\n cuda: 'cuda',\n tensorrt: 'tensorrt',\n dml: 'dml',\n} as const\n\nconst BACKEND_TO_DEVICE: Readonly<Record<string, DetectionDevice>> = {\n cpu: 'cpu',\n coreml: 'gpu-mps',\n cuda: 'gpu-cuda',\n tensorrt: 'tensorrt',\n} as const\n\nexport class NodeInferenceEngine implements IInferenceEngine {\n readonly runtime: DetectionRuntime = 'onnx'\n readonly device: DetectionDevice\n private session: InferenceSession | null = null\n private readonly log: IScopedLogger\n\n constructor(\n private readonly modelPath: string,\n private readonly backend: string,\n private readonly modelMeta: ModelInputMeta,\n logger?: IScopedLogger,\n ) {\n this.device = (BACKEND_TO_DEVICE[backend] ?? 'cpu') as DetectionDevice\n this.log = logger ?? createNoopLogger()\n }\n\n async initialize(): Promise<void> {\n const ort = await import('onnxruntime-node')\n const provider = BACKEND_TO_PROVIDER[this.backend] ?? 'cpu'\n\n // Resolve absolute path\n const absModelPath = path.isAbsolute(this.modelPath)\n ? this.modelPath\n : path.resolve(process.cwd(), this.modelPath)\n\n const sessionOptions = {\n executionProviders: [provider],\n }\n\n this.session = await ort.InferenceSession.create(absModelPath, sessionOptions)\n this.log.info('ONNX session loaded', { meta: { modelPath: absModelPath, backend: this.backend, provider } })\n }\n\n async infer(input: InferenceInput): Promise<EngineOutput> {\n // ONNX preprocess (sharp) reads JPEG bytes; raw inputs are\n // re-encoded to JPEG once before preprocess. Embedding paths almost\n // always feed JPEG crops, so this fallback rarely fires.\n const jpeg = input.kind === 'jpeg'\n ? input.data\n : await this.encodeRawAsJpeg(input.data, input.width, input.height, input.format)\n const { data, letterboxMeta } = await this.preprocess(jpeg)\n const { inputSize } = this.modelMeta\n\n const inputShape =\n this.modelMeta.preprocessMode === 'letterbox'\n ? [1, 3, inputSize.height, inputSize.width]\n : [1, 3, inputSize.height, inputSize.width]\n\n const start = Date.now()\n let result: { tensor: Float32Array } | { tensors: Record<string, Float32Array> }\n try {\n result = await this.runSession(data, inputShape)\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err))\n this.log.error('Inference failed', { meta: { error: error.message } })\n throw error\n }\n const durationMs = Date.now() - start\n\n if ('tensor' in result) {\n this.log.debug('Inference complete', { meta: { durationMs, outputKeys: ['tensor'], preprocessMode: this.modelMeta.preprocessMode } })\n return { tensor: result.tensor, letterbox: letterboxMeta, inferenceMs: durationMs }\n }\n this.log.debug('Inference complete', { meta: { durationMs, outputKeys: Object.keys(result.tensors), preprocessMode: this.modelMeta.preprocessMode } })\n return { tensors: result.tensors, letterbox: letterboxMeta, inferenceMs: durationMs }\n }\n\n /** Preprocess JPEG to Float32Array using the configured mode */\n private async preprocess(\n jpeg: Buffer,\n ): Promise<{ data: Float32Array; letterboxMeta?: LetterboxMeta }> {\n const { inputSize, inputNormalization, inputLayout, preprocessMode } = this.modelMeta\n\n if (preprocessMode === 'letterbox') {\n const targetSize = Math.max(inputSize.width, inputSize.height)\n const result = await letterbox(jpeg, targetSize)\n const letterboxMeta: LetterboxMeta = {\n scale: result.scale,\n padX: result.padX,\n padY: result.padY,\n originalWidth: result.originalWidth,\n originalHeight: result.originalHeight,\n }\n return { data: result.data, letterboxMeta }\n }\n\n // preprocessMode === 'resize'\n const data = await resizeAndNormalize(\n jpeg,\n inputSize.width,\n inputSize.height,\n inputNormalization,\n inputLayout,\n )\n return { data }\n }\n\n private async encodeRawAsJpeg(\n raw: Buffer,\n width: number,\n height: number,\n format: 'rgb' | 'bgr' | 'gray',\n ): Promise<Buffer> {\n const sharp = (await import('sharp')).default\n const channels = format === 'gray' ? 1 : 3\n return sharp(raw, { raw: { width, height, channels } })\n .jpeg({ quality: 80, mozjpeg: false })\n .toBuffer()\n }\n\n /** Run an ONNX session with a single input, handling both single and multi-output models */\n private async runSession(\n input: Float32Array,\n inputShape: readonly number[],\n ): Promise<{ tensor: Float32Array } | { tensors: Record<string, Float32Array> }> {\n if (!this.session) {\n throw new Error('NodeInferenceEngine: not initialized — call initialize() first')\n }\n\n const ort = await import('onnxruntime-node')\n const sess = this.session\n\n const inputName: string = sess.inputNames[0]!\n const tensor = new ort.Tensor('float32', input, [...inputShape])\n const feeds: Record<string, InstanceType<typeof ort.Tensor>> = { [inputName]: tensor }\n\n const results = await sess.run(feeds)\n const outputNames: readonly string[] = sess.outputNames\n\n if (outputNames.length === 1) {\n const outputName = outputNames[0]!\n return { tensor: results[outputName]!.data }\n }\n\n const tensors: Record<string, Float32Array> = {}\n for (const name of outputNames) {\n tensors[name] = results[name]!.data\n }\n return { tensors }\n }\n\n async run(input: Float32Array, inputShape: readonly number[]): Promise<Float32Array> {\n const result = await this.runSession(input, inputShape)\n if ('tensor' in result) return result.tensor\n // Return first output tensor for multi-output models\n const firstKey = Object.keys(result.tensors)[0]!\n return result.tensors[firstKey]!\n }\n\n async dispose(): Promise<void> {\n // onnxruntime-node sessions don't have explicit close in all versions\n // but we clear the reference\n this.session = null\n this.log.debug('Session disposed')\n }\n}\n","import type { IInferenceEngine, InferenceInput, DetectionRuntime, DetectionDevice, IAddonDepsManager, EngineOutput, IScopedLogger } from '@camstack/types'\nimport { spawn, type ChildProcess } from 'node:child_process'\nimport { createNoopLogger } from './noop-logger.js'\n\nexport class PythonInferenceEngine implements IInferenceEngine {\n readonly runtime: DetectionRuntime\n readonly device: DetectionDevice\n private process: ChildProcess | null = null\n private receiveBuffer: Buffer = Buffer.alloc(0)\n private pendingResolve: ((value: Record<string, unknown>) => void) | null = null\n private pendingReject: ((reason: Error) => void) | null = null\n private readonly log: IScopedLogger\n\n constructor(\n private readonly pythonPath: string,\n private readonly scriptPath: string,\n runtime: DetectionRuntime,\n private readonly modelPath: string,\n private readonly extraArgs: readonly string[] = [],\n logger?: IScopedLogger,\n ) {\n this.runtime = runtime\n // Determine device from runtime\n const runtimeDeviceMap: Readonly<Record<DetectionRuntime, DetectionDevice>> = {\n onnx: 'cpu',\n coreml: 'gpu-mps',\n pytorch: 'cpu',\n openvino: 'cpu',\n tflite: 'cpu',\n }\n this.device = runtimeDeviceMap[runtime]\n this.log = logger ?? createNoopLogger()\n }\n\n async initialize(): Promise<void> {\n const args = [this.scriptPath, this.modelPath, ...this.extraArgs]\n this.process = spawn(this.pythonPath, args, {\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n if (!this.process.stdout || !this.process.stdin) {\n throw new Error('PythonInferenceEngine: failed to create process pipes')\n }\n\n this.log.info('Python process started', { meta: { pythonPath: this.pythonPath, scriptPath: this.scriptPath, modelPath: this.modelPath } })\n\n this.process.stderr?.on('data', (chunk: Buffer) => {\n const lines = chunk.toString().split('\\n')\n for (const line of lines) {\n const trimmed = line.trim()\n if (trimmed) {\n this.log.warn(trimmed)\n }\n }\n })\n\n this.process.on('error', (err) => {\n this.log.error('Process error', { meta: { error: err.message } })\n this.pendingReject?.(err)\n this.pendingReject = null\n this.pendingResolve = null\n })\n\n this.process.on('exit', (code) => {\n if (code !== 0) {\n this.log.error('Process exited', { meta: { code } })\n const err = new Error(`PythonInferenceEngine: process exited with code ${code}`)\n this.pendingReject?.(err)\n this.pendingReject = null\n this.pendingResolve = null\n }\n })\n\n this.process.stdout.on('data', (chunk: Buffer) => {\n this.receiveBuffer = Buffer.concat([this.receiveBuffer, chunk])\n this._tryReceive()\n })\n\n // Give the process a moment to start up and load the model\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => resolve(), 2000)\n this.process?.on('error', (err) => {\n clearTimeout(timeout)\n reject(err)\n })\n this.process?.on('exit', (code) => {\n clearTimeout(timeout)\n if (code !== 0) {\n reject(new Error(`PythonInferenceEngine: process exited early with code ${code}`))\n }\n })\n })\n }\n\n private _tryReceive(): void {\n // Binary IPC: [4 bytes LE uint32 length][JSON bytes]\n if (this.receiveBuffer.length < 4) return\n\n const length = this.receiveBuffer.readUInt32LE(0)\n if (this.receiveBuffer.length < 4 + length) return\n\n const jsonBytes = this.receiveBuffer.subarray(4, 4 + length)\n this.receiveBuffer = this.receiveBuffer.subarray(4 + length)\n\n const resolve = this.pendingResolve\n const reject = this.pendingReject\n this.pendingResolve = null\n this.pendingReject = null\n\n if (!resolve) return\n\n try {\n const parsed = JSON.parse(jsonBytes.toString('utf8')) as Record<string, unknown>\n resolve(parsed)\n } catch (err) {\n reject?.(err instanceof Error ? err : new Error(String(err)))\n }\n }\n\n /** Run inference, returning structured detection results. Encodes raw input to JPEG when needed. */\n async infer(input: InferenceInput): Promise<EngineOutput> {\n const start = Date.now()\n const jpeg = input.kind === 'jpeg'\n ? input.data\n : await this.encodeRawAsJpeg(input.data, input.width, input.height, input.format)\n const result = await this.sendJpeg(jpeg)\n const durationMs = Date.now() - start\n this.log.debug('Inference complete', { meta: { durationMs } })\n return { structured: result, inferenceMs: durationMs }\n }\n\n private async encodeRawAsJpeg(\n raw: Buffer,\n width: number,\n height: number,\n format: 'rgb' | 'bgr' | 'gray',\n ): Promise<Buffer> {\n const sharp = (await import('sharp')).default\n const channels = format === 'gray' ? 1 : 3\n return sharp(raw, { raw: { width, height, channels } })\n .jpeg({ quality: 80, mozjpeg: false })\n .toBuffer()\n }\n\n /** Send JPEG buffer via binary IPC, receive JSON detection results */\n private async sendJpeg(jpeg: Buffer): Promise<Record<string, unknown>> {\n if (!this.process?.stdin) {\n throw new Error('PythonInferenceEngine: process not initialized')\n }\n\n return new Promise<Record<string, unknown>>((resolve, reject) => {\n this.pendingResolve = resolve\n this.pendingReject = reject\n\n // Binary IPC: [4 bytes LE uint32 length][JPEG bytes]\n const lengthBuf = Buffer.allocUnsafe(4)\n lengthBuf.writeUInt32LE(jpeg.length, 0)\n this.process!.stdin!.write(Buffer.concat([lengthBuf, jpeg]))\n })\n }\n\n async dispose(): Promise<void> {\n const proc = this.process\n if (!proc) return\n\n this.process = null\n proc.stdin?.end()\n proc.kill('SIGTERM')\n\n // Wait up to 5s for graceful exit, then force-kill\n const exited = await new Promise<boolean>((resolve) => {\n const timer = setTimeout(() => {\n resolve(false)\n }, 5_000)\n proc.once('exit', () => {\n clearTimeout(timer)\n resolve(true)\n })\n })\n\n if (!exited) {\n try { proc.kill('SIGKILL') } catch { /* already dead */ }\n this.log.warn('Python process did not exit gracefully — sent SIGKILL')\n } else {\n this.log.debug('Python process terminated')\n }\n }\n}\n\n/**\n * Resolve Python binary for ML inference. Priority:\n * 1. Explicit config pythonPath\n * 2. Embedded (data/deps/python/bin/python3)\n * 3. System PATH (python3, python)\n * 4. Download standalone Python\n *\n * Returns null if Python is not available.\n */\nexport async function resolvePythonBinary(\n configPath: string | undefined,\n deps: IAddonDepsManager,\n): Promise<string | null> {\n if (configPath) return configPath\n return deps.ensurePython()\n}\n","export interface ClipModelMeta {\n readonly imageModelId: string\n readonly textModelId: string\n readonly embeddingDim: number\n readonly inputSize: number\n readonly tokenizerType: 'clip' | 'siglip'\n}\n\nexport const CLIP_MODEL_META: Readonly<Record<string, ClipModelMeta>> = {\n 'clip-vit-b32': {\n imageModelId: 'clip-vit-b32',\n textModelId: 'clip-vit-b32-text',\n embeddingDim: 512,\n inputSize: 224,\n tokenizerType: 'clip',\n },\n 'clip-vit-b16': {\n imageModelId: 'clip-vit-b16',\n textModelId: 'clip-vit-b16-text',\n embeddingDim: 512,\n inputSize: 224,\n tokenizerType: 'clip',\n },\n 'siglip2-b16-256': {\n imageModelId: 'siglip2-b16-256',\n textModelId: 'siglip2-b16-256-text',\n embeddingDim: 768,\n inputSize: 256,\n tokenizerType: 'siglip',\n },\n}\n\nexport const DEFAULT_CLIP_MODEL = 'clip-vit-b32'\n\nexport function getModelMeta(modelId: string): ClipModelMeta {\n return CLIP_MODEL_META[modelId] ?? CLIP_MODEL_META[DEFAULT_CLIP_MODEL]!\n}\n","// CLIP normalization constants (OpenAI CLIP)\nconst CLIP_MEAN = [0.48145466, 0.4578275, 0.40821073] as const\nconst CLIP_STD = [0.26862954, 0.26130258, 0.27577711] as const\n\n/**\n * Preprocess raw RGB buffer for CLIP inference.\n * Resizes (nearest-neighbor for speed), normalizes with CLIP mean/std, outputs NCHW Float32Array.\n * For production use, the caller should use sharp to resize the JPEG to targetW×targetH\n * before calling this with the raw RGB. This function handles normalization + layout.\n */\nexport function preprocessForClip(\n rgb: Buffer,\n srcWidth: number,\n srcHeight: number,\n targetWidth: number,\n targetHeight: number,\n): Float32Array {\n const pixels = targetWidth * targetHeight\n const result = new Float32Array(3 * pixels)\n\n for (let y = 0; y < targetHeight; y++) {\n for (let x = 0; x < targetWidth; x++) {\n // Nearest-neighbor sampling\n const srcX = Math.min(Math.floor((x / targetWidth) * srcWidth), srcWidth - 1)\n const srcY = Math.min(Math.floor((y / targetHeight) * srcHeight), srcHeight - 1)\n const srcIdx = (srcY * srcWidth + srcX) * 3\n const dstIdx = y * targetWidth + x\n\n for (let c = 0; c < 3; c++) {\n const val = (rgb[srcIdx + c] ?? 0) / 255.0\n result[c * pixels + dstIdx] = (val - CLIP_MEAN[c]!) / CLIP_STD[c]!\n }\n }\n }\n\n return result\n}\n\n/**\n * L2-normalize a vector in-place and return it.\n */\nexport function l2Normalize(vec: Float32Array): Float32Array {\n let norm = 0\n for (let i = 0; i < vec.length; i++) norm += vec[i]! * vec[i]!\n norm = Math.sqrt(norm)\n if (norm > 0) {\n for (let i = 0; i < vec.length; i++) vec[i]! /= norm\n }\n return vec\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACUA,IAAAA,gBAAsD;AAEtD,kBAAqC;;;ACV9B,IAAM,oBAAkD;AAAA,EAC7D;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,WAAW,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,IACrC,QAAQ,CAAC;AAAA,IACT,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,SAAS;AAAA,MACP,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,WAAW,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,IACrC,QAAQ,CAAC;AAAA,IACT,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,SAAS;AAAA,MACP,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,WAAW,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,IACrC,QAAQ,CAAC;AAAA,IACT,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,SAAS;AAAA,MACP,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,mBAAiD;AAAA,EAC5D;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,WAAW,EAAE,OAAO,GAAG,QAAQ,EAAE;AAAA,IACjC,QAAQ,CAAC;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,WAAW,EAAE,OAAO,GAAG,QAAQ,EAAE;AAAA,IACjC,QAAQ,CAAC;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,WAAW,EAAE,OAAO,GAAG,QAAQ,EAAE;AAAA,IACjC,QAAQ,CAAC;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACF;;;ACxFA,IAAM,OAAO,MAAY;AAA0B;AAE5C,SAAS,mBAAkC;AAChD,QAAM,SAAwB;AAAA,IAC5B,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO,MAAM;AAAA,IACb,UAAU,CAAC,UAAmB;AAAA,EAChC;AACA,SAAO;AACT;;;ACXA,WAAsB;AAEtB,IAAM,oBAA+D;AAAA,EACnE,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,UAAU;AACZ;AAMO,IAAM,sBAAN,MAAsD;AAAA,EAM3D,YACmB,WACA,SACjB,QACA;AAHiB;AACA;AAGjB,SAAK,SAAS,kBAAkB,OAAO,KAAK;AAC5C,SAAK,MAAM,UAAU,iBAAiB;AAAA,EACxC;AAAA,EANmB;AAAA,EACA;AAAA,EAPV,UAA4B;AAAA,EAC5B;AAAA,EACD,UAAmC;AAAA,EAC1B;AAAA,EAWjB,MAAM,aAA4B;AAChC,UAAM,MAAM,MAAM,OAAO,kBAAkB;AAC3C,UAAM,WAAW,KAAK,YAAY,WAAW,WAAW,KAAK,YAAY,SAAS,SAAS;AAE3F,UAAM,eAAoB,gBAAW,KAAK,SAAS,IAC/C,KAAK,YACA,aAAQ,QAAQ,IAAI,GAAG,KAAK,SAAS;AAE9C,SAAK,UAAU,MAAM,IAAI,iBAAiB,OAAO,cAAc;AAAA,MAC7D,oBAAoB,CAAC,QAAQ;AAAA,IAC/B,CAAC;AACD,SAAK,IAAI,KAAK,uBAAuB,EAAE,MAAM,EAAE,WAAW,cAAc,SAAS,KAAK,SAAS,SAAS,EAAE,CAAC;AAAA,EAC7G;AAAA,EAEA,MAAM,IAAI,OAAqB,YAAsD;AACnF,QAAI,CAAC,KAAK,SAAS;AACjB,YAAM,IAAI,MAAM,qEAAgE;AAAA,IAClF;AAEA,UAAM,MAAM,MAAM,OAAO,kBAAkB;AAC3C,UAAM,OAAO,KAAK;AAElB,UAAM,YAAoB,KAAK,WAAW,CAAC;AAC3C,UAAM,SAAS,IAAI,IAAI,OAAO,WAAW,OAAO,CAAC,GAAG,UAAU,CAAC;AAC/D,UAAM,QAAyD,EAAE,CAAC,SAAS,GAAG,OAAO;AAErF,UAAM,QAAQ,KAAK,IAAI;AACvB,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,KAAK,IAAI,KAAK;AAAA,IAChC,SAAS,KAAK;AACZ,YAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,WAAK,IAAI,MAAM,oBAAoB,EAAE,MAAM,EAAE,OAAO,MAAM,QAAQ,EAAE,CAAC;AACrE,YAAM;AAAA,IACR;AAEA,UAAM,aAAqB,KAAK,YAAY,CAAC;AAC7C,SAAK,IAAI,MAAM,sBAAsB,EAAE,MAAM,EAAE,YAAY,KAAK,IAAI,IAAI,OAAO,YAAY,CAAC,UAAU,GAAG,gBAAgB,aAAa,EAAE,CAAC;AACzI,WAAO,QAAQ,UAAU,EAAG;AAAA,EAC9B;AAAA,EAEA,MAAM,UAAyB;AAC7B,SAAK,UAAU;AACf,SAAK,IAAI,MAAM,kBAAkB;AAAA,EACnC;AACF;;;AC/CA,mBAIO;AACP,SAAoB;AACpB,IAAAC,QAAsB;;;ACnCtB,mBAAkB;AA4BlB,eAAsB,UACpB,MACA,YAQC;AACD,QAAM,OAAO,UAAM,aAAAC,SAAM,IAAI,EAAE,SAAS;AACxC,QAAM,gBAAgB,KAAK,SAAS;AACpC,QAAM,iBAAiB,KAAK,UAAU;AAEtC,QAAM,QAAQ,KAAK,IAAI,aAAa,eAAe,aAAa,cAAc;AAC9E,QAAM,cAAc,KAAK,MAAM,gBAAgB,KAAK;AACpD,QAAM,eAAe,KAAK,MAAM,iBAAiB,KAAK;AAEtD,QAAM,OAAO,KAAK,OAAO,aAAa,eAAe,CAAC;AACtD,QAAM,OAAO,KAAK,OAAO,aAAa,gBAAgB,CAAC;AAEvD,QAAM,EAAE,KAAK,IAAI,UAAM,aAAAA,SAAM,IAAI,EAC9B,OAAO,aAAa,YAAY,EAChC,OAAO;AAAA,IACN,KAAK;AAAA,IACL,QAAQ,aAAa,eAAe;AAAA,IACpC,MAAM;AAAA,IACN,OAAO,aAAa,cAAc;AAAA,IAClC,YAAY,EAAE,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI;AAAA,EACvC,CAAC,EACA,YAAY,EACZ,IAAI,EACJ,SAAS,EAAE,mBAAmB,KAAK,CAAC;AAGvC,QAAM,YAAY,aAAa;AAC/B,QAAM,UAAU,IAAI,aAAa,IAAI,SAAS;AAC9C,WAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,UAAM,UAAU,IAAI;AACpB,YAAQ,IAAI,YAAY,CAAC,IAAK,KAAK,OAAO,IAAK;AAC/C,YAAQ,IAAI,YAAY,CAAC,IAAK,KAAK,UAAU,CAAC,IAAK;AACnD,YAAQ,IAAI,YAAY,CAAC,IAAK,KAAK,UAAU,CAAC,IAAK;AAAA,EACrD;AAEA,SAAO,EAAE,MAAM,SAAS,OAAO,MAAM,MAAM,eAAe,eAAe;AAC3E;AAGA,eAAsB,mBACpB,MACA,aACA,cACA,eACA,QACuB;AACvB,QAAM,EAAE,KAAK,IAAI,UAAM,aAAAA,SAAM,IAAI,EAC9B,OAAO,aAAa,cAAc,EAAE,KAAK,OAAO,CAAC,EACjD,YAAY,EACZ,IAAI,EACJ,SAAS,EAAE,mBAAmB,KAAK,CAAC;AAEvC,QAAM,YAAY,cAAc;AAChC,QAAM,UAAU,IAAI,aAAa,IAAI,SAAS;AAG9C,QAAM,OAAO,CAAC,OAAO,OAAO,KAAK;AACjC,QAAM,MAAM,CAAC,OAAO,OAAO,KAAK;AAEhC,MAAI,WAAW,QAAQ;AACrB,aAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,YAAM,UAAU,IAAI;AACpB,eAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,cAAM,MAAM,KAAK,UAAU,CAAC,IAAK;AACjC,YAAI;AACJ,YAAI,kBAAkB,YAAY;AAChC,gBAAM;AAAA,QACR,WAAW,kBAAkB,YAAY;AACvC,iBAAO,MAAM,KAAK,CAAC,KAAM,IAAI,CAAC;AAAA,QAChC,OAAO;AACL,gBAAM,KAAK,UAAU,CAAC;AAAA,QACxB;AACA,gBAAQ,IAAI,YAAY,CAAC,IAAI;AAAA,MAC/B;AAAA,IACF;AAAA,EACF,OAAO;AAEL,aAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,YAAM,UAAU,IAAI;AACpB,eAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,cAAM,MAAM,KAAK,UAAU,CAAC,IAAK;AACjC,YAAI;AACJ,YAAI,kBAAkB,YAAY;AAChC,gBAAM;AAAA,QACR,WAAW,kBAAkB,YAAY;AACvC,iBAAO,MAAM,KAAK,CAAC,KAAM,IAAI,CAAC;AAAA,QAChC,OAAO;AACL,gBAAM,KAAK,UAAU,CAAC;AAAA,QACxB;AACA,gBAAQ,IAAI,IAAI,CAAC,IAAI;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACjIA,IAAAC,QAAsB;AAEtB,IAAM,sBAAwD;AAAA,EAC5D,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,UAAU;AAAA,EACV,KAAK;AACP;AAEA,IAAMC,qBAA+D;AAAA,EACnE,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,UAAU;AACZ;AAEO,IAAM,sBAAN,MAAsD;AAAA,EAM3D,YACmB,WACA,SACA,WACjB,QACA;AAJiB;AACA;AACA;AAGjB,SAAK,SAAUA,mBAAkB,OAAO,KAAK;AAC7C,SAAK,MAAM,UAAU,iBAAiB;AAAA,EACxC;AAAA,EAPmB;AAAA,EACA;AAAA,EACA;AAAA,EARV,UAA4B;AAAA,EAC5B;AAAA,EACD,UAAmC;AAAA,EAC1B;AAAA,EAYjB,MAAM,aAA4B;AAChC,UAAM,MAAM,MAAM,OAAO,kBAAkB;AAC3C,UAAM,WAAW,oBAAoB,KAAK,OAAO,KAAK;AAGtD,UAAM,eAAoB,iBAAW,KAAK,SAAS,IAC/C,KAAK,YACA,cAAQ,QAAQ,IAAI,GAAG,KAAK,SAAS;AAE9C,UAAM,iBAAiB;AAAA,MACrB,oBAAoB,CAAC,QAAQ;AAAA,IAC/B;AAEA,SAAK,UAAU,MAAM,IAAI,iBAAiB,OAAO,cAAc,cAAc;AAC7E,SAAK,IAAI,KAAK,uBAAuB,EAAE,MAAM,EAAE,WAAW,cAAc,SAAS,KAAK,SAAS,SAAS,EAAE,CAAC;AAAA,EAC7G;AAAA,EAEA,MAAM,MAAM,OAA8C;AAIxD,UAAM,OAAO,MAAM,SAAS,SACxB,MAAM,OACN,MAAM,KAAK,gBAAgB,MAAM,MAAM,MAAM,OAAO,MAAM,QAAQ,MAAM,MAAM;AAClF,UAAM,EAAE,MAAM,cAAc,IAAI,MAAM,KAAK,WAAW,IAAI;AAC1D,UAAM,EAAE,UAAU,IAAI,KAAK;AAE3B,UAAM,aACJ,KAAK,UAAU,mBAAmB,cAC9B,CAAC,GAAG,GAAG,UAAU,QAAQ,UAAU,KAAK,IACxC,CAAC,GAAG,GAAG,UAAU,QAAQ,UAAU,KAAK;AAE9C,UAAM,QAAQ,KAAK,IAAI;AACvB,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,KAAK,WAAW,MAAM,UAAU;AAAA,IACjD,SAAS,KAAK;AACZ,YAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,WAAK,IAAI,MAAM,oBAAoB,EAAE,MAAM,EAAE,OAAO,MAAM,QAAQ,EAAE,CAAC;AACrE,YAAM;AAAA,IACR;AACA,UAAM,aAAa,KAAK,IAAI,IAAI;AAEhC,QAAI,YAAY,QAAQ;AACtB,WAAK,IAAI,MAAM,sBAAsB,EAAE,MAAM,EAAE,YAAY,YAAY,CAAC,QAAQ,GAAG,gBAAgB,KAAK,UAAU,eAAe,EAAE,CAAC;AACpI,aAAO,EAAE,QAAQ,OAAO,QAAQ,WAAW,eAAe,aAAa,WAAW;AAAA,IACpF;AACA,SAAK,IAAI,MAAM,sBAAsB,EAAE,MAAM,EAAE,YAAY,YAAY,OAAO,KAAK,OAAO,OAAO,GAAG,gBAAgB,KAAK,UAAU,eAAe,EAAE,CAAC;AACrJ,WAAO,EAAE,SAAS,OAAO,SAAS,WAAW,eAAe,aAAa,WAAW;AAAA,EACtF;AAAA;AAAA,EAGA,MAAc,WACZ,MACgE;AAChE,UAAM,EAAE,WAAW,oBAAoB,aAAa,eAAe,IAAI,KAAK;AAE5E,QAAI,mBAAmB,aAAa;AAClC,YAAM,aAAa,KAAK,IAAI,UAAU,OAAO,UAAU,MAAM;AAC7D,YAAM,SAAS,MAAM,UAAU,MAAM,UAAU;AAC/C,YAAM,gBAA+B;AAAA,QACnC,OAAO,OAAO;AAAA,QACd,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,QACb,eAAe,OAAO;AAAA,QACtB,gBAAgB,OAAO;AAAA,MACzB;AACA,aAAO,EAAE,MAAM,OAAO,MAAM,cAAc;AAAA,IAC5C;AAGA,UAAM,OAAO,MAAM;AAAA,MACjB;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,MACV;AAAA,MACA;AAAA,IACF;AACA,WAAO,EAAE,KAAK;AAAA,EAChB;AAAA,EAEA,MAAc,gBACZ,KACA,OACA,QACA,QACiB;AACjB,UAAMC,UAAS,MAAM,OAAO,OAAO,GAAG;AACtC,UAAM,WAAW,WAAW,SAAS,IAAI;AACzC,WAAOA,OAAM,KAAK,EAAE,KAAK,EAAE,OAAO,QAAQ,SAAS,EAAE,CAAC,EACnD,KAAK,EAAE,SAAS,IAAI,SAAS,MAAM,CAAC,EACpC,SAAS;AAAA,EACd;AAAA;AAAA,EAGA,MAAc,WACZ,OACA,YAC+E;AAC/E,QAAI,CAAC,KAAK,SAAS;AACjB,YAAM,IAAI,MAAM,qEAAgE;AAAA,IAClF;AAEA,UAAM,MAAM,MAAM,OAAO,kBAAkB;AAC3C,UAAM,OAAO,KAAK;AAElB,UAAM,YAAoB,KAAK,WAAW,CAAC;AAC3C,UAAM,SAAS,IAAI,IAAI,OAAO,WAAW,OAAO,CAAC,GAAG,UAAU,CAAC;AAC/D,UAAM,QAAyD,EAAE,CAAC,SAAS,GAAG,OAAO;AAErF,UAAM,UAAU,MAAM,KAAK,IAAI,KAAK;AACpC,UAAM,cAAiC,KAAK;AAE5C,QAAI,YAAY,WAAW,GAAG;AAC5B,YAAM,aAAa,YAAY,CAAC;AAChC,aAAO,EAAE,QAAQ,QAAQ,UAAU,EAAG,KAAK;AAAA,IAC7C;AAEA,UAAM,UAAwC,CAAC;AAC/C,eAAW,QAAQ,aAAa;AAC9B,cAAQ,IAAI,IAAI,QAAQ,IAAI,EAAG;AAAA,IACjC;AACA,WAAO,EAAE,QAAQ;AAAA,EACnB;AAAA,EAEA,MAAM,IAAI,OAAqB,YAAsD;AACnF,UAAM,SAAS,MAAM,KAAK,WAAW,OAAO,UAAU;AACtD,QAAI,YAAY,OAAQ,QAAO,OAAO;AAEtC,UAAM,WAAW,OAAO,KAAK,OAAO,OAAO,EAAE,CAAC;AAC9C,WAAO,OAAO,QAAQ,QAAQ;AAAA,EAChC;AAAA,EAEA,MAAM,UAAyB;AAG7B,SAAK,UAAU;AACf,SAAK,IAAI,MAAM,kBAAkB;AAAA,EACnC;AACF;;;AC/KA,gCAAyC;AAGlC,IAAM,wBAAN,MAAwD;AAAA,EAS7D,YACmB,YACA,YACjB,SACiB,WACA,YAA+B,CAAC,GACjD,QACA;AANiB;AACA;AAEA;AACA;AAGjB,SAAK,UAAU;AAEf,UAAM,mBAAwE;AAAA,MAC5E,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU;AAAA,MACV,QAAQ;AAAA,IACV;AACA,SAAK,SAAS,iBAAiB,OAAO;AACtC,SAAK,MAAM,UAAU,iBAAiB;AAAA,EACxC;AAAA,EAlBmB;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EAbV;AAAA,EACA;AAAA,EACD,UAA+B;AAAA,EAC/B,gBAAwB,OAAO,MAAM,CAAC;AAAA,EACtC,iBAAoE;AAAA,EACpE,gBAAkD;AAAA,EACzC;AAAA,EAuBjB,MAAM,aAA4B;AAChC,UAAM,OAAO,CAAC,KAAK,YAAY,KAAK,WAAW,GAAG,KAAK,SAAS;AAChE,SAAK,cAAU,iCAAM,KAAK,YAAY,MAAM;AAAA,MAC1C,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,IAChC,CAAC;AAED,QAAI,CAAC,KAAK,QAAQ,UAAU,CAAC,KAAK,QAAQ,OAAO;AAC/C,YAAM,IAAI,MAAM,uDAAuD;AAAA,IACzE;AAEA,SAAK,IAAI,KAAK,0BAA0B,EAAE,MAAM,EAAE,YAAY,KAAK,YAAY,YAAY,KAAK,YAAY,WAAW,KAAK,UAAU,EAAE,CAAC;AAEzI,SAAK,QAAQ,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AACjD,YAAM,QAAQ,MAAM,SAAS,EAAE,MAAM,IAAI;AACzC,iBAAW,QAAQ,OAAO;AACxB,cAAM,UAAU,KAAK,KAAK;AAC1B,YAAI,SAAS;AACX,eAAK,IAAI,KAAK,OAAO;AAAA,QACvB;AAAA,MACF;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,GAAG,SAAS,CAAC,QAAQ;AAChC,WAAK,IAAI,MAAM,iBAAiB,EAAE,MAAM,EAAE,OAAO,IAAI,QAAQ,EAAE,CAAC;AAChE,WAAK,gBAAgB,GAAG;AACxB,WAAK,gBAAgB;AACrB,WAAK,iBAAiB;AAAA,IACxB,CAAC;AAED,SAAK,QAAQ,GAAG,QAAQ,CAAC,SAAS;AAChC,UAAI,SAAS,GAAG;AACd,aAAK,IAAI,MAAM,kBAAkB,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACnD,cAAM,MAAM,IAAI,MAAM,mDAAmD,IAAI,EAAE;AAC/E,aAAK,gBAAgB,GAAG;AACxB,aAAK,gBAAgB;AACrB,aAAK,iBAAiB;AAAA,MACxB;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,OAAO,GAAG,QAAQ,CAAC,UAAkB;AAChD,WAAK,gBAAgB,OAAO,OAAO,CAAC,KAAK,eAAe,KAAK,CAAC;AAC9D,WAAK,YAAY;AAAA,IACnB,CAAC;AAGD,UAAM,IAAI,QAAc,CAACC,UAAS,WAAW;AAC3C,YAAM,UAAU,WAAW,MAAMA,SAAQ,GAAG,GAAI;AAChD,WAAK,SAAS,GAAG,SAAS,CAAC,QAAQ;AACjC,qBAAa,OAAO;AACpB,eAAO,GAAG;AAAA,MACZ,CAAC;AACD,WAAK,SAAS,GAAG,QAAQ,CAAC,SAAS;AACjC,qBAAa,OAAO;AACpB,YAAI,SAAS,GAAG;AACd,iBAAO,IAAI,MAAM,yDAAyD,IAAI,EAAE,CAAC;AAAA,QACnF;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEQ,cAAoB;AAE1B,QAAI,KAAK,cAAc,SAAS,EAAG;AAEnC,UAAM,SAAS,KAAK,cAAc,aAAa,CAAC;AAChD,QAAI,KAAK,cAAc,SAAS,IAAI,OAAQ;AAE5C,UAAM,YAAY,KAAK,cAAc,SAAS,GAAG,IAAI,MAAM;AAC3D,SAAK,gBAAgB,KAAK,cAAc,SAAS,IAAI,MAAM;AAE3D,UAAMA,WAAU,KAAK;AACrB,UAAM,SAAS,KAAK;AACpB,SAAK,iBAAiB;AACtB,SAAK,gBAAgB;AAErB,QAAI,CAACA,SAAS;AAEd,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,UAAU,SAAS,MAAM,CAAC;AACpD,MAAAA,SAAQ,MAAM;AAAA,IAChB,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,IAC9D;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,MAAM,OAA8C;AACxD,UAAM,QAAQ,KAAK,IAAI;AACvB,UAAM,OAAO,MAAM,SAAS,SACxB,MAAM,OACN,MAAM,KAAK,gBAAgB,MAAM,MAAM,MAAM,OAAO,MAAM,QAAQ,MAAM,MAAM;AAClF,UAAM,SAAS,MAAM,KAAK,SAAS,IAAI;AACvC,UAAM,aAAa,KAAK,IAAI,IAAI;AAChC,SAAK,IAAI,MAAM,sBAAsB,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AAC7D,WAAO,EAAE,YAAY,QAAQ,aAAa,WAAW;AAAA,EACvD;AAAA,EAEA,MAAc,gBACZ,KACA,OACA,QACA,QACiB;AACjB,UAAMC,UAAS,MAAM,OAAO,OAAO,GAAG;AACtC,UAAM,WAAW,WAAW,SAAS,IAAI;AACzC,WAAOA,OAAM,KAAK,EAAE,KAAK,EAAE,OAAO,QAAQ,SAAS,EAAE,CAAC,EACnD,KAAK,EAAE,SAAS,IAAI,SAAS,MAAM,CAAC,EACpC,SAAS;AAAA,EACd;AAAA;AAAA,EAGA,MAAc,SAAS,MAAgD;AACrE,QAAI,CAAC,KAAK,SAAS,OAAO;AACxB,YAAM,IAAI,MAAM,gDAAgD;AAAA,IAClE;AAEA,WAAO,IAAI,QAAiC,CAACD,UAAS,WAAW;AAC/D,WAAK,iBAAiBA;AACtB,WAAK,gBAAgB;AAGrB,YAAM,YAAY,OAAO,YAAY,CAAC;AACtC,gBAAU,cAAc,KAAK,QAAQ,CAAC;AACtC,WAAK,QAAS,MAAO,MAAM,OAAO,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC;AAAA,IAC7D,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,UAAyB;AAC7B,UAAM,OAAO,KAAK;AAClB,QAAI,CAAC,KAAM;AAEX,SAAK,UAAU;AACf,SAAK,OAAO,IAAI;AAChB,SAAK,KAAK,SAAS;AAGnB,UAAM,SAAS,MAAM,IAAI,QAAiB,CAACA,aAAY;AACrD,YAAM,QAAQ,WAAW,MAAM;AAC7B,QAAAA,SAAQ,KAAK;AAAA,MACf,GAAG,GAAK;AACR,WAAK,KAAK,QAAQ,MAAM;AACtB,qBAAa,KAAK;AAClB,QAAAA,SAAQ,IAAI;AAAA,MACd,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,QAAQ;AACX,UAAI;AAAE,aAAK,KAAK,SAAS;AAAA,MAAE,QAAQ;AAAA,MAAqB;AACxD,WAAK,IAAI,KAAK,4DAAuD;AAAA,IACvE,OAAO;AACL,WAAK,IAAI,MAAM,2BAA2B;AAAA,IAC5C;AAAA,EACF;AACF;;;AH9HA,IAAM,wBAAwB,CAAC,UAAU,QAAQ,YAAY,KAAK;AAGlE,IAAM,oBAAoB,aAAAE;AAC1B,IAAM,oBAAoB,aAAAC;AAE1B,SAAS,iBAAiB,OAA0C;AAClE,SAAO;AAAA,IACL,WAAW,MAAM;AAAA,IACjB,oBAAoB,MAAM,sBAAsB;AAAA,IAChD,aAAa,MAAM,eAAe;AAAA,IAClC,gBAAgB,MAAM,kBAAkB;AAAA,EAC1C;AACF;AAEA,SAAS,cAAc,WAAmB,YAA+B,QAA6B;AACpG,QAAM,cAAc,WAAW,QAAQ,MAAM;AAC7C,MAAI,CAAC,aAAa;AAChB,UAAM,IAAI,MAAM,SAAS,WAAW,EAAE,WAAW,MAAM,SAAS;AAAA,EAClE;AAEA,QAAM,WAAW,YAAY,IAAI,MAAM,GAAG;AAC1C,QAAM,WAAW,SAAS,SAAS,SAAS,CAAC,KAAK,GAAG,WAAW,EAAE,IAAI,MAAM;AAC5E,SAAY,WAAK,WAAW,QAAQ;AACtC;AAEA,SAAS,YAAY,UAA2B;AAC9C,MAAI;AACF,WAAU,cAAW,QAAQ;AAAA,EAC/B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,cAAc,SAAyD;AAC3F,QAAM,EAAE,SAAS,SAAS,YAAY,WAAW,OAAO,IAAI;AAC5D,QAAM,MAAM,QAAQ,UAAU,iBAAiB;AAE/C,MAAI;AACJ,MAAI;AAEJ,MAAI,YAAY,QAAQ;AAEtB,UAAM,YAAY,MAAM,kBAAkB;AAG1C,QAAI,SAA0D;AAE9D,eAAW,KAAK,uBAAuB;AACrC,UAAI,CAAC,UAAU,SAAS,CAAC,EAAG;AAC5B,YAAM,MAAM,kBAAkB,CAAC;AAC/B,UAAI,CAAC,IAAK;AACV,UAAI,CAAC,WAAW,QAAQ,GAAG,EAAG;AAC9B,eAAS,EAAE,SAAS,GAAG,QAAQ,IAAI;AACnC;AAAA,IACF;AAEA,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI;AAAA,QACR,wDAAwD,WAAW,EAAE,yBAAyB,UAAU,KAAK,IAAI,CAAC;AAAA,MACpH;AAAA,IACF;AAEA,qBAAiB,OAAO;AACxB,sBAAkB,OAAO;AAAA,EAC3B,OAAO;AAEL,UAAM,MAAM,kBAAkB,OAAO;AACrC,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,uCAAuC,OAAO,GAAG;AAAA,IACnE;AACA,QAAI,CAAC,WAAW,QAAQ,GAAG,GAAG;AAG5B,UAAI,QAAQ,UAAU,WAAW,QAAQ,MAAM,GAAG;AAChD,yBAAiB;AACjB,0BAAkB,WAAW;AAAA,MAC/B,OAAO;AACL,cAAM,IAAI;AAAA,UACR,wBAAwB,WAAW,EAAE,WAAW,GAAG,uBAAuB,OAAO;AAAA,QACnF;AAAA,MACF;AAAA,IACF,OAAO;AACL,uBAAiB;AAEjB,wBAAkB,YAAY,SAAU,WAAW,QAAS;AAAA,IAC9D;AAAA,EACF;AAGA,MAAI;AAEJ,MAAI,QAAQ;AAEV,gBAAY,MAAM,OAAO,OAAO,WAAW,IAAI,cAAc;AAAA,EAC/D,OAAO;AAEL,gBAAY,cAAc,WAAW,YAAY,cAAc;AAC/D,QAAI,CAAC,YAAY,SAAS,GAAG;AAC3B,YAAM,IAAI;AAAA,QACR,0CAA0C,SAAS;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AAEA,MAAI,KAAK,mBAAmB,EAAE,MAAM,EAAE,QAAQ,gBAAgB,SAAS,iBAAiB,SAAS,WAAW,GAAG,EAAE,CAAC;AAIlH,MAAI,mBAAmB,QAAQ;AAC7B,UAAM,SAAS,IAAI,oBAAoB,WAAW,iBAAiB,iBAAiB,UAAU,GAAG,QAAQ,MAAM;AAC/G,UAAM,OAAO,WAAW;AACxB,WAAO,EAAE,QAAQ,QAAQ,gBAAgB,UAAU;AAAA,EACrD;AAGA,QAAM,mBAAmB,YAAY,SAAS,kBAAkB;AAGhE,MAAI,EAAE,WAAW,IAAI;AACrB,MAAI,CAAC,YAAY;AACf,UAAM,EAAE,cAAc,IAAI,IAAI,MAAM,OAAO,eAAoB;AAC/D,eAAW,OAAO,CAAC,WAAW,QAAQ,GAAG;AACvC,UAAI;AAAE,YAAI,KAAK,CAAC,WAAW,GAAG,EAAE,SAAS,KAAM,OAAO,SAAS,CAAC;AAAG,qBAAa;AAAK;AAAA,MAAM,QAAQ;AAAA,MAAkB;AAAA,IACvH;AAAA,EACF;AACA,QAAM,aAAa,aAAAC,cAAwB,gBAAgB;AAE3D,MAAI,cAAc,YAAY;AAK5B,UAAM,aAAa;AAAA,MACZ,WAAK,WAAW,gBAAgB,UAAU;AAAA,MAC1C,WAAK,WAAW,aAAa,UAAU;AAAA,MACvC,WAAK,WAAW,mBAAmB,UAAU;AAAA,IACpD;AACA,UAAM,aAAa,WAAW,KAAK,OAAQ,cAAW,CAAC,CAAC;AACxD,QAAI,CAAC,YAAY;AACf,YAAM,IAAI;AAAA,QACR,iCAAiC,UAAU;AAAA,EAA2B,WAAW,KAAK,IAAI,CAAC;AAAA,MAC7F;AAAA,IACF;AACA,UAAM,YAAY,KAAK,IAAI,WAAW,UAAU,OAAO,WAAW,UAAU,MAAM;AAClF,UAAM,SAAS,IAAI,sBAAsB,YAAY,YAAY,kBAAsC,WAAW;AAAA,MAChH,gBAAgB,SAAS;AAAA,MACzB;AAAA,IACF,GAAG,QAAQ,MAAM;AACjB,UAAM,OAAO,WAAW;AACxB,WAAO,EAAE,QAAQ,QAAQ,gBAAgB,UAAU;AAAA,EACrD;AAGA,QAAM,eAAe,cAAc,WAAW,YAAY,MAAM;AAChE,MAAI,WAAW,QAAQ,MAAM,KAAK,YAAY,YAAY,GAAG;AAC3D,UAAM,SAAS,IAAI,oBAAoB,cAAc,OAAO,iBAAiB,UAAU,GAAG,QAAQ,MAAM;AACxG,UAAM,OAAO,WAAW;AACxB,WAAO,EAAE,QAAQ,QAAQ,QAAQ,WAAW,aAAa;AAAA,EAC3D;AAEA,QAAM,IAAI;AAAA,IACR,yBAAyB,cAAc;AAAA,EAEzC;AACF;AAGA,eAAsB,oBAAuC;AAC3D,QAAM,YAAsB,CAAC,KAAK;AAElC,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,kBAAkB;AAC3C,UAAM,YAAsB,IAAI,KAAK,OAAO,aAAa,SACpD,IAAI,iBAAiB,wBAAwB,KAAK,CAAC,IACpD,CAAC;AAEL,eAAW,KAAK,WAAW;AACzB,YAAM,aAAa,EAAE,YAAY,EAAE,QAAQ,qBAAqB,EAAE;AAClE,UAAI,eAAe,SAAU,WAAU,KAAK,QAAQ;AAAA,eAC3C,eAAe,OAAQ,WAAU,KAAK,MAAM;AAAA,eAC5C,eAAe,WAAY,WAAU,KAAK,UAAU;AAAA,IAC/D;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,MAAI,QAAQ,aAAa,YAAY,CAAC,UAAU,SAAS,QAAQ,GAAG;AAClE,cAAU,KAAK,QAAQ;AAAA,EACzB;AAEA,SAAO,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC;AAC/B;;;AItPO,IAAM,kBAA2D;AAAA,EACtE,gBAAgB;AAAA,IACd,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,IACd,WAAW;AAAA,IACX,eAAe;AAAA,EACjB;AAAA,EACA,gBAAgB;AAAA,IACd,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,IACd,WAAW;AAAA,IACX,eAAe;AAAA,EACjB;AAAA,EACA,mBAAmB;AAAA,IACjB,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,IACd,WAAW;AAAA,IACX,eAAe;AAAA,EACjB;AACF;AAEO,IAAM,qBAAqB;AAE3B,SAAS,aAAa,SAAgC;AAC3D,SAAO,gBAAgB,OAAO,KAAK,gBAAgB,kBAAkB;AACvE;;;ACnCA,IAAM,YAAY,CAAC,YAAY,WAAW,UAAU;AACpD,IAAM,WAAW,CAAC,YAAY,YAAY,UAAU;AAQ7C,SAAS,kBACd,KACA,UACA,WACA,aACA,cACc;AACd,QAAM,SAAS,cAAc;AAC7B,QAAM,SAAS,IAAI,aAAa,IAAI,MAAM;AAE1C,WAAS,IAAI,GAAG,IAAI,cAAc,KAAK;AACrC,aAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AAEpC,YAAM,OAAO,KAAK,IAAI,KAAK,MAAO,IAAI,cAAe,QAAQ,GAAG,WAAW,CAAC;AAC5E,YAAM,OAAO,KAAK,IAAI,KAAK,MAAO,IAAI,eAAgB,SAAS,GAAG,YAAY,CAAC;AAC/E,YAAM,UAAU,OAAO,WAAW,QAAQ;AAC1C,YAAM,SAAS,IAAI,cAAc;AAEjC,eAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,cAAM,OAAO,IAAI,SAAS,CAAC,KAAK,KAAK;AACrC,eAAO,IAAI,SAAS,MAAM,KAAK,MAAM,UAAU,CAAC,KAAM,SAAS,CAAC;AAAA,MAClE;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,YAAY,KAAiC;AAC3D,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,IAAK,SAAQ,IAAI,CAAC,IAAK,IAAI,CAAC;AAC5D,SAAO,KAAK,KAAK,IAAI;AACrB,MAAI,OAAO,GAAG;AACZ,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,IAAK,KAAI,CAAC,KAAM;AAAA,EAClD;AACA,SAAO;AACT;;;ATjBA,IAAqB,wBAArB,cAAmD,wBAAwD;AAAA,EACjG,iBAA0C;AAAA,EAC1C,gBAAyC;AAAA,EACzC,oBAA6C;AAAA,EAC7C,mBAA4C;AAAA,EAE5C,SAAoC;AAAA,EACpC,WAAW;AAAA,EAEnB,cAAc;AAAE,UAAM,EAAE,SAAS,oBAAoB,SAAS,QAAQ,SAAS,MAAM,CAAC;AAAA,EAAE;AAAA,EAExF,MAAgB,eAAgD;AAC9D,UAAM,YAAY,MAAM,KAAK,IAAI,IAAI,QAAQ,QAAQ,MAAM,EAAE,UAAU,UAAU,cAAc,GAAG,CAAC,EAChG,MAAM,MAAM,sBAAsB;AACrC,SAAK,SAAS,IAAI,iCAAqB,WAAW,CAAC,CAAC;AACpD,WAAO,CAAC,EAAE,YAAY,0CAA4B,UAAU,KAAK,CAAC;AAAA,EACpE;AAAA,EAEA,MAAM,OAAO,MAAc,OAAe,QAA0C;AAClF,UAAM,KAAK,kBAAkB;AAC7B,UAAM,OAAO,aAAa,KAAK,OAAO,OAAO;AAC7C,UAAM,QAAQ,KAAK,IAAI;AAGvB,QAAI,KAAK,YAAY,KAAK,mBAAmB;AAC3C,YAAM,SAAS,MAAM,KAAK,kBAAkB,MAAM,EAAE,MAAM,QAAQ,MAAM,KAAK,CAAC;AAC9E,YAAM,eAAe,OAAO,aAAa,WAAW;AACpD,YAAM,YAAY,IAAI,aAAa,YAAY;AAC/C,aAAO;AAAA,QACL,WAAW,YAAY,SAAS;AAAA,QAChC,aAAa,OAAO,eAAgB,KAAK,IAAI,IAAI;AAAA,MACnD;AAAA,IACF;AAGA,UAAM,eAAe,kBAAkB,MAAM,OAAO,QAAQ,KAAK,WAAW,KAAK,SAAS;AAC1F,UAAM,SAAS,MAAM,KAAK,eAAgB,IAAI,cAAc,CAAC,GAAG,GAAG,KAAK,WAAW,KAAK,SAAS,CAAC;AAClG,UAAM,SAAS,OAAO,SAAS,KAAK,eAChC,OAAO,MAAM,GAAG,KAAK,YAAY,IACjC;AAEJ,WAAO;AAAA,MACL,WAAW,YAAY,IAAI,aAAa,MAAM,CAAC;AAAA,MAC/C,aAAa,KAAK,IAAI,IAAI;AAAA,IAC5B;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,MAAwC;AACvD,UAAM,KAAK,iBAAiB;AAC5B,UAAM,OAAO,aAAa,KAAK,OAAO,OAAO;AAC7C,UAAM,QAAQ,KAAK,IAAI;AAGvB,QAAI,KAAK,YAAY,KAAK,kBAAkB;AAC1C,YAAM,aAAa,OAAO,KAAK,KAAK,UAAU,EAAE,KAAK,CAAC,GAAG,OAAO;AAChE,YAAM,SAAS,MAAM,KAAK,iBAAiB,MAAM,EAAE,MAAM,QAAQ,MAAM,WAAW,CAAC;AACnF,YAAM,eAAe,OAAO,aAAa,WAAW;AACpD,YAAM,YAAY,IAAI,aAAa,YAAY;AAC/C,aAAO;AAAA,QACL,WAAW,YAAY,SAAS;AAAA,QAChC,aAAa,OAAO,eAAgB,KAAK,IAAI,IAAI;AAAA,MACnD;AAAA,IACF;AAGA,UAAM,WAAW,aAAa,IAAI;AAClC,UAAM,cAAc,IAAI,aAAa,QAAQ;AAC7C,UAAM,SAAS,MAAM,KAAK,cAAe,IAAI,aAAa,CAAC,GAAG,SAAS,MAAM,CAAC;AAC9E,UAAM,SAAS,OAAO,SAAS,KAAK,eAChC,OAAO,MAAM,GAAG,KAAK,YAAY,IACjC;AAEJ,WAAO;AAAA,MACL,WAAW,YAAY,IAAI,aAAa,MAAM,CAAC;AAAA,MAC/C,aAAa,KAAK,IAAI,IAAI;AAAA,IAC5B;AAAA,EACF;AAAA,EAEA,UAAyB;AACvB,UAAM,OAAO,aAAa,KAAK,OAAO,OAAO;AAC7C,WAAO;AAAA,MACL,SAAS,KAAK,OAAO;AAAA,MACrB,cAAc,KAAK;AAAA,MACnB,OAAO,KAAK,mBAAmB,QAAQ,KAAK,sBAAsB;AAAA,IACpE;AAAA,EACF;AAAA,EAEA,MAAc,oBAAmC;AAC/C,QAAI,KAAK,kBAAkB,KAAK,kBAAmB;AAEnD,UAAM,OAAO,aAAa,KAAK,OAAO,OAAO;AAC7C,UAAM,aAAa,kBAAkB,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,YAAY;AAC3E,QAAI,CAAC,YAAY;AACf,YAAM,IAAI,MAAM,+CAA+C,KAAK,YAAY,GAAG;AAAA,IACrF;AAEA,UAAM,KAAK,gBAAgB,YAAY,OAAO;AAAA,EAChD;AAAA,EAEA,MAAc,mBAAkC;AAC9C,QAAI,KAAK,iBAAiB,KAAK,iBAAkB;AAEjD,UAAM,OAAO,aAAa,KAAK,OAAO,OAAO;AAC7C,UAAM,YAAY,iBAAiB,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,WAAW;AACxE,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,8CAA8C,KAAK,WAAW,GAAG;AAAA,IACnF;AAEA,UAAM,KAAK,gBAAgB,WAAW,MAAM;AAAA,EAC9C;AAAA,EAEA,MAAc,gBAAgB,OAA0B,QAAyC;AAC/F,UAAM,UAAU,KAAK,OAAO,YAAY,SAAS,SAAU,KAAK,OAAO,YAAY,SAAS,SAAS,KAAK,OAAO;AACjH,UAAM,YAAY,KAAK,OAAQ,aAAa;AAE5C,UAAM,eAAe,KAAK,IAAK,OAAO,SAAS;AAAA,MAC7C,SAAS,MAAM;AAAA,MACf,SAAS,KAAK,OAAO;AAAA,MACrB,SAAS,KAAK,OAAO;AAAA,IACvB,CAAC;AAED,UAAM,KAAK,OAAQ,OAAO,MAAM,IAAI,MAAM;AAE1C,UAAM,WAAW,MAAM,cAAc;AAAA,MACnC;AAAA,MACA,SAAS,KAAK,OAAO;AAAA,MACrB,YAAY;AAAA,MACZ;AAAA,MACA,QAAQ,KAAK,UAAU;AAAA,MACvB,QAAQ;AAAA,IACV,CAAC;AAID,QAAI,SAAS,WAAW,QAAQ;AAC9B,WAAK,WAAW;AAChB,UAAI,WAAW,SAAS;AACtB,aAAK,oBAAoB,SAAS;AAAA,MACpC,OAAO;AACL,aAAK,mBAAmB,SAAS;AAAA,MACnC;AAAA,IACF,OAAO;AAEL,YAAM,YAAY,IAAI,oBAAoB,SAAS,WAAW,KAAK,OAAO,SAAS,YAAY;AAC/F,YAAM,UAAU,WAAW;AAE3B,YAAM,SAAS,OAAO,QAAQ;AAC9B,UAAI,WAAW,SAAS;AACtB,aAAK,iBAAiB;AAAA,MACxB,OAAO;AACL,aAAK,gBAAgB;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAgB,aAA4B;AAC1C,UAAM,KAAK,gBAAgB,QAAQ;AACnC,UAAM,KAAK,eAAe,QAAQ;AAClC,UAAM,KAAK,mBAAmB,QAAQ;AACtC,UAAM,KAAK,kBAAkB,QAAQ;AAAA,EACvC;AAAA;AAAA,EAIU,uBAAuB;AAC/B,WAAO,KAAK,OAAO;AAAA,MACjB,UAAU;AAAA,QACR;AAAA,UACE,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,SAAS;AAAA,UACT,QAAQ;AAAA,YACN;AAAA,cACE,MAAM;AAAA,cACN,KAAK;AAAA,cACL,OAAO;AAAA,cACP,aAAa;AAAA,cACb,SAAS;AAAA,YACX;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,KAAK;AAAA,cACL,OAAO;AAAA,cACP,aAAa;AAAA,cACb,SAAS;AAAA,cACT,SAAS;AAAA,gBACP,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,gBAC/B,EAAE,OAAO,eAAe,OAAO,OAAO;AAAA,gBACtC,EAAE,OAAO,UAAU,OAAO,SAAS;AAAA,cACrC;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM;AAAA,cACN,KAAK;AAAA,cACL,OAAO;AAAA,cACP,aAAa;AAAA,cACb,SAAS;AAAA,cACT,SAAS;AAAA,gBACP,EAAE,OAAO,OAAO,OAAO,MAAM;AAAA,gBAC7B,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,gBAC/B,EAAE,OAAO,UAAU,OAAO,SAAS;AAAA,cACrC;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAgB,kBAAiC;AAAA,EAGjD;AACF;AAQA,SAAS,aAAa,MAAc,YAAY,IAAc;AAC5D,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,SAAmB,CAAC,SAAS;AAEnC,WAAS,IAAI,GAAG,IAAI,KAAK,UAAU,OAAO,SAAS,YAAY,GAAG,KAAK;AACrE,WAAO,KAAK,KAAK,WAAW,CAAC,IAAI,GAAG;AAAA,EACtC;AACA,SAAO,KAAK,SAAS;AAErB,SAAO,OAAO,SAAS,WAAW;AAChC,WAAO,KAAK,CAAC;AAAA,EACf;AAEA,SAAO;AACT;","names":["import_types","path","sharp","path","BACKEND_TO_DEVICE","sharp","resolve","sharp","CANONICAL_BACKEND_TO_FORMAT","CANONICAL_RUNTIME_TO_FORMAT","CANONICAL_PYTHON_SCRIPT"]}
|